添加扫描商品
This commit is contained in:
parent
17b927213a
commit
77aac21317
7
package-lock.json
generated
7
package-lock.json
generated
@ -23,6 +23,7 @@
|
|||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.0.14",
|
"pinia": "^2.0.14",
|
||||||
|
"tracking": "^1.1.3",
|
||||||
"vditor": "^3.9.9",
|
"vditor": "^3.9.9",
|
||||||
"vue": "^3.5.12",
|
"vue": "^3.5.12",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
@ -8028,6 +8029,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tracking": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tracking/-/tracking-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-XS9CVMzjp6AHT5e7oRamU8U5Lz3k6BIRTkBVs0XqepwgwXQ4kbbmxrWzTG2v6RMvJC/9MKuSBQiX/5hwsQFcCQ==",
|
||||||
|
"license": "BSD"
|
||||||
|
},
|
||||||
"node_modules/traverse": {
|
"node_modules/traverse": {
|
||||||
"version": "0.6.8",
|
"version": "0.6.8",
|
||||||
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz",
|
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.0.14",
|
"pinia": "^2.0.14",
|
||||||
|
"tracking": "^1.1.3",
|
||||||
"vditor": "^3.9.9",
|
"vditor": "^3.9.9",
|
||||||
"vue": "^3.5.12",
|
"vue": "^3.5.12",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
|
@ -63,3 +63,11 @@ export function apiPurchaseProductOffersetStoreroomInfoTwo(params: any) {
|
|||||||
export function apiPurchaseProductOfferDetail(params: any) {
|
export function apiPurchaseProductOfferDetail(params: any) {
|
||||||
return request.get({ url: '/purchase_product_offer/purchaseproductoffer/detail', params })
|
return request.get({ url: '/purchase_product_offer/purchaseproductoffer/detail', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 上传商品图片
|
||||||
|
export function apiPurchaseProductOfferUpload(params: any) {
|
||||||
|
return request.post({
|
||||||
|
url: '/purchase_product_offer/purchaseproductoffer/upload',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
@ -17,6 +17,11 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
|
<el-card class="!border-none" v-loading="pager.loading" shadow="never">
|
||||||
|
<router-link v-perms="['order/sort_list/scan']" :to="{
|
||||||
|
path: 'order_sort_list/scan'
|
||||||
|
}" class="ml-4 mr-4">
|
||||||
|
<el-button type="primary"> 扫描商品 </el-button>
|
||||||
|
</router-link>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<el-table :data="pager.lists">
|
<el-table :data="pager.lists">
|
||||||
<el-table-column label="ID" prop="id" show-overflow-tooltip />
|
<el-table-column label="ID" prop="id" show-overflow-tooltip />
|
||||||
|
170
src/views/order/sort_list/scan.vue
Normal file
170
src/views/order/sort_list/scan.vue
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-frame">
|
||||||
|
<div class="demo-container">
|
||||||
|
<video ref="videoRef" id="video" width="400" height="300" preload autoplay loop muted></video>
|
||||||
|
<canvas ref="canvasRef" id="canvas" width="400" height="300"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import 'tracking';
|
||||||
|
import { ElMessage, type FormInstance } from 'element-plus'
|
||||||
|
import { apiPurchaseProductOfferUpload } from '@/api/purchase_product_offer'
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
canvas: null,
|
||||||
|
context: null,
|
||||||
|
video: null,
|
||||||
|
tracker: null,
|
||||||
|
needInit: false,
|
||||||
|
stream: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
this.canvas = this.$refs.canvasRef;
|
||||||
|
this.context = this.canvas.getContext('2d');
|
||||||
|
this.video = this.$refs.videoRef;
|
||||||
|
|
||||||
|
this.startTrack()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
startTrack() {
|
||||||
|
let getUserMedia = function(constrains, success, error) {
|
||||||
|
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||||
|
navigator.mediaDevices.getUserMedia(constrains).then(success).catch(error);
|
||||||
|
} else if (navigator.webkitGetUserMedia) {
|
||||||
|
//webkit内核浏览器
|
||||||
|
navigator.webkitGetUserMedia(constrains).then(success).catch(error);
|
||||||
|
} else if (navigator.mozGetUserMedia) {
|
||||||
|
//Firefox浏览器
|
||||||
|
navagator.mozGetUserMedia(constrains).then(success).catch(error);
|
||||||
|
} else if (navigator.getUserMedia) {
|
||||||
|
//旧版API
|
||||||
|
navigator.getUserMedia(constrains).then(success).catch(error);
|
||||||
|
} else {
|
||||||
|
ElMessage.error('浏览器不支持getUserMedia')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.tracking.initUserMedia_ = function (element, opt_options) {
|
||||||
|
const options = {
|
||||||
|
video: true,
|
||||||
|
audio: !!(opt_options && opt_options.audio)
|
||||||
|
};
|
||||||
|
getUserMedia(options, function (stream) {
|
||||||
|
try {
|
||||||
|
element.srcObject = stream;
|
||||||
|
} catch (err) {
|
||||||
|
element.src = window.URL.createObjectURL(stream);
|
||||||
|
}
|
||||||
|
}, function (e) {
|
||||||
|
ElMessage.error(e.message)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重写视频捕获方法,因为不能停止 stop无效的bug
|
||||||
|
window.tracking.trackVideo_ = function (element, tracker) {
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
var width;
|
||||||
|
var height;
|
||||||
|
|
||||||
|
var resizeCanvas_ = function () {
|
||||||
|
width = element.offsetWidth;
|
||||||
|
height = element.offsetHeight;
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
};
|
||||||
|
resizeCanvas_();
|
||||||
|
element.addEventListener('resize', resizeCanvas_);
|
||||||
|
|
||||||
|
var requestId;
|
||||||
|
var stopped = false;
|
||||||
|
var requestAnimationFrame_ = function () {
|
||||||
|
requestId = window.requestAnimationFrame(function () {
|
||||||
|
if (element.readyState === element.HAVE_ENOUGH_DATA) {
|
||||||
|
try {
|
||||||
|
context.drawImage(element, 0, 0, width, height);
|
||||||
|
} catch (err) { }
|
||||||
|
tracking.trackCanvasInternal_(canvas, tracker);
|
||||||
|
}
|
||||||
|
if (stopped !== true) {
|
||||||
|
requestAnimationFrame_();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var task = new tracking.TrackerTask(tracker);
|
||||||
|
task.on('stop', function () {
|
||||||
|
stopped = true;
|
||||||
|
window.cancelAnimationFrame(requestId);
|
||||||
|
});
|
||||||
|
task.on('run', function () {
|
||||||
|
stopped = false;
|
||||||
|
requestAnimationFrame_();
|
||||||
|
});
|
||||||
|
return task.run();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const FastTracker = function () {
|
||||||
|
FastTracker.base(this, 'constructor');
|
||||||
|
};
|
||||||
|
tracking.inherits(FastTracker, tracking.Tracker);
|
||||||
|
|
||||||
|
tracking.Fast.THRESHOLD = 8;
|
||||||
|
FastTracker.prototype.threshold = tracking.Fast.THRESHOLD;
|
||||||
|
|
||||||
|
FastTracker.prototype.track = function (pixels, width, height) {
|
||||||
|
const gray = tracking.Image.grayscale(pixels, width, height);
|
||||||
|
const corners = tracking.Fast.findCorners(gray, width, height);
|
||||||
|
|
||||||
|
this.emit('track', {
|
||||||
|
data: corners
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.tracker = new FastTracker();
|
||||||
|
|
||||||
|
this.tracker.on('track', (event) => {
|
||||||
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
const corners = event.data;
|
||||||
|
if (corners.length > 220) {
|
||||||
|
this.context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
if (!this.needInit) {
|
||||||
|
this.needInit = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.upload()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.needInit = false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tracking.track('#video', this.tracker, {
|
||||||
|
camera: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
upload() {
|
||||||
|
this.canvas.toBlob(async (blob) => {
|
||||||
|
if (blob) {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', blob, 'motion_photo.jpg');
|
||||||
|
await apiPurchaseProductOfferUpload(formData).then(res => {
|
||||||
|
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('上传过程出错:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 'image/jpeg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user