Vue.component("monitor-workbench", { template: `
设备选择
当前没有可展示的数据
快捷操作
{{ controlTargetText }}
{{ controlPanelHint }}
{{ getItemTitle(activeCard, selectedItem) }}
{{ getItemMeta(activeCard, selectedItem) }}
{{ entry.label }}
{{ entry.value }}
请先从左侧选择一个设备
{{ noticeMessage }}
`, props: { activeCard: { type: String, default: "crn" }, crnParam: { type: Object, default: function () { return {}; } }, dualCrnParam: { type: Object, default: function () { return {}; } }, devpParam: { type: Object, default: function () { return {}; } }, rgvParam: { type: Object, default: function () { return {}; } }, crnList: { type: Array, default: function () { return []; } }, dualCrnList: { type: Array, default: function () { return []; } }, stationList: { type: Array, default: function () { return []; } }, rgvList: { type: Array, default: function () { return []; } } }, data() { return { tabs: [ { key: "crn", label: "堆垛机" }, { key: "dualCrn", label: "双工位" }, { key: "devp", label: "输送站" }, { key: "rgv", label: "RGV" } ], searchMap: { crn: "", dualCrn: "", devp: "", rgv: "" }, selectedIdMap: { crn: null, dualCrn: null, devp: null, rgv: null }, showControlMap: { crn: false, dualCrn: false, devp: false, rgv: false }, controlForms: { crn: { crnNo: "", sourceLocNo: "", targetLocNo: "" }, dualCrn: { crnNo: "", sourceLocNo: "", targetLocNo: "", station: 1 }, devp: { stationId: "", taskNo: "", targetStationId: "" }, rgv: { rgvNo: "", sourcePos: "", targetPos: "" } }, noticeMessage: "", noticeType: "info", noticeTimer: null }; }, computed: { currentSearch() { return this.searchMap[this.activeCard] || ""; }, currentShowControl() { return !!this.showControlMap[this.activeCard]; }, currentList() { return this.getListByType(this.activeCard); }, filteredList() { const keyword = String(this.currentSearch || "").trim().toLowerCase(); if (!keyword) { return this.currentList; } return this.currentList.filter((item) => this.matchesKeyword(this.activeCard, item, keyword)); }, selectedItem() { return this.getSelectedItem(this.activeCard); }, detailEntries() { return this.buildDetailEntries(this.activeCard, this.selectedItem); }, controlPanelTitle() { if (this.activeCard === "crn") { return "堆垛机控制"; } if (this.activeCard === "dualCrn") { return "双工位控制"; } if (this.activeCard === "devp") { return "输送站控制"; } if (this.activeCard === "rgv") { return "RGV控制"; } return "控制操作"; }, controlPanelHint() { if (this.activeCard === "crn") { return "先确认设备号,再填写源库位和目标库位。"; } if (this.activeCard === "dualCrn") { return "先选择工位,再下发取货、放货或移动指令。"; } if (this.activeCard === "devp") { return "用于站点下发、复位和条码维护。"; } if (this.activeCard === "rgv") { return "用于轨道车取放货、移动和任务完成。"; } return ""; }, controlTargetText() { if (!this.selectedItem) { return "未选中设备"; } return "当前目标: " + this.getItemTitle(this.activeCard, this.selectedItem); } }, watch: { activeCard: { immediate: true, handler(type) { this.ensureSelection(type); } }, crnList() { this.ensureSelection("crn"); }, dualCrnList() { this.ensureSelection("dualCrn"); }, stationList() { this.ensureSelection("devp"); }, rgvList() { this.ensureSelection("rgv"); }, crnParam: { deep: true, handler(v) { this.applyExternalFocus("crn", v && v.crnNo); } }, dualCrnParam: { deep: true, handler(v) { this.applyExternalFocus("dualCrn", v && v.crnNo); } }, devpParam: { deep: true, handler(v) { this.applyExternalFocus("devp", v && v.stationId); } }, rgvParam: { deep: true, handler(v) { this.applyExternalFocus("rgv", v && v.rgvNo); } } }, beforeDestroy() { if (this.noticeTimer) { clearTimeout(this.noticeTimer); this.noticeTimer = null; } }, methods: { changeTab(type) { if (type === this.activeCard) { return; } this.$emit("change-tab", type); }, updateSearch(value) { this.$set(this.searchMap, this.activeCard, value); this.ensureSelection(this.activeCard); }, refreshCurrent() { this.$emit("refresh-request", this.activeCard); }, toggleControl() { this.$set(this.showControlMap, this.activeCard, !this.currentShowControl); if (this.currentShowControl && this.selectedItem) { this.hydrateControlForm(this.activeCard, this.selectedItem); } }, getListByType(type) { if (type === "crn") { return this.crnList || []; } if (type === "dualCrn") { return this.dualCrnList || []; } if (type === "devp") { return this.stationList || []; } if (type === "rgv") { return this.rgvList || []; } return []; }, getItemId(type, item) { if (!item) { return null; } if (type === "crn" || type === "dualCrn") { return item.crnNo; } if (type === "devp") { return item.stationId; } if (type === "rgv") { return item.rgvNo; } return null; }, getSelectedItem(type) { const list = this.filteredListForType(type); if (!list.length) { return null; } const selectedId = this.selectedIdMap[type]; for (let i = 0; i < list.length; i++) { if (String(this.getItemId(type, list[i])) === String(selectedId)) { return list[i]; } } return list[0]; }, filteredListForType(type) { const keyword = String(this.searchMap[type] || "").trim().toLowerCase(); const list = this.getListByType(type); if (!keyword) { return list; } return list.filter((item) => this.matchesKeyword(type, item, keyword)); }, ensureSelection(type) { const list = this.filteredListForType(type); if (!list.length) { this.$set(this.selectedIdMap, type, null); return; } const currentId = this.selectedIdMap[type]; const exists = list.some((item) => String(this.getItemId(type, item)) === String(currentId)); if (!exists) { this.$set(this.selectedIdMap, type, this.getItemId(type, list[0])); } }, applyExternalFocus(type, rawId) { if (rawId == null || rawId === "" || rawId === 0) { return; } this.$set(this.selectedIdMap, type, rawId); if (this.activeCard === type) { const item = this.getSelectedItem(type); if (item) { this.hydrateControlForm(type, item); } } }, selectItem(type, item) { this.$set(this.selectedIdMap, type, this.getItemId(type, item)); this.hydrateControlForm(type, item); }, hydrateControlForm(type, item) { if (!item) { return; } if (type === "crn") { this.controlForms.crn.crnNo = this.orEmpty(item.crnNo); } else if (type === "dualCrn") { this.controlForms.dualCrn.crnNo = this.orEmpty(item.crnNo); } else if (type === "devp") { this.controlForms.devp.stationId = this.orEmpty(item.stationId); this.controlForms.devp.taskNo = this.orEmpty(item.taskNo); this.controlForms.devp.targetStationId = this.orEmpty(item.targetStaNo); } else if (type === "rgv") { this.controlForms.rgv.rgvNo = this.orEmpty(item.rgvNo); } }, matchesKeyword(type, item, keyword) { const fields = []; if (type === "crn" || type === "dualCrn") { fields.push(item.crnNo, item.taskNo, item.taskNoTwo, item.locNo, item.sourceLocNo, item.status, item.mode); } else if (type === "devp") { fields.push(item.stationId, item.taskNo, item.targetStaNo, item.barcode, item.errorMsg, item.extend); } else if (type === "rgv") { fields.push(item.rgvNo, item.taskNo, item.trackSiteNo, item.status, item.mode, item.alarm); } return fields.some((field) => String(field == null ? "" : field).toLowerCase().indexOf(keyword) !== -1); }, currentSearchPlaceholder() { if (this.activeCard === "crn") { return "搜索堆垛机号"; } if (this.activeCard === "dualCrn") { return "搜索双工位堆垛机号"; } if (this.activeCard === "devp") { return "搜索站号 / 条码"; } if (this.activeCard === "rgv") { return "搜索RGV号"; } return "搜索"; }, getItemTitle(type, item) { if (!item) { return "-"; } if (type === "crn") { return item.crnNo + "号堆垛机"; } if (type === "dualCrn") { return item.crnNo + "号双工位堆垛机"; } if (type === "devp") { return item.stationId + "号站点"; } if (type === "rgv") { return item.rgvNo + "号RGV"; } return "-"; }, getItemMeta(type, item) { if (!item) { return "-"; } if (type === "crn") { return "任务 " + this.orDash(item.workNo) + " | 目标 " + this.orDash(item.locNo); } if (type === "dualCrn") { return "工位1 " + this.orDash(item.taskNo) + " | 工位2 " + this.orDash(item.taskNoTwo); } if (type === "devp") { return "任务 " + this.orDash(item.taskNo) + " | 目标站 " + this.orDash(item.targetStaNo); } if (type === "rgv") { return "轨道位 " + this.orDash(item.trackSiteNo) + " | 任务 " + this.orDash(item.taskNo); } return "-"; }, getStatusLabel(type, item) { if (!item) { return "未知"; } if (type === "devp") { return item.autoing ? "自动" : "手动"; } const status = String(item.deviceStatus || "").toUpperCase(); if (status === "AUTO") { return "自动"; } if (status === "WORKING") { return "作业中"; } if (status === "ERROR") { return "故障"; } return "离线"; }, getStatusTone(type, item) { const label = this.getStatusLabel(type, item); if (label === "自动") { return "success"; } if (label === "作业中") { return "working"; } if (label === "手动") { return "warning"; } if (label === "故障") { return "danger"; } return "muted"; }, isSelected(type, item) { return String(this.getItemId(type, item)) === String(this.selectedIdMap[type]); }, buildDetailEntries(type, item) { if (!item) { return []; } if (type === "crn") { return [ { label: "编号", value: this.orDash(item.crnNo) }, { label: "工作号", value: this.orDash(item.workNo) }, { label: "模式", value: this.orDash(item.mode) }, { label: "状态", value: this.orDash(item.status) }, { label: "源库位", value: this.orDash(item.sourceLocNo) }, { label: "目标库位", value: this.orDash(item.locNo) }, { label: "是否有物", value: this.yesNo(item.loading) }, { label: "任务接收", value: this.orDash(item.taskReceive) }, { label: "列", value: this.orDash(item.bay) }, { label: "层", value: this.orDash(item.lev) }, { label: "货叉定位", value: this.orDash(item.forkOffset) }, { label: "载货台定位", value: this.orDash(item.liftPos) }, { label: "走行定位", value: this.orDash(item.walkPos) }, { label: "走行速度", value: this.orDash(item.xspeed) }, { label: "升降速度", value: this.orDash(item.yspeed) }, { label: "叉牙速度", value: this.orDash(item.zspeed) }, { label: "称重数据", value: this.orDash(item.weight) }, { label: "条码数据", value: this.orDash(item.barcode) }, { label: "故障代码", value: this.orDash(item.warnCode) }, { label: "故障描述", value: this.orDash(item.alarm) } ]; } if (type === "dualCrn") { return [ { label: "模式", value: this.orDash(item.mode) }, { label: "异常码", value: this.orDash(item.warnCode) }, { label: "工位1任务号", value: this.orDash(item.taskNo) }, { label: "工位2任务号", value: this.orDash(item.taskNoTwo) }, { label: "工位1状态", value: this.orDash(item.status) }, { label: "工位2状态", value: this.orDash(item.statusTwo) }, { label: "工位1有物", value: this.yesNo(item.loading) }, { label: "工位2有物", value: this.yesNo(item.loadingTwo) }, { label: "列", value: this.orDash(item.bay) }, { label: "层", value: this.orDash(item.lev) }, { label: "载货台定位", value: this.orDash(item.liftPos) }, { label: "走行定位", value: this.orDash(item.walkPos) }, { label: "走行速度", value: this.orDash(item.xspeed) }, { label: "升降速度", value: this.orDash(item.yspeed) }, { label: "叉牙速度", value: this.orDash(item.zspeed) }, { label: "扩展数据", value: this.orDash(item.extend) } ]; } if (type === "devp") { return [ { label: "编号", value: this.orDash(item.stationId) }, { label: "工作号", value: this.orDash(item.taskNo) }, { label: "目标站", value: this.orDash(item.targetStaNo) }, { label: "模式", value: item.autoing ? "自动" : "手动" }, { label: "有物", value: this.yesNo(item.loading) }, { label: "可入", value: this.yesNo(item.inEnable) }, { label: "可出", value: this.yesNo(item.outEnable) }, { label: "空板信号", value: this.yesNo(item.emptyMk) }, { label: "满板信号", value: this.yesNo(item.fullPlt) }, { label: "运行阻塞", value: this.yesNo(item.runBlock) }, { label: "启动入库", value: this.yesNo(item.enableIn) }, { label: "托盘高度", value: this.orDash(item.palletHeight) }, { label: "条码", value: this.orDash(item.barcode) }, { label: "重量", value: this.orDash(item.weight) }, { label: "任务可写区", value: this.orDash(item.taskWriteIdx) }, { label: "故障代码", value: this.orDash(item.error) }, { label: "故障信息", value: this.orDash(item.errorMsg) } ]; } if (type === "rgv") { return [ { label: "编号", value: this.orDash(item.rgvNo) }, { label: "工作号", value: this.orDash(item.taskNo) }, { label: "模式", value: this.orDash(item.mode) }, { label: "状态", value: this.orDash(item.status) }, { label: "轨道位", value: this.orDash(item.trackSiteNo) }, { label: "是否有物", value: this.yesNo(item.loading) }, { label: "故障代码", value: this.orDash(item.warnCode) }, { label: "故障描述", value: this.orDash(item.alarm) }, { label: "扩展数据", value: this.orDash(item.extend) } ]; } return []; }, submitControl(action) { const config = this.getControlConfig(this.activeCard, action); if (!config) { return; } $.ajax({ url: baseUrl + config.url, headers: { token: localStorage.getItem("token") }, contentType: "application/json", method: "post", data: JSON.stringify(config.payload), success: (res) => { if (res && res.code === 200) { this.showNotice(res.msg || "操作成功", "success"); this.$emit("refresh-request", this.activeCard); } else { this.showNotice((res && res.msg) || "操作失败", "warning"); } }, error: () => { this.showNotice("请求失败", "danger"); } }); }, getControlConfig(type, action) { if (type === "crn") { return { url: { transport: "/crn/command/take", move: "/crn/command/move", taskComplete: "/crn/command/taskComplete" }[action], payload: this.controlForms.crn }; } if (type === "dualCrn") { return { url: { transport: "/dualcrn/command/take", pickup: "/dualcrn/command/pick", putdown: "/dualcrn/command/put", move: "/dualcrn/command/move", taskComplete: "/dualcrn/command/taskComplete" }[action], payload: this.controlForms.dualCrn }; } if (type === "devp") { return { url: { move: "/station/command/move", reset: "/station/command/reset" }[action], payload: this.controlForms.devp }; } if (type === "rgv") { return { url: { transport: "/rgv/command/transport", move: "/rgv/command/move", taskComplete: "/rgv/command/taskComplete" }[action], payload: this.controlForms.rgv }; } return null; }, editBarcode() { const item = this.selectedItem; if (!item || item.stationId == null) { return; } const barcode = window.prompt("请输入新的条码值(可留空清空)", item.barcode || ""); if (barcode === null) { return; } $.ajax({ url: baseUrl + "/station/command/barcode", headers: { token: localStorage.getItem("token") }, contentType: "application/json", method: "post", data: JSON.stringify({ stationId: item.stationId, barcode: String(barcode).trim() }), success: (res) => { if (res && res.code === 200) { this.showNotice("条码修改成功", "success"); this.$emit("refresh-request", "devp"); } else { this.showNotice((res && res.msg) || "条码修改失败", "warning"); } }, error: () => { this.showNotice("条码修改失败", "danger"); } }); }, editDualTask(station) { const item = this.selectedItem; if (!item || item.crnNo == null) { return; } const currentValue = station === 1 ? item.taskNo : item.taskNoTwo; const value = window.prompt("请输入工位" + station + "任务号", currentValue == null ? "" : String(currentValue)); if (value === null) { return; } if (!/^\d+$/.test(String(value).trim())) { this.showNotice("任务号必须是非负整数", "warning"); return; } $.ajax({ url: baseUrl + "/dualcrn/command/updateTaskNo", headers: { token: localStorage.getItem("token") }, contentType: "application/json", method: "post", data: JSON.stringify({ crnNo: item.crnNo, station: station, taskNo: Number(value) }), success: (res) => { if (res && res.code === 200) { this.showNotice("任务号更新成功", "success"); this.$emit("refresh-request", "dualCrn"); } else { this.showNotice((res && res.msg) || "任务号更新失败", "warning"); } }, error: () => { this.showNotice("任务号更新失败", "danger"); } }); }, showNotice(message, type) { this.noticeMessage = message; this.noticeType = type || "info"; if (this.noticeTimer) { clearTimeout(this.noticeTimer); } this.noticeTimer = setTimeout(() => { this.noticeMessage = ""; this.noticeTimer = null; }, 2200); }, yesNo(value) { if (value === true || value === "Y" || value === "y" || value === 1 || value === "1") { return "Y"; } if (value === false || value === 0 || value === "0") { return "N"; } return value ? "Y" : "N"; }, orDash(value) { return value == null || value === "" ? "-" : String(value); }, orEmpty(value) { return value == null ? "" : String(value); } } });