纯vue 获取usb串口,实现电子秤的对接_vue.js_My&Liu-Vue (2024)

说明:解决生产上过秤重量手动输入出错问题

效果图:

纯vue 获取usb串口,实现电子秤的对接_vue.js_My&Liu-Vue (1)

一:代码部分

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> 重&nbsp;&nbsp; &nbsp; &nbsp; 量 </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

纯vue 获取usb串口,实现电子秤的对接_vue.js_My&Liu-Vue (2)

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
图片:

纯vue 获取usb串口,实现电子秤的对接_vue.js_My&Liu-Vue (3)

设置成功之后图片:(这个X号不能删除,否则会清空,我自己电脑试过几次会清空)

纯vue 获取usb串口,实现电子秤的对接_vue.js_My&Liu-Vue (4)

问题图片

纯vue 获取usb串口,实现电子秤的对接_vue.js_My&Liu-Vue (5)

注:有问题私信留言

纯vue 获取usb串口,实现电子秤的对接_vue.js_My&Liu-Vue (2024)
Top Articles
Dark Goddes in the Transformation of Consciousness - PDFCOFFEE.COM
Language Acquisition and Development Misha Becker - PDFCOFFEE.COM
Ilovepersuasian
Jennifer Riordan Net Worth: A Comprehensive Look At Her Life And Legacy
Yale College Confidential 2027
Parc Soleil Drowning
Buenasado Bluewater
Netlearning Login Rwjbh
Hailie Deegan News, Rumors, & NASCAR Updates
Msu Ro
Okc Farm And Garden Craigslist
Thompson Center Thunderhawk Parts
Sonic Fan Games Hq
Tabdil Tarikh
Real Estate Transfers Erie Pa
Jennifer Paeyeneers Wikipedia
Cherry Spa Madison
R/Skinwalker
Big Lots $99 Fireplace
Ultimate Guide to Visiting Dungeness, UK
Managing Your Activision Account
G 037 White Oblong Pill
Dickinson Jewelers Prince Frederick Md
Ice Dodo Unblocked 76
2022 NFL Predictions
Diabetes Care - Horizon Blue Cross Blue Shield of New Jersey
Dr Seuss Star Bellied Sneetches Pdf
phoenix health/wellness services - craigslist
Maurice hat ein echtes Aggressionsproblem
222 US Dollars to Euros - 222 USD to EUR Exchange Rate
La Times Jumble Answer Today
Parishes Online Bulletins
12 30 Pacific Time
Lo que necesitas saber antes de desrizarte el cabello
Dr Yakubu Riverview
Oklahoma Craigslist Pets
Daftpo
New York Sports Club Carmel Hamlet Photos
Press-Citizen Obituaries
More massage parlors shut down by Roswell Police after ordinance violations
Blog:Vyond-styled rants -- List of nicknames (blog edition) (TouhouWonder version)
About My Father Showtimes Near Marcus Saukville Cinema
How To Buy Taylor Swift Tickets By Navigating Ticketek's Stress-Inducing System
Transactions on Computational Social Systems - IEEE SMC
Vcu Basketball Wiki
Immortal Ink Waxahachie
Evangeline Shrine Club Banquet Hall Photos
Craigslist Old Forge
Cb2 South Coast Plaza
Funny Roblox Id Codes 2023
Barotrauma Game Wiki
Latest Posts
Article information

Author: Saturnina Altenwerth DVM

Last Updated:

Views: 6473

Rating: 4.3 / 5 (44 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Saturnina Altenwerth DVM

Birthday: 1992-08-21

Address: Apt. 237 662 Haag Mills, East Verenaport, MO 57071-5493

Phone: +331850833384

Job: District Real-Estate Architect

Hobby: Skateboarding, Taxidermy, Air sports, Painting, Knife making, Letterboxing, Inline skating

Introduction: My name is Saturnina Altenwerth DVM, I am a witty, perfect, combative, beautiful, determined, fancy, determined person who loves writing and wants to share my knowledge and understanding with you.