From ec0e9a96ab21cc681da29df7087932923632f4dd Mon Sep 17 00:00:00 2001 From: XingCheng3 <1773407212@qq.com> Date: Thu, 28 May 2026 17:45:38 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=AF=8F=E6=AC=A1=20=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E6=89=8B=E5=8A=A8=E4=B8=8A=E7=BA=BF=E6=97=B6=20=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=20=E7=89=A9=E6=96=99=E7=BC=96=E7=A0=81=E4=B8=8E?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=E5=85=B3=E7=B3=BB=E5=88=B0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=202.=E5=BD=93=E4=BA=BA=E5=B7=A5=E6=89=AB?= =?UTF-8?q?=E7=A0=81=E6=97=B6=20=E6=94=B6=E5=88=B0MQTT=E6=B6=88=E6=81=AF?= =?UTF-8?q?=20=E5=BC=B9=E5=87=BA=E7=AA=97=E5=8F=A3=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E8=AF=A5=E7=89=A9=E6=96=99=E5=8F=B7=E5=8E=86=E5=8F=B2=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E5=8F=B7=20=E5=8F=AF=E4=BA=BA=E5=B7=A5=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E6=88=96=E8=87=AA=E8=A1=8C=E8=BE=93=E5=85=A5=E6=96=B0?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=203.=E7=82=B9=E5=87=BB=E4=B8=8A?= =?UTF-8?q?=E7=BA=BF=E6=8C=89=E9=92=AE=20=E9=9C=80=E8=A6=81=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1=E7=A1=AE=E8=AE=A4=E4=BF=A1=E6=81=AF=E5=BC=B9=E7=AA=97?= =?UTF-8?q?=20=E5=BC=B9=E7=AA=97=20=E6=98=BE=E7=A4=BA=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E6=88=96=E8=80=85=E5=B7=A5=E4=BB=B6=E7=9A=84=E8=AF=A6=E7=BB=86?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=20=E9=9C=80=E8=A6=81=E4=BA=8C=E6=AC=A1?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E6=88=96=E8=80=85=E5=8F=96=E6=B6=88=204.?= =?UTF-8?q?=E4=BA=8C=E6=AC=A1=E7=A1=AE=E8=AE=A4=E5=BC=B9=E7=AA=97=20?= =?UTF-8?q?=E4=B8=AD=E5=A2=9E=E5=8A=A0=20=E7=A8=8B=E5=BA=8F=E5=8F=B7=20?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7+=E7=89=A9=E6=96=99=E7=BC=96?= =?UTF-8?q?=E7=A0=81=205.=E7=89=88=E6=9C=AC=E5=8F=B7=20=E5=92=8C=20?= =?UTF-8?q?=E7=89=A9=E6=96=99=E7=BC=96=E7=A0=81=20=E6=94=BE=E5=9C=A8?= =?UTF-8?q?=E4=B8=80=E8=A1=8C=E6=98=BE=E7=A4=BA=20=E5=88=86=E4=B8=A4?= =?UTF-8?q?=E4=B8=AA=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../index copy20250528.vue | 1038 +++++++++++++++++ .../DeviceUpLineBarCodeDJ/index.vue | 891 ++++++++++++-- .../DeviceUpLineBarCodeZT/index.vue | 891 ++++++++++++-- static/config.js | 10 +- 4 files changed, 2581 insertions(+), 249 deletions(-) create mode 100644 src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index copy20250528.vue diff --git a/src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index copy20250528.vue b/src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index copy20250528.vue new file mode 100644 index 0000000..e0f2e63 --- /dev/null +++ b/src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index copy20250528.vue @@ -0,0 +1,1038 @@ + + + + + diff --git a/src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index.vue b/src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index.vue index e0f2e63..3c20c54 100644 --- a/src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index.vue +++ b/src/views/EquipmentManagement/DeviceUpLineBarCodeDJ/index.vue @@ -17,63 +17,55 @@
扫码上线验证信息
- + - - + + - - - - - - - - - - - - - + - + + + + + + - - - - - - - - - - -
-
- - -
- 验证通过
-
- 验证失败
-
- 解析错误
-
-
+
+
+
程序版本
+ +
+
+
物料编码
+ +
+
+
验证结果
+
+ 验证通过 + 验证失败 + 解析错误 +
+
+
扫码上线验证信息
- + - - + + - - - - - - - - - - - - - + - + + + + + + - - - - - - - - - - -
-
- - -
- 验证通过
-
- 验证失败
-
- 解析错误
-
-
+
+
+
程序版本
+ +
+
+
物料编码
+ +
+
+
验证结果
+
+ 验证通过 + 验证失败 + 解析错误 +
+
+
+ + +
+
选择程序版本
+
物料编码 · {{ versionDialog.partCode || '—' }}
+
+ +
+
+ 历史程序版本 + 共 {{ versionDialog.historyList.length }} 条 +
+ +
+
+ {{ item }} +
+
+
+
该物料暂无历史程序版本
+
请在下方手动输入新版本号
+
+ +
手动输入版本号
+ +
+ + +
+ + +
+
上线信息确认
+
请确认以下信息无误后再点击"确认上线"
+
+ +
+
+
关键信息
+
+
+
程序版本
+
{{ loadConfirmDialog.detail.程序版本 || '—' }}
+
+
+
物料编码
+
{{ loadConfirmDialog.detail.扫码物料编码 || '—' }}
+
+
+
+
程序号
+
{{ loadConfirmProgramNo || '—' }}
+
+
+ +
+
+
+
工位号
+
{{ loadConfirmDialog.detail.工位号 || '—' }}
+
+
+
序列号
+
{{ loadConfirmDialog.detail.扫码序列号 || '—' }}
+
+
+
工单号
+
{{ loadConfirmDialog.detail.工单号 || '—' }}
+
+
+
扫码值
+
{{ loadConfirmDialog.detail.扫码值 || '—' }}
+
+
+
+
+ + +
@@ -366,10 +457,14 @@ import { mqttIp, mqttTopic, mqttInitRequestTopic, writePlcApi_BtnType, selectOpN const PROGRAM_VERSION_TAG_ID = '208640' /** 程序版本下拉选项 */ -const PROGRAM_VERSION_OPTIONS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('') +/** 程序版本可选项(PLC 实际可写的字符值) */ +const PROGRAM_VERSION_OPTIONS = [] /** 轮询读取的所有 PLC 信号标识 */ -const POLL_TAG_IDS = ['200004', '200005', '200006', '200007', '200380', '203240', '200440', PROGRAM_VERSION_TAG_ID] +const POLL_TAG_IDS = ['200004', '200005', '200006', '200007', '200380', '203240', '200440'] + +/** 上次使用的程序版本 localStorage key 前缀(按工位独立) */ +const LAST_VERSION_STORAGE_PREFIX = 'ZL_DJ_LastProgramVersion_' /** 状态灯信号 → data 属性映射 */ const STATUS_TAG_MAP = { @@ -404,6 +499,9 @@ export default { // 双工位扫码验证数据 ws1Result: { 扫码值: '', 工单号: '', 扫码物料编码: '', 扫码序列号: '', 错误消息: '', 验证结果: '', 程序版本: '' }, ws2Result: { 扫码值: '', 工单号: '', 扫码物料编码: '', 扫码序列号: '', 错误消息: '', 验证结果: '', 程序版本: '' }, + // 是否已处理过首次扫码(首次:自动取最近一次版本,不弹窗;之后:弹窗手动选) + ws1FirstVerifyHandled: false, + ws2FirstVerifyHandled: false, programVersionOptions: PROGRAM_VERSION_OPTIONS, // 双工位托盘信息 ws1Tray: { 托盘号: '', 托盘物料编码: '', 托盘工件状态: '' }, @@ -424,10 +522,41 @@ export default { isResetSerialLoading: false, // 轮询定时器(按工位分别存储,支持双工位同时轮询) pollTimers: {}, + // 历史程序版本选择弹窗 + versionDialog: { + visible: false, + opName: '', + partCode: '', + historyList: [], + selectedVersion: '' + }, + // 手动上线二次确认弹窗 + loadConfirmDialog: { + visible: false, + loading: false, + opName: '', + detail: { + 工位号: '', 扫码值: '', 工单号: '', 扫码序列号: '', 扫码物料编码: '', 程序版本: '' + } + }, } }, computed: { - ...mapGetters(['id', 'token']) + ...mapGetters(['id', 'token', 'name']), + versionDialogOptions() { + const merged = [...this.versionDialog.historyList] + this.programVersionOptions.forEach(v => { + if (!merged.includes(v)) merged.push(v) + }) + return merged + }, + /** 上线信息确认弹窗 - 程序号 = 程序版本 + 物料编码 */ + loadConfirmProgramNo() { + const ver = this.loadConfirmDialog.detail.程序版本 || '' + const code = this.loadConfirmDialog.detail.扫码物料编码 || '' + if (!ver && !code) return '' + return `${ver}${code}` + } }, created() { if (this.opNameType === '转台上线') { @@ -518,7 +647,6 @@ export default { if (valueMap['200380'] !== undefined) tray.托盘号 = valueMap['200380'] if (valueMap['203240'] !== undefined) this.convertMaterialCode(opName, valueMap['203240']) if (valueMap['200440'] !== undefined) tray.托盘工件状态 = TRAY_STATUS_TEXT[valueMap['200440']] || '' - if (valueMap[PROGRAM_VERSION_TAG_ID] !== undefined) result.程序版本 = valueMap[PROGRAM_VERSION_TAG_ID] || '' }, /** 将PLC读取到的物料号通过存储过程转换为物料编码 */ @@ -715,7 +843,7 @@ export default { switch (interFaceType) { case 'VerifyResult': { - if (arrays_signal.length < 11) { + if (arrays_signal.length < 9) { this.$message.warning('收到扫码结果,但是数据异常,不予处理!') console.log(msg) return @@ -737,10 +865,22 @@ export default { targetResult.扫码物料编码 = arrays_signal[6] targetResult.扫码序列号 = arrays_signal[7] targetResult.工单号 = arrays_signal[8] - targetResult.工单物料编号 = arrays_signal[9] - targetResult.工单序列号 = arrays_signal[10] + // targetResult.工单物料编号 = arrays_signal[9] + // targetResult.工单序列号 = arrays_signal[10] if (targetResult.验证结果 == 1) { this.$message.success('收到校验结果,校验通过!' + targetResult.错误消息) + if (pos === this.clickOpName) { + const isFirst = pos === this.opNameList[0] + ? !this.ws1FirstVerifyHandled + : !this.ws2FirstVerifyHandled + if (isFirst) { + this.autoFillFirstVersion(pos) + if (pos === this.opNameList[0]) this.ws1FirstVerifyHandled = true + else this.ws2FirstVerifyHandled = true + } else { + this.openVersionDialog(pos) + } + } if (this.isAutoPartLoad && this.clickOpName === pos) { this.partLoadOpName(targetResult.扫码工位) } @@ -804,17 +944,50 @@ export default { return } - try { - await this.$confirm('确定要执行手动请求上线操作吗?', '确认操作', { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: 'warning' - }) - } catch (error) { + this.loadConfirmDialog.opName = opName + this.loadConfirmDialog.detail = { + 工位号: opName, + 扫码值: result.扫码值 || '', + 工单号: result.工单号 || '', + 扫码序列号: result.扫码序列号 || '', + 扫码物料编码: result.扫码物料编码 || '', + 程序版本: programVersion + } + this.loadConfirmDialog.loading = false + this.loadConfirmDialog.visible = true + }, + + /** 二次确认弹窗"确定":把弹窗里的程序版本写回扫码结果,再走 PLC 写值流程 */ + async confirmLoadDialog() { + const opName = this.loadConfirmDialog.opName + const version = this.loadConfirmDialog.detail.程序版本 + ? this.loadConfirmDialog.detail.程序版本.toString() + : '' + if (!version) { + this.$message.warning('请选择或输入程序版本!') return } + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + result.程序版本 = version + this.setLastUsedVersion(opName, version) + + this.loadConfirmDialog.loading = true + try { + await this.doPartLoad(opName) + } finally { + this.loadConfirmDialog.loading = false + this.loadConfirmDialog.visible = false + } + }, + + /** 实际执行 PLC 写值上线流程;成功后写入手动上线记录 */ + async doPartLoad(opName) { + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result const partLoadStatus = opName === this.opNameList[0] ? this.ws1PartLoadStatus : this.ws2PartLoadStatus + const programVersion = result.程序版本 ? result.程序版本.toString() : '' + const partCode = result.扫码物料编码 || '' + const plcValue = await this.getPLCValue(opName, '205015') if (plcValue === 'True') { partLoadStatus.success = false @@ -824,34 +997,112 @@ export default { return } - this.writePLCValue(opName, PROGRAM_VERSION_TAG_ID, programVersion) - .then(response => { - if (response.data.code != 0) { - return Promise.reject(new Error(response.data.msg || '程序版本写入失败')) - } - return this.writePLCValue(opName, '205015', 'true') - }) - .then(response => { - if (response.data.code == 0) { - partLoadStatus.success = true - partLoadStatus.message = '' - partLoadStatus.show = true - this.$message.success('申请上线成功!') - } else { - partLoadStatus.success = false - partLoadStatus.message = response.data.msg || '申请失败' - partLoadStatus.show = true - this.$message.error(response.data.msg) - } - }) - .catch(error => { - partLoadStatus.success = false - partLoadStatus.message = error.message + try { + const r1 = await this.writePLCValue(opName, PROGRAM_VERSION_TAG_ID, programVersion) + if (r1.data.code != 0) throw new Error(r1.data.msg || '程序版本写入失败') + const r2 = await this.writePLCValue(opName, '205015', 'true') + if (r2.data.code == 0) { + partLoadStatus.success = true + partLoadStatus.message = '' partLoadStatus.show = true - this.$message.error('申请上线失败' + error.message) + this.$message.success('申请上线成功!') + this.recordManualLoad(opName, partCode, programVersion) + } else { + partLoadStatus.success = false + partLoadStatus.message = r2.data.msg || '申请失败' + partLoadStatus.show = true + this.$message.error(r2.data.msg) + } + } catch (error) { + partLoadStatus.success = false + partLoadStatus.message = error.message + partLoadStatus.show = true + this.$message.error('申请上线失败' + error.message) + } + }, + + /** 写入手动上线 (物料编码,程序版本) 记录 */ + recordManualLoad(opName, partCode, version) { + if (!partCode || !version) return + const param = [] + param[0] = ['物料编码', partCode] + param[1] = ['程序版本', version] + param[2] = ['工位号', opName] + param[3] = ['操作人', this.name || ''] + const Data = this.CreateData('12', 'ZL_物料程序版本_手动上线记录_Insert', param) + this.ExecDatabase(Data).catch(err => console.error('记录手动上线失败:', err)) + }, + + // ==================== 历史程序版本弹窗 ==================== + + /** 查询某物料编码的历史程序版本(按最近使用时间倒序) */ + loadHistoryVersions(partCode) { + if (!partCode) return Promise.resolve([]) + const param = [['物料编码', partCode]] + const Data = this.CreateData('11', 'ZL_物料程序版本_手动上线记录_查询历史版本', param) + return this.ExecDatabase(Data) + .then(resp => Array.isArray(resp.data) ? resp.data.map(r => r.程序版本).filter(v => !!v) : []) + .catch(err => { + console.error('查询历史程序版本失败:', err) + return [] }) }, + /** 打开"选择程序版本"弹窗:扫码验证通过且为当前工位时触发 */ + async openVersionDialog(opName) { + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + const partCode = result.扫码物料编码 || '' + const historyList = await this.loadHistoryVersions(partCode) + const lastUsed = this.getLastUsedVersion(opName) + this.versionDialog.opName = opName + this.versionDialog.partCode = partCode + this.versionDialog.historyList = historyList + this.versionDialog.selectedVersion = (result.程序版本 || lastUsed || historyList[0] || '') + this.versionDialog.visible = true + }, + + /** 首次扫码:从数据库取该物料最近一次的程序版本,直接回填,不弹窗 */ + async autoFillFirstVersion(opName) { + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + const partCode = result.扫码物料编码 || '' + if (!partCode) return + const historyList = await this.loadHistoryVersions(partCode) + if (historyList && historyList.length > 0) { + result.程序版本 = historyList[0] + this.setLastUsedVersion(opName, historyList[0]) + } + }, + + /** "选择程序版本"弹窗确定:把版本回填到对应工位,不自动上线 */ + confirmVersionDialog() { + const version = this.versionDialog.selectedVersion ? this.versionDialog.selectedVersion.toString() : '' + if (!version) { + this.$message.warning('请选择或输入程序版本!') + return + } + const opName = this.versionDialog.opName + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + result.程序版本 = version + this.setLastUsedVersion(opName, version) + this.versionDialog.visible = false + }, + + /** 读取该工位上一次使用的程序版本(localStorage) */ + getLastUsedVersion(opName) { + try { + return localStorage.getItem(LAST_VERSION_STORAGE_PREFIX + opName) || '' + } catch (e) { + return '' + } + }, + + /** 持久化保存该工位本次使用的程序版本(localStorage) */ + setLastUsedVersion(opName, version) { + try { + localStorage.setItem(LAST_VERSION_STORAGE_PREFIX + opName, version || '') + } catch (e) { /* ignore */ } + }, + // ==================== 读码 / 写码 / 清码 ==================== /** 写码 - 发送写码请求并启动10秒轮询 */ @@ -1035,4 +1286,400 @@ export default { font-size: inherit !important; } } + +.material-version-row { + display: flex; + align-items: flex-end; + gap: 8px; + margin-top: 4px; + + .mv-version { + flex: 0 0 90px; + } + + .mv-material { + flex: 2 1 0; + min-width: 0; + } + + .mv-result { + flex: 1 1 0; + min-width: 120px; + } + + .top-label { + font-size: 14px; + color: #606266; + font-weight: bold; + line-height: 1.4; + padding: 0 0 2px 2px; + } + + .version-input { + ::v-deep .el-input__inner { + text-align: right; + cursor: pointer; + background-color: #fff; + } + } + + .result-display { + height: 32px; + display: flex; + align-items: center; + justify-content: center; + + .result-pass, + .result-fail, + .result-error { + display: inline-block; + width: 100%; + font-weight: bold; + font-size: 14px; + padding: 4px 8px; + border-radius: 4px; + text-align: center; + } + + .result-pass { background: #aaff33; color: #222; } + .result-fail { background: #ff3b3b; color: #fff; } + .result-error { background: #ffe066; color: #222; } + } +} + +.upline-form { + ::v-deep .el-form-item__label { + width: 70px !important; + padding-right: 6px; + } + + ::v-deep .el-form-item__content { + width: calc(100% - 70px) !important; + } +} + + + diff --git a/src/views/EquipmentManagement/DeviceUpLineBarCodeZT/index.vue b/src/views/EquipmentManagement/DeviceUpLineBarCodeZT/index.vue index 955293f..5e76f88 100644 --- a/src/views/EquipmentManagement/DeviceUpLineBarCodeZT/index.vue +++ b/src/views/EquipmentManagement/DeviceUpLineBarCodeZT/index.vue @@ -17,63 +17,55 @@
扫码上线验证信息
- + - - + + - - - - - - - - - - - - - + - + + + + + + - - - - - - - - - - -
-
- - -
- 验证通过
-
- 验证失败
-
- 解析错误
-
-
+
+
+
程序版本
+ +
+
+
物料编码
+ +
+
+
验证结果
+
+ 验证通过 + 验证失败 + 解析错误 +
+
+
扫码上线验证信息
- + - - + + - - - - - - - - - - - - - + - + + + + + + - - - - - - - - - - -
-
- - -
- 验证通过
-
- 验证失败
-
- 解析错误
-
-
+
+
+
程序版本
+ +
+
+
物料编码
+ +
+
+
验证结果
+
+ 验证通过 + 验证失败 + 解析错误 +
+
+
+ + +
+
选择程序版本
+
物料编码 · {{ versionDialog.partCode || '—' }}
+
+ +
+
+ 历史程序版本 + 共 {{ versionDialog.historyList.length }} 条 +
+ +
+
+ {{ item }} +
+
+
+
该物料暂无历史程序版本
+
请在下方手动输入新版本号
+
+ +
手动输入版本号
+ +
+ + +
+ + +
+
上线信息确认
+
请确认以下信息无误后再点击"确认上线"
+
+ +
+
+
关键信息
+
+
+
程序版本
+
{{ loadConfirmDialog.detail.程序版本 || '—' }}
+
+
+
物料编码
+
{{ loadConfirmDialog.detail.扫码物料编码 || '—' }}
+
+
+
+
程序号
+
{{ loadConfirmProgramNo || '—' }}
+
+
+ +
+
+
+
工位号
+
{{ loadConfirmDialog.detail.工位号 || '—' }}
+
+
+
序列号
+
{{ loadConfirmDialog.detail.扫码序列号 || '—' }}
+
+
+
工单号
+
{{ loadConfirmDialog.detail.工单号 || '—' }}
+
+
+
扫码值
+
{{ loadConfirmDialog.detail.扫码值 || '—' }}
+
+
+
+
+ + +
@@ -366,10 +457,14 @@ import { mqttIp, mqttTopic, mqttInitRequestTopic, writePlcApi_BtnType, selectOpN const PROGRAM_VERSION_TAG_ID = '208640' /** 程序版本下拉选项 */ -const PROGRAM_VERSION_OPTIONS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('') +/** 程序版本可选项(PLC 实际可写的字符值) */ +const PROGRAM_VERSION_OPTIONS = [] /** 轮询读取的所有 PLC 信号标识 */ -const POLL_TAG_IDS = ['200004', '200005', '200006', '200007', '200380', '203240', '200440', PROGRAM_VERSION_TAG_ID] +const POLL_TAG_IDS = ['200004', '200005', '200006', '200007', '200380', '203240', '200440'] + +/** 上次使用的程序版本 localStorage key 前缀(按工位独立) */ +const LAST_VERSION_STORAGE_PREFIX = 'ZL_DJ_LastProgramVersion_' /** 状态灯信号 → data 属性映射 */ const STATUS_TAG_MAP = { @@ -404,6 +499,9 @@ export default { // 双工位扫码验证数据 ws1Result: { 扫码值: '', 工单号: '', 扫码物料编码: '', 扫码序列号: '', 错误消息: '', 验证结果: '', 程序版本: '' }, ws2Result: { 扫码值: '', 工单号: '', 扫码物料编码: '', 扫码序列号: '', 错误消息: '', 验证结果: '', 程序版本: '' }, + // 是否已处理过首次扫码(首次:自动取最近一次版本,不弹窗;之后:弹窗手动选) + ws1FirstVerifyHandled: false, + ws2FirstVerifyHandled: false, programVersionOptions: PROGRAM_VERSION_OPTIONS, // 双工位托盘信息 ws1Tray: { 托盘号: '', 托盘物料编码: '', 托盘工件状态: '' }, @@ -424,10 +522,41 @@ export default { isResetSerialLoading: false, // 轮询定时器(按工位分别存储,支持双工位同时轮询) pollTimers: {}, + // 历史程序版本选择弹窗 + versionDialog: { + visible: false, + opName: '', + partCode: '', + historyList: [], + selectedVersion: '' + }, + // 手动上线二次确认弹窗 + loadConfirmDialog: { + visible: false, + loading: false, + opName: '', + detail: { + 工位号: '', 扫码值: '', 工单号: '', 扫码序列号: '', 扫码物料编码: '', 程序版本: '' + } + }, } }, computed: { - ...mapGetters(['id', 'token']) + ...mapGetters(['id', 'token', 'name']), + versionDialogOptions() { + const merged = [...this.versionDialog.historyList] + this.programVersionOptions.forEach(v => { + if (!merged.includes(v)) merged.push(v) + }) + return merged + }, + /** 上线信息确认弹窗 - 程序号 = 程序版本 + 物料编码 */ + loadConfirmProgramNo() { + const ver = this.loadConfirmDialog.detail.程序版本 || '' + const code = this.loadConfirmDialog.detail.扫码物料编码 || '' + if (!ver && !code) return '' + return `${ver}${code}` + } }, created() { if (this.opNameType === '转台上线') { @@ -518,7 +647,6 @@ export default { if (valueMap['200380'] !== undefined) tray.托盘号 = valueMap['200380'] if (valueMap['203240'] !== undefined) this.convertMaterialCode(opName, valueMap['203240']) if (valueMap['200440'] !== undefined) tray.托盘工件状态 = TRAY_STATUS_TEXT[valueMap['200440']] || '' - if (valueMap[PROGRAM_VERSION_TAG_ID] !== undefined) result.程序版本 = valueMap[PROGRAM_VERSION_TAG_ID] || '' }, /** 将PLC读取到的物料号通过存储过程转换为物料编码 */ @@ -715,7 +843,7 @@ export default { switch (interFaceType) { case 'VerifyResult': { - if (arrays_signal.length < 11) { + if (arrays_signal.length < 9) { this.$message.warning('收到扫码结果,但是数据异常,不予处理!') console.log(msg) return @@ -737,10 +865,22 @@ export default { targetResult.扫码物料编码 = arrays_signal[6] targetResult.扫码序列号 = arrays_signal[7] targetResult.工单号 = arrays_signal[8] - targetResult.工单物料编号 = arrays_signal[9] - targetResult.工单序列号 = arrays_signal[10] + // targetResult.工单物料编号 = arrays_signal[9] + // targetResult.工单序列号 = arrays_signal[10] if (targetResult.验证结果 == 1) { this.$message.success('收到校验结果,校验通过!' + targetResult.错误消息) + if (pos === this.clickOpName) { + const isFirst = pos === this.opNameList[0] + ? !this.ws1FirstVerifyHandled + : !this.ws2FirstVerifyHandled + if (isFirst) { + this.autoFillFirstVersion(pos) + if (pos === this.opNameList[0]) this.ws1FirstVerifyHandled = true + else this.ws2FirstVerifyHandled = true + } else { + this.openVersionDialog(pos) + } + } if (this.isAutoPartLoad && this.clickOpName === pos) { this.partLoadOpName(targetResult.扫码工位) } @@ -804,17 +944,50 @@ export default { return } - try { - await this.$confirm('确定要执行手动请求上线操作吗?', '确认操作', { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: 'warning' - }) - } catch (error) { + this.loadConfirmDialog.opName = opName + this.loadConfirmDialog.detail = { + 工位号: opName, + 扫码值: result.扫码值 || '', + 工单号: result.工单号 || '', + 扫码序列号: result.扫码序列号 || '', + 扫码物料编码: result.扫码物料编码 || '', + 程序版本: programVersion + } + this.loadConfirmDialog.loading = false + this.loadConfirmDialog.visible = true + }, + + /** 二次确认弹窗"确定":把弹窗里的程序版本写回扫码结果,再走 PLC 写值流程 */ + async confirmLoadDialog() { + const opName = this.loadConfirmDialog.opName + const version = this.loadConfirmDialog.detail.程序版本 + ? this.loadConfirmDialog.detail.程序版本.toString() + : '' + if (!version) { + this.$message.warning('请选择或输入程序版本!') return } + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + result.程序版本 = version + this.setLastUsedVersion(opName, version) + + this.loadConfirmDialog.loading = true + try { + await this.doPartLoad(opName) + } finally { + this.loadConfirmDialog.loading = false + this.loadConfirmDialog.visible = false + } + }, + + /** 实际执行 PLC 写值上线流程;成功后写入手动上线记录 */ + async doPartLoad(opName) { + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result const partLoadStatus = opName === this.opNameList[0] ? this.ws1PartLoadStatus : this.ws2PartLoadStatus + const programVersion = result.程序版本 ? result.程序版本.toString() : '' + const partCode = result.扫码物料编码 || '' + const plcValue = await this.getPLCValue(opName, '205015') if (plcValue === 'True') { partLoadStatus.success = false @@ -824,34 +997,112 @@ export default { return } - this.writePLCValue(opName, PROGRAM_VERSION_TAG_ID, programVersion) - .then(response => { - if (response.data.code != 0) { - return Promise.reject(new Error(response.data.msg || '程序版本写入失败')) - } - return this.writePLCValue(opName, '205015', 'true') - }) - .then(response => { - if (response.data.code == 0) { - partLoadStatus.success = true - partLoadStatus.message = '' - partLoadStatus.show = true - this.$message.success('申请上线成功!') - } else { - partLoadStatus.success = false - partLoadStatus.message = response.data.msg || '申请失败' - partLoadStatus.show = true - this.$message.error(response.data.msg) - } - }) - .catch(error => { - partLoadStatus.success = false - partLoadStatus.message = error.message + try { + const r1 = await this.writePLCValue(opName, PROGRAM_VERSION_TAG_ID, programVersion) + if (r1.data.code != 0) throw new Error(r1.data.msg || '程序版本写入失败') + const r2 = await this.writePLCValue(opName, '205015', 'true') + if (r2.data.code == 0) { + partLoadStatus.success = true + partLoadStatus.message = '' partLoadStatus.show = true - this.$message.error('申请上线失败' + error.message) + this.$message.success('申请上线成功!') + this.recordManualLoad(opName, partCode, programVersion) + } else { + partLoadStatus.success = false + partLoadStatus.message = r2.data.msg || '申请失败' + partLoadStatus.show = true + this.$message.error(r2.data.msg) + } + } catch (error) { + partLoadStatus.success = false + partLoadStatus.message = error.message + partLoadStatus.show = true + this.$message.error('申请上线失败' + error.message) + } + }, + + /** 写入手动上线 (物料编码,程序版本) 记录 */ + recordManualLoad(opName, partCode, version) { + if (!partCode || !version) return + const param = [] + param[0] = ['物料编码', partCode] + param[1] = ['程序版本', version] + param[2] = ['工位号', opName] + param[3] = ['操作人', this.name || ''] + const Data = this.CreateData('12', 'ZL_物料程序版本_手动上线记录_Insert', param) + this.ExecDatabase(Data).catch(err => console.error('记录手动上线失败:', err)) + }, + + // ==================== 历史程序版本弹窗 ==================== + + /** 查询某物料编码的历史程序版本(按最近使用时间倒序) */ + loadHistoryVersions(partCode) { + if (!partCode) return Promise.resolve([]) + const param = [['物料编码', partCode]] + const Data = this.CreateData('11', 'ZL_物料程序版本_手动上线记录_查询历史版本', param) + return this.ExecDatabase(Data) + .then(resp => Array.isArray(resp.data) ? resp.data.map(r => r.程序版本).filter(v => !!v) : []) + .catch(err => { + console.error('查询历史程序版本失败:', err) + return [] }) }, + /** 打开"选择程序版本"弹窗:扫码验证通过且为当前工位时触发 */ + async openVersionDialog(opName) { + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + const partCode = result.扫码物料编码 || '' + const historyList = await this.loadHistoryVersions(partCode) + const lastUsed = this.getLastUsedVersion(opName) + this.versionDialog.opName = opName + this.versionDialog.partCode = partCode + this.versionDialog.historyList = historyList + this.versionDialog.selectedVersion = (result.程序版本 || lastUsed || historyList[0] || '') + this.versionDialog.visible = true + }, + + /** 首次扫码:从数据库取该物料最近一次的程序版本,直接回填,不弹窗 */ + async autoFillFirstVersion(opName) { + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + const partCode = result.扫码物料编码 || '' + if (!partCode) return + const historyList = await this.loadHistoryVersions(partCode) + if (historyList && historyList.length > 0) { + result.程序版本 = historyList[0] + this.setLastUsedVersion(opName, historyList[0]) + } + }, + + /** "选择程序版本"弹窗确定:把版本回填到对应工位,不自动上线 */ + confirmVersionDialog() { + const version = this.versionDialog.selectedVersion ? this.versionDialog.selectedVersion.toString() : '' + if (!version) { + this.$message.warning('请选择或输入程序版本!') + return + } + const opName = this.versionDialog.opName + const result = opName === this.opNameList[0] ? this.ws1Result : this.ws2Result + result.程序版本 = version + this.setLastUsedVersion(opName, version) + this.versionDialog.visible = false + }, + + /** 读取该工位上一次使用的程序版本(localStorage) */ + getLastUsedVersion(opName) { + try { + return localStorage.getItem(LAST_VERSION_STORAGE_PREFIX + opName) || '' + } catch (e) { + return '' + } + }, + + /** 持久化保存该工位本次使用的程序版本(localStorage) */ + setLastUsedVersion(opName, version) { + try { + localStorage.setItem(LAST_VERSION_STORAGE_PREFIX + opName, version || '') + } catch (e) { /* ignore */ } + }, + // ==================== 读码 / 写码 / 清码 ==================== /** 写码 - 发送写码请求并启动10秒轮询 */ @@ -1035,4 +1286,400 @@ export default { font-size: inherit !important; } } + +.material-version-row { + display: flex; + align-items: flex-end; + gap: 8px; + margin-top: 4px; + + .mv-version { + flex: 0 0 90px; + } + + .mv-material { + flex: 2 1 0; + min-width: 0; + } + + .mv-result { + flex: 1 1 0; + min-width: 120px; + } + + .top-label { + font-size: 14px; + color: #606266; + font-weight: bold; + line-height: 1.4; + padding: 0 0 2px 2px; + } + + .version-input { + ::v-deep .el-input__inner { + text-align: right; + cursor: pointer; + background-color: #fff; + } + } + + .result-display { + height: 32px; + display: flex; + align-items: center; + justify-content: center; + + .result-pass, + .result-fail, + .result-error { + display: inline-block; + width: 100%; + font-weight: bold; + font-size: 14px; + padding: 4px 8px; + border-radius: 4px; + text-align: center; + } + + .result-pass { background: #aaff33; color: #222; } + .result-fail { background: #ff3b3b; color: #fff; } + .result-error { background: #ffe066; color: #222; } + } +} + +.upline-form { + ::v-deep .el-form-item__label { + width: 70px !important; + padding-right: 6px; + } + + ::v-deep .el-form-item__content { + width: calc(100% - 70px) !important; + } +} + + + diff --git a/static/config.js b/static/config.js index 6480437..31415fe 100644 --- a/static/config.js +++ b/static/config.js @@ -6,14 +6,14 @@ export const name4_config = `OP9999` // 工厂网段 192.168.0.180 生产环境需使用 // 开发环境使用 127.0.0.1 -// var url = `http://192.168.0.180:10140` -// var api = `http://192.168.0.180:9981` +var url = `http://192.168.0.180:10140` +var api = `http://192.168.0.180:9981` -var url = `http://127.0.0.1:10140` -var api = `http://127.0.0.1:9981` +// var url = `http://127.0.0.1:10140` +// var api = `http://127.0.0.1:9981` // var url = `http://192.168.0.180:10140` -// export const mqttIp = `192.168.0.180` +// export const mqttIp = `127.0.0.1` export const mqttIp = `192.168.0.180` export const mqttTopic = `VerifyResult` export const mqttInitRequestTopic = `MesServer`