说明:解决生产上过秤重量手动输入出错问题
效果图:
一:代码部分
1、创建一个名字为seriaport.js文件(随便定义,为下面页面引入使用)
export default class MySerialPort { constructor() { this.state = { portIndex: undefined, ports: [], isOpen: false, writeType: 1, readType: 1, isScroll: true, readValue: [], status:false, //port参数 baudRate: "9600", dataBits: "8", stopBits: "1", parity: "none", flowControl: "none", }; this.keepReading=false; this.getPorts = this.getPorts.bind(this); this.handleRequestPort = this.handleRequestPort.bind(this); this.handleChildrenChange = this.handleChildrenChange.bind(this); this.readText = this.readText.bind(this); this.writeText = this.writeText.bind(this); this.handleClear = this.handleClear.bind(this); this.a2hex = this.a2hex.bind(this); this.hex2a = this.hex2a.bind(this); this.hex2atostr=this.hex2atostr.bind(this); this.reader={}; this.closed; } async getPorts() { // 获取已授权的全部串口 let ports = await navigator.serial.getPorts(); this.setState({ ports, }); } async handleRequestPort() { // 请求授权 try { await navigator.serial.requestPort(); await this.getPorts(); } catch (e) { this.$message.error(e.toString()); } } async openPort(portIndex, isOpen,callBack=null) { // 打开串口 let port = this.state.ports[portIndex]; if (!isOpen) { // 关闭串口 this.keepReading = false; this.reader.cancel(); await this.closed; this.handlePortOpen({ portIndex, isOpen, }); } else { await port.open({ baudRate: this.state.baudRate, dataBits: this.state.dataBits, stopBits: this.state.stopBits, parity: this.state.parity, flowControl: this.state.flowControl, }); this.handlePortOpen({ portIndex, isOpen, }); this.keepReading = true; this.closed=this.readUntilClosed(portIndex,callBack); } } async readUntilClosed(portIndex,callBack=null) { let port = this.state.ports[portIndex]; while (port.readable && this.keepReading) { this.reader = port.readable.getReader(); try { let readCache=[] while (true) { const { value, done } = await this.reader.read(); if (done) { break; } readCache.push(...value) setTimeout(() => { if(readCache.length>0){ this.readText(readCache); callBack(readCache) readCache=[] } }, 300);//串口缓存 } } catch (error) { this.$message.error(error.toString()); } finally { this.reader.releaseLock(); } await port.close(); } } handlePortOpen({ portIndex, isOpen }) { // 处理打开串口 this.setState({ portIndex, isOpen, }); } handleChildrenChange(type, value) { this.setState({ [type]: value, }); } portWrite(value) { return new Promise(async (resolve, reject) => { if (!this.state.isOpen) { this.$message.error("串口未打开"); reject(); return; } else { let port = this.state.ports[this.state.portIndex]; const writer = port.writable.getWriter(); await writer.write(new Uint8Array(value)); writer.releaseLock(); resolve(value); } }); } readText(value) { // console.log(value, "读取"); let newValue = this.state.readValue.concat({ value, type: 1, }); this.setState({ readValue: newValue, }); } writeText(value) { // console.log(value, "写入"); this.portWrite(value).then((res) => { let newValue = this.state.readValue.concat({ value: res, type: 1, }); this.setState({ readValue: newValue, }); }); } handleClear() { this.setState({ readValue: [], }); } componentDidMount() { this.getPorts(); } handleState(status) { this.setState({ status, }); } setState(obj){ Object.keys(this.state).forEach(key => { if(obj[key]!=undefined){ this.state[key]=obj[key] } }); } //字节转字符串 hex2atostr (arr) { return String.fromCharCode.apply(String, arr); } hex2a(hexx) { return String.fromCharCode(hexx); } //字符转16进制 a2hex(str) { return str.charCodeAt(0);}}
2、创建一个为usb.json 文件(随便定义,为下面页面引入使用)
文件过大,下载地址(因为大部分是参考这位大佬的,一部分是按照自己的需求进行更改的ZhangY1217的博客_CSDN博客-java,c#,java23种设计模式领域博主)
文件下载链接:https://download.csdn.net/download/ZhangY1217/86662302
3、页面代码部分
<template> <span> <a-row :gutter="[10, 1]"> <a-col :span="6"> <a-form-item :labelCol="{ span: 6 }" :wrapperCol="{ span: 16 }"> <template v-slot:label>//v-has="'cont:Scales'" 为管理员权限,方便调试,普通用户进入页面直接授权,是为了第一次进行调试 <a v-has="'cont:Scales'" @click="getScales"><a-icon type="windows"/></a> <span> 重 量 </span> </template> <!-- <a-input-number /> --> <a-input-search placeholder=" " enter-button="换端口" v-model="ObjFrom.qtReal" @pressEnter="OnScreen" :formatter="value => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')" :parser="value => `${value}`.replace(/\$\s?|(,*)/g, '')" :precision="2" style="width: 100%" @search="obtainAuthorization" :key="time1" /> </a-form-item></a-col></a-row></span></template>//js部分<script>//第一步新建的文件名称import MySerialPort from '@api/seriaport.js'//第二步新建的import USBDevice from '@api/usb.json'export default { name: 'MzInProducts', components: { MzOrderlist, LbCard, modalScales }, data() { return { // 电子秤 form: { baudRate: '9600', dataBits: '8', stopBits: '1', parity: 'none', flowControl: 'none', desc: '', type: '1', isShowHistory: false, port: '1' }, btnType: 'primary', //这个portsList是我自己写死的,因为我的电子秤是这个名称 portsList: [ { label: 'PL2303 Serial Port / Mobile Action MA-8910P', value: 1 } ],ObjFrom:{}, readType: 1, time1: '', } }, mounted() { this.loadData() }, methods: { // 链接配置页面 // 电子称配置 loadData() { console.log(navigator) console.log('serial' in navigator) if ('serial' in navigator) { this.myserialport = new MySerialPort() this.getPorts() navigator.serial.addEventListener('connect', e => { this.$message.success('电子秤已连接') this.getPorts() }) navigator.serial.addEventListener('disconnect', e => { this.$message.error('设备已断开') }) this.restaurants = this.loadAll() } else { this.$message.error('当前浏览器不支持,请换成谷歌浏览器8 9 以上浏览器') } }, // 链接电子秤 async connectBtn() { if (this.btnType == 'primary') { try { this.myserialport.state.baudRate = this.form.baudRate this.myserialport.state.dataBits = this.form.dataBits this.myserialport.state.stopBits = this.form.stopBits this.myserialport.state.parity = this.form.parity this.myserialport.state.flowControl = this.form.flowControl await this.myserialport.openPort(this.form.port, true, this.callBack) } catch (error) { this.$message.error('串口连接失败!请关闭其他页面占用电子称的系统,确保电子秤的是唯一的值') } if (this.myserialport.state.isOpen) { this.$message.success('电子秤链接成功') this.btnType = 'dashed' this.btnText = '关闭电子称' } } else { this.myserialport.openPort(this.form.port, false, this.callBack) this.$message.success('串口关闭成功') this.btnType = 'primary' this.btnText = '链接电子秤' } }, //接受数据的回调 callBack(value) {//this.ObjFrom.qtReal 是input 的值 if (this.form.isShowHistory) this.ObjFrom.qtReal = this.getNumberFromStr(this.readLi().join('')) else { if (value.length > 0) this.ObjFrom.qtReal = this.getNumberFromStr(this.myserialport.hex2atostr(value)) } console.log(this.ObjFrom.qtReal) this.time1 = Date.now() }, clearHistory() { this.form.desc = '' this.myserialport.state.readValue = [] }, loadHistory() { if (this.form.isShowHistory) { this.form.desc = this.readLi().join('') console.log(temp[temp.length - 1].join('')) } else { let temp = this.readLi() if (temp.length > 0) this.form.desc = temp[temp.length - 1].join('') console.log(temp[temp.length - 1].join('')) } }, readLi() { let readType = this.readType return this.myserialport.state.readValue.map((items, index) => { const item = items.value const type = items.type // 1接收,2发送 let body = [] if (item !== undefined) { let strArr = [] for (let hex of Array.from(item)) { strArr.push(hex.toString(16).toLocaleUpperCase()) } if (strArr.includes('D') && strArr.includes('A')) { if (strArr.indexOf('A') - strArr.indexOf('D') === 1) { strArr.splice(strArr.indexOf('D'), 1) strArr.splice(strArr.indexOf('A'), 1, <br key={0} />) } } strArr = strArr.map(item => { if (typeof item === 'string') { if (readType === 1) { return this.myserialport.hex2a(parseInt(item, 16)) } else if (readType === 2) { return item + ' ' } } return item }) if (typeof strArr[strArr.length - 1] === 'string') { strArr.push('\r\n') } body.push(strArr.join('')) } return body }) }, //授权 async obtainAuthorization() { if ('serial' in navigator) { console.log('The Web Serial API is supported.') if (!this.myserialport) this.myserialport = new MySerialPort() try { await this.myserialport.handleRequestPort() this.$message.success('串口授权成功') this.getPortInfo(this.myserialport.state.ports) } catch (error) { this.$message.warning('未选择新串口授权!') } } else { this.$message.error('当前为HTTP模式或者浏览器版本过低,不支持网页连接串口') } }, //串口列表初始化 getPortInfo(portList) { this.portsList = [] portList.map((port, index) => { const { usbProductId, usbVendorId } = port.getInfo() if (usbProductId === undefined || usbVendorId === undefined) { // this.portsList.push({ label: "未知设备" + index, value: index }); } else { const usbVendor = USBDevice.filter(item => parseInt(item.vendor, 16) === usbVendorId) let usbProduct = [] if (usbVendor.length === 1) { usbProduct = usbVendor[0].devices.filter(item => parseInt(item.devid, 16) === usbProductId) } console.log(usbProduct[0].devname) this.portsList.push({ label: usbProduct[0].devname, value: index }) if (this.portsList.length > 0) { this.form.port = this.portsList[0].value } } }) }, async getPorts() { await this.myserialport.getPorts() this.getPortInfo(this.myserialport.state.ports) this.connectBtn() }, querySearch(queryString, cb) { var restaurants = this.restaurants var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants // 调用 callback 返回建议列表的数据 cb(results) }, createFilter(queryString) { return restaurant => { return restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0 } }, loadAll() { return [ { value: '110' }, { value: '300' }, { value: '600' }, { value: '1200' }, { value: '2400' }, { value: '4800' }, { value: '7200' }, { value: '9600' }, { value: '14400' }, { value: '19200' }, { value: '28800' }, { value: '38400' }, { value: '56000' }, { value: '57600' }, { value: '76800' }, { value: '115200' }, { value: '230400' }, { value: '460800' } ] }, // 截取方法 getNumberFromStr(str) { let matchArr = str.match(/\d+\.\d+/) if (matchArr && matchArr.length) { let num = parseFloat(matchArr[0]) .toFixed(2) .toString() if (num.indexOf('.') === -1) { return num } let numArr = num.split('.') if (numArr[0] !== '') { numArr[0] = parseInt(numArr[0]).toString() } if (numArr[0] === '0' && numArr[0].length > 1) { numArr[0] = numArr[0].slice(1) } return numArr.join('.') } return '' },// ScalesFrom页面是调试页面 getScales() { this.$refs.ScalesFrom.showDrawer() } }}</script>
注:ScalesFrom 后期我在更新上去
4、这个搭建只适合(只支持本机访问和https的,你这个要弄nginx和自己生成证书来用https的才能访问)但是可以通过别的方式解决本地服务器,使用一个局域网访问的需求(解决方法5)
5、解决谷歌服务器安全机制(因为谷歌浏览器有安全机制,我们是http访问,而不是https,https不会有这种问题)
解决方案:
1、谷歌浏览器访问:chrome://flags/#unsafely-treat-insecure-origin-as-secure
设置为Enabled ---一定点击下面Relaunch
2、打开电脑终端:
chrome(为你自己安装路径)--unsafely-treat-insecure-origin-as-secure=http://192.168.0.99(http://192.168.0.99 这个是我们服务地址,改为你自己的)
我的地址是("C:\Program Files (x86)\Chromiumbrowser\Chromium.exe")则是"C:\Program Files (x86)\Chromiumbrowser\Chromium.exe"--unsafely-treat-insecure-origin-as-secure=http://192.168.0.99
图片:
设置成功之后图片:(这个X号不能删除,否则会清空,我自己电脑试过几次会清空)
问题图片:
注:有问题私信留言