提交 | 用户 | 时间
|
3cef24
|
1 |
<template> |
A |
2 |
<div> |
|
3 |
<el-row |
|
4 |
type="flex" |
|
5 |
class="row-bg" |
|
6 |
justify="center" |
|
7 |
v-show="portsList.length == 0" |
|
8 |
> |
|
9 |
<el-col :span="7" |
|
10 |
><div style="margin-top: 400px"> |
|
11 |
<span style="display: block"> |
|
12 |
仅支持Chrome 89+或者Edge 89+浏览器(安全上下文(HTTPS)中可用) |
|
13 |
</span> |
|
14 |
<el-button type="primary" @click="obtainAuthorization" |
|
15 |
>授权</el-button |
|
16 |
> |
|
17 |
</div></el-col |
|
18 |
> |
|
19 |
</el-row> |
|
20 |
<el-form |
|
21 |
v-show="portsList.length > 0" |
|
22 |
ref="form" |
|
23 |
:model="form" |
|
24 |
label-width="100px" |
|
25 |
> |
|
26 |
<el-row> |
|
27 |
<el-col :span="6" |
|
28 |
><div> |
|
29 |
<el-form-item label="串口"> |
|
30 |
<el-select |
|
31 |
v-model="form.port" |
|
32 |
filterable |
|
33 |
placeholder="请选择串口" |
|
34 |
:disabled="isDisable" |
|
35 |
> |
|
36 |
<el-option |
|
37 |
v-for="item in portsList" |
|
38 |
:key="item.value" |
|
39 |
:label="item.label" |
|
40 |
:value="item.value" |
|
41 |
> |
|
42 |
</el-option> |
|
43 |
</el-select> |
|
44 |
</el-form-item> |
|
45 |
<el-form-item label="波特率"> |
|
46 |
<el-autocomplete |
|
47 |
popper-class="my-autocomplete" |
|
48 |
v-model="form.baudRate" |
|
49 |
:fetch-suggestions="querySearch" |
|
50 |
placeholder="请输入波特率" |
|
51 |
:disabled="isDisable" |
|
52 |
> |
|
53 |
<i class="el-icon-edit el-input__icon" slot="suffix"> </i> |
|
54 |
<template slot-scope="{ item }"> |
|
55 |
<div class="name">{{ item.value }}</div> |
|
56 |
<span class="addr">{{ item.address }}</span> |
|
57 |
</template> |
|
58 |
</el-autocomplete> |
|
59 |
</el-form-item> |
|
60 |
<el-form-item label="数据位"> |
|
61 |
<el-select |
|
62 |
v-model="form.dataBits" |
|
63 |
placeholder="请选择数据位" |
|
64 |
:disabled="isDisable" |
|
65 |
> |
|
66 |
<el-option label="7" value="7"></el-option> |
|
67 |
<el-option label="8" value="8"></el-option> |
|
68 |
</el-select> |
|
69 |
</el-form-item> |
|
70 |
<el-form-item label="停止位"> |
|
71 |
<el-select |
|
72 |
v-model="form.stopBits" |
|
73 |
placeholder="请选择停止位" |
|
74 |
:disabled="isDisable" |
|
75 |
> |
|
76 |
<el-option label="1" value="1"></el-option> |
|
77 |
<el-option label="2" value="2"></el-option> |
|
78 |
</el-select> |
|
79 |
</el-form-item> |
|
80 |
|
|
81 |
<el-form-item label="校验位"> |
|
82 |
<el-select |
|
83 |
v-model="form.parity" |
|
84 |
placeholder="请选择校验位" |
|
85 |
:disabled="isDisable" |
|
86 |
> |
|
87 |
<el-option label="None" value="none"></el-option> |
|
88 |
<el-option label="Even" value="even"></el-option> |
|
89 |
<el-option label="Odd" value="odd"></el-option> |
|
90 |
</el-select> |
|
91 |
</el-form-item> |
|
92 |
|
|
93 |
<el-form-item label="流控制"> |
|
94 |
<el-select |
|
95 |
v-model="form.flowControl" |
|
96 |
placeholder="请选择流控制" |
|
97 |
:disabled="isDisable" |
|
98 |
> |
|
99 |
<el-option label="None" value="none"></el-option> |
|
100 |
<el-option label="HardWare" value="hardware"></el-option> |
|
101 |
</el-select> |
|
102 |
</el-form-item> |
|
103 |
<el-form-item label="显示历史"> |
|
104 |
<el-switch |
|
105 |
v-model="form.isShowHistory" |
|
106 |
@change="loadHistory" |
|
107 |
></el-switch> |
|
108 |
<el-button |
|
109 |
type="danger" |
|
110 |
icon="el-icon-delete" |
|
111 |
circle |
|
112 |
title="清空历史" |
|
113 |
@click="clearHistory" |
|
114 |
></el-button> |
|
115 |
</el-form-item> |
|
116 |
<el-form-item label="发送区设置" v-show="isShowSendArea"> |
|
117 |
<el-form-item label="发送格式"> |
|
118 |
<el-radio-group v-model="form.type"> |
|
119 |
<el-radio label="1">ASCII</el-radio> |
|
120 |
<el-radio label="2">HEX</el-radio> |
|
121 |
</el-radio-group> |
|
122 |
</el-form-item> |
|
123 |
<el-form-item label="发送信息"> |
|
124 |
<el-input type="textarea" v-model="form.sendMsg"></el-input> |
|
125 |
</el-form-item> |
|
126 |
<el-button type="primary" @click="sendCommon">发送</el-button> |
|
127 |
</el-form-item> |
|
128 |
|
|
129 |
<el-form-item> |
|
130 |
<el-button :type="btnType" @click="connectBtn">{{ |
|
131 |
btnText |
|
132 |
}}</el-button> |
|
133 |
<el-button type="info" @click="obtainAuthorization" |
|
134 |
>新增授权</el-button |
|
135 |
> |
|
136 |
</el-form-item> |
|
137 |
</div> |
|
138 |
</el-col> |
|
139 |
<el-col :span="10" |
|
140 |
><div> |
|
141 |
<el-form-item label="电子秤信息"> |
|
142 |
<el-input |
|
143 |
type="textarea" |
|
144 |
v-model="form.desc" |
|
145 |
disabled |
|
146 |
:autosize="{ minRows: 21, maxRows: 25 }" |
|
147 |
></el-input> |
|
148 |
</el-form-item></div |
|
149 |
></el-col> |
|
150 |
</el-row> |
|
151 |
</el-form> |
|
152 |
</div> |
|
153 |
</template> |
|
154 |
|
|
155 |
<script> |
|
156 |
import MySerialPort from "@/utils/MySerialPort"; |
|
157 |
import USBDevice from "@/utils/usb.json"; |
|
158 |
export default { |
|
159 |
data() { |
|
160 |
return { |
|
161 |
input: "", |
|
162 |
keepReading: true, |
|
163 |
form: { |
|
164 |
baudRate: "9600", |
|
165 |
dataBits: "8", |
|
166 |
stopBits: "1", |
|
167 |
parity: "none", |
|
168 |
flowControl: "none", |
|
169 |
desc: "", |
|
170 |
type: "1", |
|
171 |
isShowHistory: false, |
|
172 |
}, |
|
173 |
btnType: "primary", |
|
174 |
btnText: "连接串口", |
|
175 |
restaurants: [], |
|
176 |
portsList: [], |
|
177 |
isShowSendArea: true, |
|
178 |
readType: 1, |
|
179 |
}; |
|
180 |
}, |
|
181 |
mounted() { |
|
182 |
if ("serial" in navigator) { |
|
183 |
this.myserialport = new MySerialPort(); |
|
184 |
this.getPorts(); |
|
185 |
navigator.serial.addEventListener("connect", (e) => { |
|
186 |
this.$message.success("设备已连接"); |
|
187 |
this.getPorts(); |
|
188 |
}); |
|
189 |
navigator.serial.addEventListener("disconnect", (e) => { |
|
190 |
this.$message.error("设备已断开"); |
|
191 |
}); |
|
192 |
this.restaurants = this.loadAll(); |
|
193 |
} else { |
|
194 |
this.$message.error( |
|
195 |
"当前为HTTP模式或者浏览器版本过低,不支持网页连接串口" |
|
196 |
); |
|
197 |
} |
|
198 |
}, |
|
199 |
computed: { |
|
200 |
isDisable() { |
|
201 |
return this.btnType == "danger"; |
|
202 |
}, |
|
203 |
}, |
|
204 |
methods: { |
|
205 |
//接受数据的回调 |
|
206 |
callBack(value) { |
|
207 |
if (this.form.isShowHistory) this.form.desc = this.readLi().join(""); |
|
208 |
else { |
|
209 |
if (value.length > 0) |
|
210 |
this.form.desc = this.myserialport.hex2atostr(value); |
|
211 |
} |
|
212 |
}, |
|
213 |
clearHistory() { |
|
214 |
this.form.desc = ""; |
|
215 |
this.myserialport.state.readValue = []; |
|
216 |
}, |
|
217 |
loadHistory() { |
|
218 |
if (this.form.isShowHistory) this.form.desc = this.readLi().join(""); |
|
219 |
else { |
|
220 |
let temp = this.readLi(); |
|
221 |
if (temp.length > 0) this.form.desc = temp[temp.length - 1].join(""); |
|
222 |
} |
|
223 |
}, |
|
224 |
readLi() { |
|
225 |
let readType = this.readType; |
|
226 |
return this.myserialport.state.readValue.map((items, index) => { |
|
227 |
const item = items.value; |
|
228 |
const type = items.type; // 1接收,2发送 |
|
229 |
let body = []; |
|
230 |
if (item !== undefined) { |
|
231 |
let strArr = []; |
|
232 |
for (let hex of Array.from(item)) { |
|
233 |
strArr.push(hex.toString(16).toLocaleUpperCase()); |
|
234 |
} |
|
235 |
if (strArr.includes("D") && strArr.includes("A")) { |
|
236 |
if (strArr.indexOf("A") - strArr.indexOf("D") === 1) { |
|
237 |
strArr.splice(strArr.indexOf("D"), 1); |
|
238 |
strArr.splice(strArr.indexOf("A"), 1, <br key={0} />); |
|
239 |
} |
|
240 |
} |
|
241 |
strArr = strArr.map((item) => { |
|
242 |
if (typeof item === "string") { |
|
243 |
if (readType === 1) { |
|
244 |
return this.myserialport.hex2a(parseInt(item, 16)); |
|
245 |
} else if (readType === 2) { |
|
246 |
return item + " "; |
|
247 |
} |
|
248 |
} |
|
249 |
return item; |
|
250 |
}); |
|
251 |
if (typeof strArr[strArr.length - 1] === "string") { |
|
252 |
strArr.push("\r\n"); |
|
253 |
} |
|
254 |
body.push(strArr.join("")); |
|
255 |
} |
|
256 |
return body; |
|
257 |
}); |
|
258 |
}, |
|
259 |
//连接 |
|
260 |
async connectBtn() { |
|
261 |
if (this.btnType == "primary") { |
|
262 |
try { |
|
263 |
this.myserialport.state.baudRate = this.form.baudRate; |
|
264 |
this.myserialport.state.dataBits = this.form.dataBits; |
|
265 |
this.myserialport.state.stopBits = this.form.stopBits; |
|
266 |
this.myserialport.state.parity = this.form.parity; |
|
267 |
this.myserialport.state.flowControl = this.form.flowControl; |
|
268 |
await this.myserialport.openPort(this.form.port, true, this.callBack); |
|
269 |
} catch (error) { |
|
270 |
this.$message.error("串口连接失败!请检查串口是否已被占用"); |
|
271 |
} |
|
272 |
if (this.myserialport.state.isOpen) { |
|
273 |
this.$message.success("串口连接成功"); |
|
274 |
this.btnType = "danger"; |
|
275 |
this.btnText = "关闭串口"; |
|
276 |
} |
|
277 |
} else { |
|
278 |
this.myserialport.openPort(this.form.port, false, this.callBack); |
|
279 |
this.$message.success("串口关闭成功"); |
|
280 |
this.btnType = "primary"; |
|
281 |
this.btnText = "连接串口"; |
|
282 |
} |
|
283 |
}, |
|
284 |
//授权 |
|
285 |
async obtainAuthorization() { |
|
286 |
if ("serial" in navigator) { |
|
287 |
console.log("The Web Serial API is supported."); |
|
288 |
if (!this.myserialport) this.myserialport = new MySerialPort(); |
|
289 |
try { |
|
290 |
await this.myserialport.handleRequestPort(); |
|
291 |
this.$message.success("串口授权成功"); |
|
292 |
this.getPortInfo(this.myserialport.state.ports); |
|
293 |
} catch (error) { |
|
294 |
this.$message.warning("未选择新串口授权!"); |
|
295 |
} |
|
296 |
} else { |
|
297 |
this.$message.error( |
|
298 |
"当前为HTTP模式或者浏览器版本过低,不支持网页连接串口" |
|
299 |
); |
|
300 |
} |
|
301 |
}, |
|
302 |
//串口列表初始化 |
|
303 |
getPortInfo(portList) { |
|
304 |
this.portsList = []; |
|
305 |
portList.map((port, index) => { |
|
306 |
const { usbProductId, usbVendorId } = port.getInfo(); |
|
307 |
if (usbProductId === undefined || usbVendorId === undefined) { |
|
308 |
this.portsList.push({ label: "未知设备" + index, value: index }); |
|
309 |
} else { |
|
310 |
const usbVendor = USBDevice.filter( |
|
311 |
(item) => parseInt(item.vendor, 16) === usbVendorId |
|
312 |
); |
|
313 |
let usbProduct = []; |
|
314 |
if (usbVendor.length === 1) { |
|
315 |
usbProduct = usbVendor[0].devices.filter( |
|
316 |
(item) => parseInt(item.devid, 16) === usbProductId |
|
317 |
); |
|
318 |
} |
|
319 |
this.portsList.push({ label: usbProduct[0].devname, value: index }); |
|
320 |
} |
|
321 |
}); |
|
322 |
}, |
|
323 |
// 发送 |
|
324 |
async sendCommon() { |
|
325 |
if (this.myserialport.state.isOpen) { |
|
326 |
if (this.form.sendMsg.length !== 0) { |
|
327 |
const writeType = this.form.type; |
|
328 |
let value = this.form.sendMsg; |
|
329 |
let arr = []; |
|
330 |
if (writeType == 1) { |
|
331 |
// ASCII |
|
332 |
for (let i = 0; i < value.length; i++) { |
|
333 |
arr.push(this.myserialport.a2hex(value[i])); |
|
334 |
} |
|
335 |
} else if (writeType == 2) { |
|
336 |
// HEX |
|
337 |
if (/^[0-9A-Fa-f]+$/.test(value) && value.length % 2 === 0) { |
|
338 |
for (let i = 0; i < value.length; i = i + 2) { |
|
339 |
arr.push(parseInt(value.substring(i, i + 2), 16)); |
|
340 |
} |
|
341 |
} else { |
|
342 |
this.$message.error("格式错误"); |
|
343 |
return; |
|
344 |
} |
|
345 |
} |
|
346 |
this.myserialport.writeText(arr); |
|
347 |
} else { |
|
348 |
this.$message.warning("请输入发送的信息"); |
|
349 |
} |
|
350 |
} else { |
|
351 |
this.$message.warning("串口处于关闭状态,请连接串口"); |
|
352 |
} |
|
353 |
}, |
|
354 |
async getPorts() { |
|
355 |
await this.myserialport.getPorts(); |
|
356 |
this.getPortInfo(this.myserialport.state.ports); |
|
357 |
}, |
|
358 |
querySearch(queryString, cb) { |
|
359 |
var restaurants = this.restaurants; |
|
360 |
var results = queryString |
|
361 |
? restaurants.filter(this.createFilter(queryString)) |
|
362 |
: restaurants; |
|
363 |
// 调用 callback 返回建议列表的数据 |
|
364 |
cb(results); |
|
365 |
}, |
|
366 |
createFilter(queryString) { |
|
367 |
return (restaurant) => { |
|
368 |
return ( |
|
369 |
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === |
|
370 |
0 |
|
371 |
); |
|
372 |
}; |
|
373 |
}, |
|
374 |
loadAll() { |
|
375 |
return [ |
|
376 |
{ value: "110" }, |
|
377 |
{ value: "300" }, |
|
378 |
{ value: "600" }, |
|
379 |
{ value: "1200" }, |
|
380 |
{ value: "2400" }, |
|
381 |
{ value: "4800" }, |
|
382 |
{ value: "7200" }, |
|
383 |
{ value: "9600" }, |
|
384 |
{ value: "14400" }, |
|
385 |
{ value: "19200" }, |
|
386 |
{ value: "28800" }, |
|
387 |
{ value: "38400" }, |
|
388 |
{ value: "56000" }, |
|
389 |
{ value: "57600" }, |
|
390 |
{ value: "76800" }, |
|
391 |
{ value: "115200" }, |
|
392 |
{ value: "230400" }, |
|
393 |
{ value: "460800" }, |
|
394 |
]; |
|
395 |
}, |
|
396 |
}, |
|
397 |
}; |
|
398 |
</script> |
|
399 |
|
|
400 |
<style scoped> |
|
401 |
/* ::v-deep .el-textarea__inner { |
|
402 |
height: 320px !important; |
|
403 |
width: 80% !important; |
|
404 |
} */ |
|
405 |
</style> |