1.0.6
This commit is contained in:
parent
887aa55930
commit
ebdc516a55
@ -1,3 +1,9 @@
|
|||||||
|
# 1.0.6
|
||||||
|
|
||||||
|
1. 增加远程扫码入库功能
|
||||||
|
2. 修改 README 文档
|
||||||
|
3. 修复已知问题
|
||||||
|
|
||||||
# 1.0.5
|
# 1.0.5
|
||||||
|
|
||||||
1. 新增扫码入库功能
|
1. 新增扫码入库功能
|
||||||
|
|||||||
@ -68,8 +68,10 @@ V2.2 用户菜单栏将直接出现“LEYE”选项;V3 用户若未开启“
|
|||||||
## 开源许可
|
## 开源许可
|
||||||
|
|
||||||
本扩展使用以下开源软件:
|
本扩展使用以下开源软件:
|
||||||
- [jsQR](https://www.jsdelivr.com/package/npm/jsqr):二维码解析库,使用 [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/) 许可协议授权
|
- [SheetJS](https://www.npmjs.com/package/xlsx):Excel 解析库,使用 [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/) 许可协议授权
|
||||||
- [xlsx](https://www.jsdelivr.com/package/npm/xlsx):Excel 解析库,使用 [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/) 许可协议授权
|
- [jsQR](https://www.npmjs.com/package/jsqr):二维码解析库,使用 [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/) 许可协议授权
|
||||||
- [Tailwind CSS](https://www.jsdelivr.com/package/npm/tailwindcss):CSS 框架,使用 [MIT License](https://choosealicense.com/licenses/mit/) 许可协议授权
|
- [node-qrcode](https://www.npmjs.com/package/qrcode):二维码生成库,使用 [MIT License](https://choosealicense.com/licenses/mit/) 许可协议授权
|
||||||
|
- [MQTT.js](https://www.npmjs.com/package/mqtt):MQTT 客户端库,使用 [MIT License](https://choosealicense.com/licenses/mit/) 许可协议授权
|
||||||
|
- [Tailwind CSS](https://www.npmjs.com/package/tailwindcss):CSS 框架,使用 [MIT License](https://choosealicense.com/licenses/mit/) 许可协议授权
|
||||||
|
|
||||||
本扩展使用 [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/) 开源许可协议,商业/教育用途请考虑联系开发者获取常规版。
|
本扩展使用 [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/) 开源许可协议,商业/教育用途请考虑联系开发者获取常规版。
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"uuid": "944f7c94a8ca485e848f1118effcbb9a",
|
"uuid": "944f7c94a8ca485e848f1118effcbb9a",
|
||||||
"displayName": "LEYE",
|
"displayName": "LEYE",
|
||||||
"description": "LEYE 电子元器件库存管理系统 EDA 联动扩展",
|
"description": "LEYE 电子元器件库存管理系统 EDA 联动扩展",
|
||||||
"version": "1.0.5",
|
"version": "1.0.6",
|
||||||
"publisher": "Mr_Fang",
|
"publisher": "Mr_Fang",
|
||||||
"engines": {
|
"engines": {
|
||||||
"eda": "^3.2.80"
|
"eda": "^3.2.80"
|
||||||
|
|||||||
@ -596,6 +596,10 @@ video {
|
|||||||
visibility: collapse;
|
visibility: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.static {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
.fixed {
|
.fixed {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
@ -644,6 +648,10 @@ video {
|
|||||||
margin: 0.75rem;
|
margin: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.m-auto {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.mx-auto {
|
.mx-auto {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
@ -1086,6 +1094,11 @@ video {
|
|||||||
border-color: rgb(219 234 254 / var(--tw-border-opacity, 1));
|
border-color: rgb(219 234 254 / var(--tw-border-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-blue-300 {
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(147 197 253 / var(--tw-border-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.border-blue-600 {
|
.border-blue-600 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(37 99 235 / var(--tw-border-opacity, 1));
|
border-color: rgb(37 99 235 / var(--tw-border-opacity, 1));
|
||||||
|
|||||||
@ -16,6 +16,8 @@
|
|||||||
</style>
|
</style>
|
||||||
<script src="/iframe/js/xlsx.full.min.js" language="JavaScript"></script>
|
<script src="/iframe/js/xlsx.full.min.js" language="JavaScript"></script>
|
||||||
<script src="/iframe/js/jsQR.min.js" language="JavaScript"></script>
|
<script src="/iframe/js/jsQR.min.js" language="JavaScript"></script>
|
||||||
|
<script src="/iframe/js/qrcode.min.js" language="JavaScript"></script>
|
||||||
|
<script src="/iframe/js/mqtt.min.js" language="JavaScript"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-100 font-sans text-sm">
|
<body class="bg-gray-100 font-sans text-sm">
|
||||||
<div id="fixed-window" class="bg-gray-50 flex flex-col overflow-hidden mx-auto">
|
<div id="fixed-window" class="bg-gray-50 flex flex-col overflow-hidden mx-auto">
|
||||||
@ -124,6 +126,8 @@
|
|||||||
let importList = [];
|
let importList = [];
|
||||||
let videoStream = null;
|
let videoStream = null;
|
||||||
let currentScanData = null;
|
let currentScanData = null;
|
||||||
|
let mqttClient = null;
|
||||||
|
const myDeviceId = Math.random().toString(36).substring(2, 10);
|
||||||
|
|
||||||
function renderList() {
|
function renderList() {
|
||||||
if (importList.length === 0) {
|
if (importList.length === 0) {
|
||||||
@ -156,9 +160,12 @@
|
|||||||
try {
|
try {
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
||||||
cameraSelect.innerHTML = videoDevices.map(d =>
|
let options = videoDevices.map(d =>
|
||||||
`<option value="${d.deviceId}">${d.label || '摄像头 ' + d.deviceId.slice(0, 5)}</option>`
|
`<option value="${d.deviceId}">${d.label || '摄像头 ' + d.deviceId.slice(0, 5)}</option>`
|
||||||
).join('');
|
).join('');
|
||||||
|
|
||||||
|
options += `<option value="WEBSOCKET_MODE">WebSocket 远程扫码</option>`;
|
||||||
|
cameraSelect.innerHTML = options;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
eda.sys_Message.showToastMessage('无法获取摄像头列表: ' + e.message, ESYS_ToastMessageType.ERROR);
|
eda.sys_Message.showToastMessage('无法获取摄像头列表: ' + e.message, ESYS_ToastMessageType.ERROR);
|
||||||
}
|
}
|
||||||
@ -168,11 +175,12 @@
|
|||||||
stopCamera();
|
stopCamera();
|
||||||
qrDialog.classList.add('hidden');
|
qrDialog.classList.add('hidden');
|
||||||
|
|
||||||
|
if (currentScanData) {
|
||||||
document.getElementById('res-cid').textContent = currentScanData.lcscId;
|
document.getElementById('res-cid').textContent = currentScanData.lcscId;
|
||||||
document.getElementById('res-pm').textContent = currentScanData.name;
|
document.getElementById('res-pm').textContent = currentScanData.name;
|
||||||
document.getElementById('res-qty').textContent = currentScanData.quantity;
|
document.getElementById('res-qty').textContent = currentScanData.quantity;
|
||||||
|
|
||||||
currentScanData = null;
|
currentScanData = null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function stopCamera() {
|
function stopCamera() {
|
||||||
@ -180,16 +188,68 @@
|
|||||||
videoStream.getTracks().forEach(track => track.stop());
|
videoStream.getTracks().forEach(track => track.stop());
|
||||||
videoStream = null;
|
videoStream = null;
|
||||||
}
|
}
|
||||||
qrVideo.parentElement.classList.remove('scanning');
|
|
||||||
|
if (mqttClient) {
|
||||||
|
console.log("正在断开 MQTT 远程连接...");
|
||||||
|
mqttClient.end(true); // 强制关闭连接
|
||||||
|
mqttClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('btn-start-camera').onclick = async () => {
|
qrVideo.style.display = 'block';
|
||||||
stopCamera();
|
const oldQr = document.getElementById('remote-qr-canvas');
|
||||||
const deviceId = cameraSelect.value;
|
if (oldQr) oldQr.remove();
|
||||||
|
|
||||||
|
if(qrVideo.parentElement) {
|
||||||
|
qrVideo.parentElement.classList.remove('scanning');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startRemoteMode() {
|
||||||
|
if (mqttClient) {
|
||||||
|
mqttClient.end(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const broker = 'wss://test.mosquitto.org:8081';
|
||||||
|
const topic = `leye/scan/${myDeviceId}`;
|
||||||
|
|
||||||
|
mqttClient = mqtt.connect(broker);
|
||||||
|
|
||||||
|
mqttClient.on('connect', () => {
|
||||||
|
mqttClient.subscribe(topic);
|
||||||
|
eda.sys_Message.showToastMessage('MQTT 远程模式启动', ESYS_ToastMessageType.SUCCESS);
|
||||||
|
|
||||||
|
const scanUrl = `https://leye.dragon.edu.kg/scan.html?id=${myDeviceId}`;
|
||||||
|
|
||||||
|
qrVideo.style.display = 'none';
|
||||||
|
let qrCanvas = document.getElementById('remote-qr-canvas') || createQrCanvas();
|
||||||
|
QRCode.toCanvas(qrCanvas, scanUrl, { width: 250 });
|
||||||
|
});
|
||||||
|
|
||||||
|
mqttClient.on('message', (t, message) => {
|
||||||
|
try {
|
||||||
|
const msg = JSON.parse(message.toString());
|
||||||
|
if (msg.type === 'SCAN_RESULT') {
|
||||||
|
parseQrData(msg.content);
|
||||||
|
eda.sys_Message.showToastMessage('远程扫码成功', ESYS_ToastMessageType.INFO);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("MQTT数据解析失败", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createQrCanvas() {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.id = 'remote-qr-canvas';
|
||||||
|
canvas.className = "absolute inset-0 w-full h-full p-4 bg-white";
|
||||||
|
qrVideo.parentElement.appendChild(canvas);
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startLocalCamera(deviceId) {
|
||||||
const constraints = {
|
const constraints = {
|
||||||
video: deviceId ? { deviceId: { exact: deviceId } } : { facingMode: 'environment' }
|
video: deviceId ? { deviceId: { exact: deviceId } } : { facingMode: 'environment' }
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
videoStream = await navigator.mediaDevices.getUserMedia(constraints);
|
videoStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
qrVideo.srcObject = videoStream;
|
qrVideo.srcObject = videoStream;
|
||||||
@ -199,6 +259,17 @@
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
eda.sys_Message.showToastMessage('启动摄像头失败', ESYS_ToastMessageType.ERROR);
|
eda.sys_Message.showToastMessage('启动摄像头失败', ESYS_ToastMessageType.ERROR);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('btn-start-camera').onclick = async () => {
|
||||||
|
stopCamera();
|
||||||
|
const mode = cameraSelect.value;
|
||||||
|
|
||||||
|
if (mode === "WEBSOCKET_MODE") {
|
||||||
|
startRemoteMode();
|
||||||
|
} else {
|
||||||
|
startLocalCamera(mode);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('btn-scan').onclick = () => {
|
document.getElementById('btn-scan').onclick = () => {
|
||||||
@ -429,7 +500,6 @@
|
|||||||
|
|
||||||
let successCount = 0;
|
let successCount = 0;
|
||||||
let failCount = 0;
|
let failCount = 0;
|
||||||
const SERVER = await eda.sys_Storage.getExtensionUserConfig('server-host') || 'http://localhost:21816';
|
|
||||||
|
|
||||||
for (const item of toSave) {
|
for (const item of toSave) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
19
iframe/js/mqtt.min.js
vendored
Normal file
19
iframe/js/mqtt.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
iframe/js/qrcode.min.js
vendored
Normal file
7
iframe/js/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user