| | |
| | | private static final int RUN_BLOCK_DIRECT_REASSIGN_NEAREST_CACHE_SECONDS = 60 * 60 * 24; |
| | | private static final long CHECK_STATION_OUT_ORDER_SLOW_THRESHOLD_MS = 200L; |
| | | private static final long EXECUTE_REROUTE_PLAN_SLOW_THRESHOLD_MS = 200L; |
| | | private static final String RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING_PREFIX = "堵塞重分配请求WMS失败"; |
| | | private static final String RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING = |
| | | RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING_PREFIX + ",请检查WMS重新分配库位接口"; |
| | | |
| | | @Autowired |
| | | private WrkMastService wrkMastService; |
| | |
| | | } |
| | | String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId()); |
| | | if (Cools.isEmpty(response)) { |
| | | appendStationSystemWarning(stationProtocol, RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING); |
| | | News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,接口未响应!!!response:{}", response); |
| | | return; |
| | | } |
| | | JSONObject jsonObject = JSON.parseObject(response); |
| | | if (!jsonObject.getInteger("code").equals(200)) { |
| | | News.error("请求WMS接口失败!!!response:{}", response); |
| | | JSONObject jsonObject; |
| | | try { |
| | | jsonObject = JSON.parseObject(response); |
| | | } catch (Exception e) { |
| | | appendStationSystemWarning(stationProtocol, RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING); |
| | | News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口响应解析异常!!!response:{}", response, e); |
| | | return; |
| | | } |
| | | if (jsonObject == null || !Integer.valueOf(200).equals(jsonObject.getInteger("code"))) { |
| | | appendStationSystemWarning(stationProtocol, RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING); |
| | | News.taskError(wrkMast.getWrkNo(), "请求WMS接口失败!!!response:{}", response); |
| | | return; |
| | | } |
| | | |
| | | StartupDto dto = jsonObject.getObject("data", StartupDto.class); |
| | | if (dto == null || Cools.isEmpty(dto.getLocNo())) { |
| | | appendStationSystemWarning(stationProtocol, RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING); |
| | | News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,WMS未返回目标库位!!!response:{}", response); |
| | | return; |
| | | } |
| | | clearStationSystemWarningByPrefix(stationProtocol, RUN_BLOCK_DIRECT_REASSIGN_WMS_WARNING_PREFIX); |
| | | String sourceLocNo = wrkMast.getLocNo(); |
| | | String locNo = dto.getLocNo(); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | private void appendStationSystemWarning(StationProtocol stationProtocol, String warning) { |
| | | if (stationProtocol == null || Cools.isEmpty(warning)) { |
| | | return; |
| | | } |
| | | String currentWarning = stationProtocol.getSystemWarning(); |
| | | if (Cools.isEmpty(currentWarning)) { |
| | | stationProtocol.setSystemWarning(warning); |
| | | return; |
| | | } |
| | | if (currentWarning.contains(warning)) { |
| | | return; |
| | | } |
| | | stationProtocol.setSystemWarning(currentWarning + ";" + warning); |
| | | } |
| | | |
| | | private void clearStationSystemWarningByPrefix(StationProtocol stationProtocol, String warningPrefix) { |
| | | if (stationProtocol == null || Cools.isEmpty(warningPrefix) || Cools.isEmpty(stationProtocol.getSystemWarning())) { |
| | | return; |
| | | } |
| | | String[] warningParts = stationProtocol.getSystemWarning().split(";"); |
| | | List<String> keepWarningList = new ArrayList<>(); |
| | | for (String warningPart : warningParts) { |
| | | if (Cools.isEmpty(warningPart) || warningPart.startsWith(warningPrefix)) { |
| | | continue; |
| | | } |
| | | keepWarningList.add(warningPart); |
| | | } |
| | | stationProtocol.setSystemWarning(String.join(";", keepWarningList)); |
| | | } |
| | | |
| | | private int countCurrentTaskBufferCommands(List<StationTaskBufferItem> taskBufferItems, Integer currentTaskNo) { |
| | | if (taskBufferItems == null || taskBufferItems.isEmpty() || currentTaskNo == null || currentTaskNo <= 0) { |
| | | return 0; |
| | |
| | | # 系统版本信息 |
| | | app: |
| | | version: 3.0.1.3 |
| | | version: 3.0.1.5 |
| | | version-type: prd # prd 或 dev |
| | | i18n: |
| | | default-locale: zh-CN |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 134, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | dialogForm: createFormDefaults(), |
| | | dialogDisplay: createDisplayDefaults(), |
| | | rowMapRows: [], |
| | | stationEditorFields: ['inStationList', 'outStationList'], |
| | | intArray2dFields: ['controlRows'], |
| | | intArrayFields: [], |
| | | jsonEditorRows: {}, |
| | | dialogRules: createFormRules() |
| | | }; |
| | | }, |
| | |
| | | this.dialogForm = createFormDefaults(); |
| | | this.dialogDisplay = createDisplayDefaults(); |
| | | this.rowMapRows = []; |
| | | this.jsonEditorRows = {}; |
| | | if (this.$refs.dialogForm) { |
| | | this.$refs.dialogForm.clearValidate(); |
| | | } |
| | |
| | | self.resetDialogState(); |
| | | fillFormFromRow(row, self.dialogForm, self.dialogDisplay); |
| | | self.rowMapRows = parseRowMapRows(self.dialogForm.rowMap); |
| | | self.initJsonEditorRows(); |
| | | if (self.$refs.dialogForm) { |
| | | self.$refs.dialogForm.clearValidate(); |
| | | } |
| | |
| | | syncRowMapJson: function () { |
| | | this.$set(this.dialogForm, 'rowMap', buildRowMapJson(this.rowMapRows)); |
| | | }, |
| | | initJsonEditorRows: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | self.$set(self.jsonEditorRows, field, editors.parseStationList(self.dialogForm[field])); |
| | | }); |
| | | self.intArray2dFields.forEach(function (field) { |
| | | self.$set(self.jsonEditorRows, field, editors.parseIntArray2D(self.dialogForm[field])); |
| | | }); |
| | | self.intArrayFields.forEach(function (field) { |
| | | self.$set(self.jsonEditorRows, field, editors.parseIntArray(self.dialogForm[field])); |
| | | }); |
| | | }, |
| | | syncAllJsonEditors: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | self.$set(self.dialogForm, field, editors.buildStationListJson(self.jsonEditorRows[field])); |
| | | }); |
| | | self.intArray2dFields.forEach(function (field) { |
| | | self.$set(self.dialogForm, field, editors.buildIntArray2DJson(self.jsonEditorRows[field])); |
| | | }); |
| | | self.intArrayFields.forEach(function (field) { |
| | | self.$set(self.dialogForm, field, editors.buildIntArrayJson(self.jsonEditorRows[field])); |
| | | }); |
| | | }, |
| | | validateAllJsonEditors: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | var error = ''; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | if (error) return; |
| | | error = editors.validateStationList(self.jsonEditorRows[field]); |
| | | }); |
| | | self.intArray2dFields.forEach(function (field) { |
| | | if (error) return; |
| | | error = editors.validateIntArray2D(self.jsonEditorRows[field]); |
| | | }); |
| | | self.intArrayFields.forEach(function (field) { |
| | | if (error) return; |
| | | error = editors.validateIntArray(self.jsonEditorRows[field]); |
| | | }); |
| | | return error; |
| | | }, |
| | | addStationRow: function (field) { |
| | | if (!this.jsonEditorRows[field]) { |
| | | this.$set(this.jsonEditorRows, field, []); |
| | | } |
| | | this.jsonEditorRows[field].push(window.WcsJsonEditors.createEmptyStation()); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeStationRow: function (field, index) { |
| | | this.jsonEditorRows[field].splice(index, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | toggleNested: function (field, rowIndex, nestedKey) { |
| | | var row = this.jsonEditorRows[field][rowIndex]; |
| | | var showKey = '_show' + nestedKey.charAt(0).toUpperCase() + nestedKey.slice(1); |
| | | this.$set(row, showKey, !row[showKey]); |
| | | }, |
| | | addNestedStation: function (field, rowIndex, nestedKey) { |
| | | var row = this.jsonEditorRows[field][rowIndex]; |
| | | var nested = {}; |
| | | window.WcsJsonEditors.STATION_OBJ_FIELDS.forEach(function (k) { nested[k] = ''; }); |
| | | this.$set(row, nestedKey, nested); |
| | | var showKey = '_show' + nestedKey.charAt(0).toUpperCase() + nestedKey.slice(1); |
| | | this.$set(row, showKey, true); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeNestedStation: function (field, rowIndex, nestedKey) { |
| | | this.$set(this.jsonEditorRows[field][rowIndex], nestedKey, null); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | syncStationField: function (field) { |
| | | this.$set(this.dialogForm, field, window.WcsJsonEditors.buildStationListJson(this.jsonEditorRows[field])); |
| | | }, |
| | | addIntArray2DGroup: function (field) { |
| | | if (!this.jsonEditorRows[field]) { |
| | | this.$set(this.jsonEditorRows, field, []); |
| | | } |
| | | this.jsonEditorRows[field].push({ values: [''] }); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeIntArray2DGroup: function (field, index) { |
| | | this.jsonEditorRows[field].splice(index, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | addIntArray2DValue: function (field, groupIndex) { |
| | | this.jsonEditorRows[field][groupIndex].values.push(''); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeIntArray2DValue: function (field, groupIndex, valueIndex) { |
| | | this.jsonEditorRows[field][groupIndex].values.splice(valueIndex, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | syncIntArray2DField: function (field) { |
| | | this.$set(this.dialogForm, field, window.WcsJsonEditors.buildIntArray2DJson(this.jsonEditorRows[field])); |
| | | }, |
| | | addIntArrayValue: function (field) { |
| | | if (!this.jsonEditorRows[field]) { |
| | | this.$set(this.jsonEditorRows, field, []); |
| | | } |
| | | this.jsonEditorRows[field].push(''); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeIntArrayValue: function (field, index) { |
| | | this.jsonEditorRows[field].splice(index, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | syncIntArrayField: function (field) { |
| | | this.$set(this.dialogForm, field, window.WcsJsonEditors.buildIntArrayJson(this.jsonEditorRows[field])); |
| | | }, |
| | | submitDialog: function () { |
| | | var self = this; |
| | | if (!self.$refs.dialogForm) { |
| | |
| | | self.$message.warning(rowMapMessage); |
| | | return; |
| | | } |
| | | self.syncAllJsonEditors(); |
| | | var jsonError = self.validateAllJsonEditors(); |
| | | if (jsonError) { |
| | | self.$message.warning(jsonError); |
| | | return; |
| | | } |
| | | self.$refs.dialogForm.validate(function (valid) { |
| | | if (!valid) { |
| | | return false; |
| | |
| | | tableResizeHandler: null, |
| | | dialogForm: createFormDefaults(), |
| | | dialogDisplay: createDisplayDefaults(), |
| | | stationEditorFields: ['stationList', 'barcodeStationList', 'inStationList', 'outStationList', 'runBlockReassignLocStationList', 'isOutOrderList', 'isLiftTransferList'], |
| | | jsonEditorRows: {}, |
| | | dialogRules: createFormRules() |
| | | }; |
| | | }, |
| | |
| | | resetDialogState: function () { |
| | | this.dialogForm = createFormDefaults(); |
| | | this.dialogDisplay = createDisplayDefaults(); |
| | | this.jsonEditorRows = {}; |
| | | if (this.$refs.dialogForm) { |
| | | this.$refs.dialogForm.clearValidate(); |
| | | } |
| | |
| | | self.$nextTick(function () { |
| | | self.resetDialogState(); |
| | | fillFormFromRow(row, self.dialogForm, self.dialogDisplay); |
| | | self.initJsonEditorRows(); |
| | | if (self.$refs.dialogForm) { |
| | | self.$refs.dialogForm.clearValidate(); |
| | | } |
| | |
| | | submitDialog: function () { |
| | | var self = this; |
| | | if (!self.$refs.dialogForm) { |
| | | return; |
| | | } |
| | | self.syncAllJsonEditors(); |
| | | var jsonError = self.validateAllJsonEditors(); |
| | | if (jsonError) { |
| | | self.$message.warning(jsonError); |
| | | return; |
| | | } |
| | | self.$refs.dialogForm.validate(function (valid) { |
| | |
| | | return true; |
| | | }); |
| | | }, |
| | | initJsonEditorRows: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | self.$set(self.jsonEditorRows, field, editors.parseStationList(self.dialogForm[field])); |
| | | }); |
| | | }, |
| | | syncAllJsonEditors: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | self.$set(self.dialogForm, field, editors.buildStationListJson(self.jsonEditorRows[field])); |
| | | }); |
| | | }, |
| | | validateAllJsonEditors: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | var error = ''; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | if (error) return; |
| | | error = editors.validateStationList(self.jsonEditorRows[field]); |
| | | }); |
| | | return error; |
| | | }, |
| | | addStationRow: function (field) { |
| | | if (!this.jsonEditorRows[field]) { |
| | | this.$set(this.jsonEditorRows, field, []); |
| | | } |
| | | this.jsonEditorRows[field].push(window.WcsJsonEditors.createEmptyStation()); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeStationRow: function (field, index) { |
| | | this.jsonEditorRows[field].splice(index, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | toggleNested: function (field, rowIndex, nestedKey) { |
| | | var row = this.jsonEditorRows[field][rowIndex]; |
| | | var showKey = '_show' + nestedKey.charAt(0).toUpperCase() + nestedKey.slice(1); |
| | | this.$set(row, showKey, !row[showKey]); |
| | | }, |
| | | addNestedStation: function (field, rowIndex, nestedKey) { |
| | | var row = this.jsonEditorRows[field][rowIndex]; |
| | | var nested = {}; |
| | | window.WcsJsonEditors.STATION_OBJ_FIELDS.forEach(function (k) { nested[k] = ''; }); |
| | | this.$set(row, nestedKey, nested); |
| | | var showKey = '_show' + nestedKey.charAt(0).toUpperCase() + nestedKey.slice(1); |
| | | this.$set(row, showKey, true); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeNestedStation: function (field, rowIndex, nestedKey) { |
| | | this.$set(this.jsonEditorRows[field][rowIndex], nestedKey, null); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | syncStationField: function (field) { |
| | | this.$set(this.dialogForm, field, window.WcsJsonEditors.buildStationListJson(this.jsonEditorRows[field])); |
| | | }, |
| | | removeSelection: function () { |
| | | var self = this; |
| | | var ids = self.selection.map(function (row) { |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 134, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 116, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 170, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | textarea: true, |
| | | minWidth: 170, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | |
| | | tableResizeHandler: null, |
| | | dialogForm: createFormDefaults(), |
| | | dialogDisplay: createDisplayDefaults(), |
| | | stationEditorFields: ['inStationList', 'outStationList'], |
| | | intArray2dFields: ['controlRows'], |
| | | intArrayFields: ['disableStationOneBays', 'disableStationTwoBays', 'deepRows'], |
| | | jsonEditorRows: {}, |
| | | dialogRules: createFormRules() |
| | | }; |
| | | }, |
| | |
| | | resetDialogState: function () { |
| | | this.dialogForm = createFormDefaults(); |
| | | this.dialogDisplay = createDisplayDefaults(); |
| | | this.jsonEditorRows = {}; |
| | | if (this.$refs.dialogForm) { |
| | | this.$refs.dialogForm.clearValidate(); |
| | | } |
| | |
| | | self.$nextTick(function () { |
| | | self.resetDialogState(); |
| | | fillFormFromRow(row, self.dialogForm, self.dialogDisplay); |
| | | self.initJsonEditorRows(); |
| | | if (self.$refs.dialogForm) { |
| | | self.$refs.dialogForm.clearValidate(); |
| | | } |
| | |
| | | submitDialog: function () { |
| | | var self = this; |
| | | if (!self.$refs.dialogForm) { |
| | | return; |
| | | } |
| | | self.syncAllJsonEditors(); |
| | | var jsonError = self.validateAllJsonEditors(); |
| | | if (jsonError) { |
| | | self.$message.warning(jsonError); |
| | | return; |
| | | } |
| | | self.$refs.dialogForm.validate(function (valid) { |
| | |
| | | return true; |
| | | }); |
| | | }, |
| | | initJsonEditorRows: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | self.$set(self.jsonEditorRows, field, editors.parseStationList(self.dialogForm[field])); |
| | | }); |
| | | self.intArray2dFields.forEach(function (field) { |
| | | self.$set(self.jsonEditorRows, field, editors.parseIntArray2D(self.dialogForm[field])); |
| | | }); |
| | | self.intArrayFields.forEach(function (field) { |
| | | self.$set(self.jsonEditorRows, field, editors.parseIntArray(self.dialogForm[field])); |
| | | }); |
| | | }, |
| | | syncAllJsonEditors: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | self.$set(self.dialogForm, field, editors.buildStationListJson(self.jsonEditorRows[field])); |
| | | }); |
| | | self.intArray2dFields.forEach(function (field) { |
| | | self.$set(self.dialogForm, field, editors.buildIntArray2DJson(self.jsonEditorRows[field])); |
| | | }); |
| | | self.intArrayFields.forEach(function (field) { |
| | | self.$set(self.dialogForm, field, editors.buildIntArrayJson(self.jsonEditorRows[field])); |
| | | }); |
| | | }, |
| | | validateAllJsonEditors: function () { |
| | | var self = this; |
| | | var editors = window.WcsJsonEditors; |
| | | var error = ''; |
| | | self.stationEditorFields.forEach(function (field) { |
| | | if (error) return; |
| | | error = editors.validateStationList(self.jsonEditorRows[field]); |
| | | }); |
| | | self.intArray2dFields.forEach(function (field) { |
| | | if (error) return; |
| | | error = editors.validateIntArray2D(self.jsonEditorRows[field]); |
| | | }); |
| | | self.intArrayFields.forEach(function (field) { |
| | | if (error) return; |
| | | error = editors.validateIntArray(self.jsonEditorRows[field]); |
| | | }); |
| | | return error; |
| | | }, |
| | | addStationRow: function (field) { |
| | | if (!this.jsonEditorRows[field]) { |
| | | this.$set(this.jsonEditorRows, field, []); |
| | | } |
| | | this.jsonEditorRows[field].push(window.WcsJsonEditors.createEmptyStation()); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeStationRow: function (field, index) { |
| | | this.jsonEditorRows[field].splice(index, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | toggleNested: function (field, rowIndex, nestedKey) { |
| | | var row = this.jsonEditorRows[field][rowIndex]; |
| | | var showKey = '_show' + nestedKey.charAt(0).toUpperCase() + nestedKey.slice(1); |
| | | this.$set(row, showKey, !row[showKey]); |
| | | }, |
| | | addNestedStation: function (field, rowIndex, nestedKey) { |
| | | var row = this.jsonEditorRows[field][rowIndex]; |
| | | var nested = {}; |
| | | window.WcsJsonEditors.STATION_OBJ_FIELDS.forEach(function (k) { nested[k] = ''; }); |
| | | this.$set(row, nestedKey, nested); |
| | | var showKey = '_show' + nestedKey.charAt(0).toUpperCase() + nestedKey.slice(1); |
| | | this.$set(row, showKey, true); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeNestedStation: function (field, rowIndex, nestedKey) { |
| | | this.$set(this.jsonEditorRows[field][rowIndex], nestedKey, null); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | syncStationField: function (field) { |
| | | this.$set(this.dialogForm, field, window.WcsJsonEditors.buildStationListJson(this.jsonEditorRows[field])); |
| | | }, |
| | | addIntArray2DGroup: function (field) { |
| | | if (!this.jsonEditorRows[field]) { |
| | | this.$set(this.jsonEditorRows, field, []); |
| | | } |
| | | this.jsonEditorRows[field].push({ values: [''] }); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeIntArray2DGroup: function (field, index) { |
| | | this.jsonEditorRows[field].splice(index, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | addIntArray2DValue: function (field, groupIndex) { |
| | | this.jsonEditorRows[field][groupIndex].values.push(''); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeIntArray2DValue: function (field, groupIndex, valueIndex) { |
| | | this.jsonEditorRows[field][groupIndex].values.splice(valueIndex, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | syncIntArray2DField: function (field) { |
| | | this.$set(this.dialogForm, field, window.WcsJsonEditors.buildIntArray2DJson(this.jsonEditorRows[field])); |
| | | }, |
| | | addIntArrayValue: function (field) { |
| | | if (!this.jsonEditorRows[field]) { |
| | | this.$set(this.jsonEditorRows, field, []); |
| | | } |
| | | this.jsonEditorRows[field].push(''); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | removeIntArrayValue: function (field, index) { |
| | | this.jsonEditorRows[field].splice(index, 1); |
| | | this.syncAllJsonEditors(); |
| | | }, |
| | | syncIntArrayField: function (field) { |
| | | this.$set(this.dialogForm, field, window.WcsJsonEditors.buildIntArrayJson(this.jsonEditorRows[field])); |
| | | }, |
| | | removeSelection: function () { |
| | | var self = this; |
| | | var ids = self.selection.map(function (row) { |
| New file |
| | |
| | | /** |
| | | * WCS JSON 可视化编辑器 - 共享工具函数 |
| | | * 用于 basCrnp、basDevp、basDualCrnp 页面的 JSON 字段编辑 |
| | | */ |
| | | (function () { |
| | | 'use strict'; |
| | | |
| | | var STATION_OBJ_FIELDS = [ |
| | | 'deviceNo', 'stationId', 'deviceRow', 'deviceBay', |
| | | 'deviceLev', 'stationLev', 'barcodeIdx', 'dualCrnExecuteStation' |
| | | ]; |
| | | |
| | | // ========== StationObjModel 数组 ========== |
| | | |
| | | function createEmptyStation() { |
| | | return { |
| | | deviceNo: '', stationId: '', deviceRow: '', deviceBay: '', |
| | | deviceLev: '', stationLev: '', barcodeIdx: '', dualCrnExecuteStation: '', |
| | | barcodeStation: null, |
| | | backStation: null, |
| | | _showBarcode: false, |
| | | _showBack: false |
| | | }; |
| | | } |
| | | |
| | | function stationObjToRow(obj) { |
| | | var row = createEmptyStation(); |
| | | STATION_OBJ_FIELDS.forEach(function (key) { |
| | | if (obj[key] !== null && obj[key] !== undefined) { |
| | | row[key] = String(obj[key]); |
| | | } |
| | | }); |
| | | if (obj.barcodeStation && typeof obj.barcodeStation === 'object') { |
| | | row.barcodeStation = {}; |
| | | STATION_OBJ_FIELDS.forEach(function (key) { |
| | | row.barcodeStation[key] = (obj.barcodeStation[key] !== null && obj.barcodeStation[key] !== undefined) |
| | | ? String(obj.barcodeStation[key]) : ''; |
| | | }); |
| | | row._showBarcode = false; |
| | | } |
| | | if (obj.backStation && typeof obj.backStation === 'object') { |
| | | row.backStation = {}; |
| | | STATION_OBJ_FIELDS.forEach(function (key) { |
| | | row.backStation[key] = (obj.backStation[key] !== null && obj.backStation[key] !== undefined) |
| | | ? String(obj.backStation[key]) : ''; |
| | | }); |
| | | row._showBack = false; |
| | | } |
| | | return row; |
| | | } |
| | | |
| | | function parseStationList(jsonText) { |
| | | if (!jsonText || typeof jsonText !== 'string' || !jsonText.trim()) { |
| | | return []; |
| | | } |
| | | try { |
| | | var arr = JSON.parse(jsonText); |
| | | if (!Array.isArray(arr)) return []; |
| | | return arr.map(function (item) { |
| | | return stationObjToRow(item); |
| | | }); |
| | | } catch (e) { |
| | | return []; |
| | | } |
| | | } |
| | | |
| | | function buildStationObj(row) { |
| | | var obj = {}; |
| | | var hasValue = false; |
| | | STATION_OBJ_FIELDS.forEach(function (key) { |
| | | var val = row[key] ? String(row[key]).trim() : ''; |
| | | if (val !== '') { |
| | | obj[key] = Number(val); |
| | | hasValue = true; |
| | | } else { |
| | | obj[key] = null; |
| | | } |
| | | }); |
| | | if (row.barcodeStation && typeof row.barcodeStation === 'object') { |
| | | var bs = {}; |
| | | var bsHasValue = false; |
| | | STATION_OBJ_FIELDS.forEach(function (key) { |
| | | var val = row.barcodeStation[key] ? String(row.barcodeStation[key]).trim() : ''; |
| | | if (val !== '') { |
| | | bs[key] = Number(val); |
| | | bsHasValue = true; |
| | | } else { |
| | | bs[key] = null; |
| | | } |
| | | }); |
| | | obj.barcodeStation = bsHasValue ? bs : null; |
| | | } else { |
| | | obj.barcodeStation = null; |
| | | } |
| | | if (row.backStation && typeof row.backStation === 'object') { |
| | | var bk = {}; |
| | | var bkHasValue = false; |
| | | STATION_OBJ_FIELDS.forEach(function (key) { |
| | | var val = row.backStation[key] ? String(row.backStation[key]).trim() : ''; |
| | | if (val !== '') { |
| | | bk[key] = Number(val); |
| | | bkHasValue = true; |
| | | } else { |
| | | bk[key] = null; |
| | | } |
| | | }); |
| | | obj.backStation = bkHasValue ? bk : null; |
| | | } else { |
| | | obj.backStation = null; |
| | | } |
| | | return hasValue ? obj : null; |
| | | } |
| | | |
| | | function buildStationListJson(rows) { |
| | | if (!rows || !rows.length) return ''; |
| | | var result = []; |
| | | rows.forEach(function (row) { |
| | | var obj = buildStationObj(row); |
| | | if (obj) result.push(obj); |
| | | }); |
| | | return result.length > 0 ? JSON.stringify(result) : ''; |
| | | } |
| | | |
| | | function validateStationList(rows) { |
| | | if (!rows || !rows.length) return ''; |
| | | for (var i = 0; i < rows.length; i++) { |
| | | var row = rows[i]; |
| | | var hasAny = false; |
| | | STATION_OBJ_FIELDS.forEach(function (key) { |
| | | if (row[key] && String(row[key]).trim()) hasAny = true; |
| | | }); |
| | | if (!hasAny) continue; |
| | | if (!row.deviceNo || !String(row.deviceNo).trim()) { |
| | | return '第' + (i + 1) + '个站点:设备号不能为空'; |
| | | } |
| | | if (!row.stationId || !String(row.stationId).trim()) { |
| | | return '第' + (i + 1) + '个站点:站点ID不能为空'; |
| | | } |
| | | for (var j = 0; j < STATION_OBJ_FIELDS.length; j++) { |
| | | var key = STATION_OBJ_FIELDS[j]; |
| | | var val = row[key] ? String(row[key]).trim() : ''; |
| | | if (val !== '' && !/^-?\d+$/.test(val)) { |
| | | return '第' + (i + 1) + '个站点:' + key + ' 必须为整数'; |
| | | } |
| | | } |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | // ========== 二维整数数组 ========== |
| | | |
| | | function parseIntArray2D(jsonText) { |
| | | if (!jsonText || typeof jsonText !== 'string' || !jsonText.trim()) { |
| | | return []; |
| | | } |
| | | try { |
| | | var arr = JSON.parse(jsonText); |
| | | if (!Array.isArray(arr)) return []; |
| | | return arr.map(function (group) { |
| | | if (!Array.isArray(group)) return { values: [] }; |
| | | return { |
| | | values: group.map(function (v) { return String(v); }) |
| | | }; |
| | | }); |
| | | } catch (e) { |
| | | return []; |
| | | } |
| | | } |
| | | |
| | | function buildIntArray2DJson(rows) { |
| | | if (!rows || !rows.length) return ''; |
| | | var result = []; |
| | | rows.forEach(function (group) { |
| | | if (!group.values || !group.values.length) return; |
| | | var nums = []; |
| | | group.values.forEach(function (v) { |
| | | var trimmed = v ? String(v).trim() : ''; |
| | | if (trimmed !== '') nums.push(Number(trimmed)); |
| | | }); |
| | | if (nums.length > 0) result.push(nums); |
| | | }); |
| | | return result.length > 0 ? JSON.stringify(result) : ''; |
| | | } |
| | | |
| | | function validateIntArray2D(rows) { |
| | | if (!rows || !rows.length) return ''; |
| | | for (var i = 0; i < rows.length; i++) { |
| | | var group = rows[i]; |
| | | if (!group.values) continue; |
| | | for (var j = 0; j < group.values.length; j++) { |
| | | var val = group.values[j] ? String(group.values[j]).trim() : ''; |
| | | if (val !== '' && !/^-?\d+$/.test(val)) { |
| | | return '第' + (i + 1) + '组第' + (j + 1) + '个值必须为整数'; |
| | | } |
| | | } |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | // ========== 整数数组 ========== |
| | | |
| | | function parseIntArray(jsonText) { |
| | | if (!jsonText || typeof jsonText !== 'string' || !jsonText.trim()) { |
| | | return []; |
| | | } |
| | | try { |
| | | var arr = JSON.parse(jsonText); |
| | | if (!Array.isArray(arr)) return []; |
| | | return arr.map(function (v) { return String(v); }); |
| | | } catch (e) { |
| | | return []; |
| | | } |
| | | } |
| | | |
| | | function buildIntArrayJson(rows) { |
| | | if (!rows || !rows.length) return ''; |
| | | var result = []; |
| | | rows.forEach(function (v) { |
| | | var trimmed = v ? String(v).trim() : ''; |
| | | if (trimmed !== '') result.push(Number(trimmed)); |
| | | }); |
| | | return result.length > 0 ? JSON.stringify(result) : ''; |
| | | } |
| | | |
| | | function validateIntArray(rows) { |
| | | if (!rows || !rows.length) return ''; |
| | | for (var i = 0; i < rows.length; i++) { |
| | | var val = rows[i] ? String(rows[i]).trim() : ''; |
| | | if (val !== '' && !/^-?\d+$/.test(val)) { |
| | | return '第' + (i + 1) + '个值必须为整数'; |
| | | } |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | // ========== 暴露全局对象 ========== |
| | | |
| | | window.WcsJsonEditors = { |
| | | STATION_OBJ_FIELDS: STATION_OBJ_FIELDS, |
| | | createEmptyStation: createEmptyStation, |
| | | parseStationList: parseStationList, |
| | | buildStationListJson: buildStationListJson, |
| | | validateStationList: validateStationList, |
| | | parseIntArray2D: parseIntArray2D, |
| | | buildIntArray2DJson: buildIntArray2DJson, |
| | | validateIntArray2D: validateIntArray2D, |
| | | parseIntArray: parseIntArray, |
| | | buildIntArrayJson: buildIntArrayJson, |
| | | validateIntArray: validateIntArray |
| | | }; |
| | | |
| | | })(); |
| | |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .station-list-editor, |
| | | .int-array2d-editor, |
| | | .int-array-editor { |
| | | padding: 10px 12px; |
| | | border: 1px solid #dfe7f1; |
| | | border-radius: 10px; |
| | | background: #f8fbff; |
| | | max-height: 400px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .station-list-editor-row { |
| | | padding: 10px; |
| | | border: 1px solid #e8eef5; |
| | | border-radius: 8px; |
| | | background: #fff; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .station-list-editor-row-head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | } |
| | | |
| | | .station-fields-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(4, 1fr); |
| | | gap: 6px; |
| | | } |
| | | |
| | | .station-fields-grid label { |
| | | display: block; |
| | | font-size: 11px; |
| | | color: #66788f; |
| | | margin-bottom: 2px; |
| | | } |
| | | |
| | | .station-fields-grid .el-input__inner { |
| | | height: 28px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .nested-section { |
| | | margin-top: 8px; |
| | | padding: 8px; |
| | | border: 1px dashed #d0dbe8; |
| | | border-radius: 6px; |
| | | background: #f5f8fc; |
| | | } |
| | | |
| | | .nested-section-head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 6px; |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | } |
| | | |
| | | .json-editor-footer { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .json-preview { |
| | | min-width: 0; |
| | | color: #8a98ac; |
| | | font-size: 12px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | font-family: Menlo, Monaco, Consolas, monospace; |
| | | max-width: 400px; |
| | | } |
| | | |
| | | .int-array2d-group { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | margin-bottom: 8px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .int-array2d-group-label { |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | min-width: 36px; |
| | | } |
| | | |
| | | .int-array2d-values { |
| | | display: flex; |
| | | gap: 6px; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | } |
| | | |
| | | .int-array2d-values .el-input { |
| | | width: 70px; |
| | | } |
| | | |
| | | .int-array2d-values .el-input__inner { |
| | | height: 28px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .int-array-items { |
| | | display: flex; |
| | | gap: 8px; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | } |
| | | |
| | | .int-array-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .int-array-item .el-input { |
| | | width: 80px; |
| | | } |
| | | |
| | | .int-array-item .el-input__inner { |
| | | height: 28px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .pager-bar { |
| | | padding: 0 16px 16px; |
| | | display: flex; |
| | |
| | | <span class="row-map-json-preview mono" :title="dialogForm.rowMap">{{ dialogForm.rowMap || '未配置时使用库位排原值' }}</span> |
| | | </div> |
| | | </div> |
| | | <!-- StationObjModel 数组编辑器 --> |
| | | <div |
| | | v-else-if="stationEditorFields.indexOf(field.field) !== -1" |
| | | class="station-list-editor"> |
| | | <div |
| | | v-for="(station, sIdx) in jsonEditorRows[field.field] || []" |
| | | :key="field.field + '-station-' + sIdx" |
| | | class="station-list-editor-row"> |
| | | <div class="station-list-editor-row-head"> |
| | | <span>站点 {{ sIdx + 1 }}</span> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeStationRow(field.field, sIdx)">删除</el-button> |
| | | </div> |
| | | <div class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.deviceNo" placeholder="如 1" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.stationId" placeholder="如 11" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.deviceRow" placeholder="排" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.deviceBay" placeholder="列" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.deviceLev" placeholder="层" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.stationLev" placeholder="站点层" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.barcodeIdx" placeholder="条码索引" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.dualCrnExecuteStation" placeholder="双工位工位" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | <!-- 条码站点 --> |
| | | <div class="nested-section"> |
| | | <div class="nested-section-head"> |
| | | <span>条码站点 {{ station.barcodeStation ? '(已配置)' : '' }}</span> |
| | | <span> |
| | | <el-button v-if="!station.barcodeStation" type="text" size="mini" @click="addNestedStation(field.field, sIdx, 'barcodeStation')">添加</el-button> |
| | | <el-button v-if="station.barcodeStation" type="text" size="mini" @click="toggleNested(field.field, sIdx, 'barcodeStation')">{{ station._showBarcode ? '收起' : '展开' }}</el-button> |
| | | <el-button v-if="station.barcodeStation" type="text" size="mini" style="color:#f56c6c;" @click="removeNestedStation(field.field, sIdx, 'barcodeStation')">移除</el-button> |
| | | </span> |
| | | </div> |
| | | <div v-if="station.barcodeStation && station._showBarcode" class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.barcodeStation.deviceNo" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.barcodeStation.stationId" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.barcodeStation.deviceRow" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.barcodeStation.deviceBay" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.barcodeStation.deviceLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.barcodeStation.stationLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.barcodeStation.barcodeIdx" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.barcodeStation.dualCrnExecuteStation" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | </div> |
| | | <!-- 回库站点 --> |
| | | <div class="nested-section"> |
| | | <div class="nested-section-head"> |
| | | <span>回库站点 {{ station.backStation ? '(已配置)' : '' }}</span> |
| | | <span> |
| | | <el-button v-if="!station.backStation" type="text" size="mini" @click="addNestedStation(field.field, sIdx, 'backStation')">添加</el-button> |
| | | <el-button v-if="station.backStation" type="text" size="mini" @click="toggleNested(field.field, sIdx, 'backStation')">{{ station._showBack ? '收起' : '展开' }}</el-button> |
| | | <el-button v-if="station.backStation" type="text" size="mini" style="color:#f56c6c;" @click="removeNestedStation(field.field, sIdx, 'backStation')">移除</el-button> |
| | | </span> |
| | | </div> |
| | | <div v-if="station.backStation && station._showBack" class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.backStation.deviceNo" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.backStation.stationId" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.backStation.deviceRow" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.backStation.deviceBay" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.backStation.deviceLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.backStation.stationLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.backStation.barcodeIdx" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.backStation.dualCrnExecuteStation" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="json-editor-footer"> |
| | | <el-button size="mini" plain icon="el-icon-plus" @click="addStationRow(field.field)">新增站点</el-button> |
| | | <span class="json-preview mono" :title="dialogForm[field.field]">{{ dialogForm[field.field] || '空' }}</span> |
| | | </div> |
| | | </div> |
| | | <!-- 二维整数数组编辑器 --> |
| | | <div |
| | | v-else-if="intArray2dFields.indexOf(field.field) !== -1" |
| | | class="int-array2d-editor"> |
| | | <div |
| | | v-for="(group, gIdx) in jsonEditorRows[field.field] || []" |
| | | :key="field.field + '-group-' + gIdx" |
| | | class="int-array2d-group"> |
| | | <span class="int-array2d-group-label">组 {{ gIdx + 1 }}</span> |
| | | <div class="int-array2d-values"> |
| | | <el-input |
| | | v-for="(val, vIdx) in group.values" |
| | | :key="field.field + '-g' + gIdx + '-v' + vIdx" |
| | | v-model.trim="group.values[vIdx]" |
| | | placeholder="值" |
| | | @input="syncIntArray2DField(field.field)"> |
| | | </el-input> |
| | | <el-button type="text" icon="el-icon-plus" @click="addIntArray2DValue(field.field, gIdx)"></el-button> |
| | | </div> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeIntArray2DGroup(field.field, gIdx)">删除组</el-button> |
| | | </div> |
| | | <div class="json-editor-footer"> |
| | | <el-button size="mini" plain icon="el-icon-plus" @click="addIntArray2DGroup(field.field)">新增组</el-button> |
| | | <span class="json-preview mono" :title="dialogForm[field.field]">{{ dialogForm[field.field] || '空' }}</span> |
| | | </div> |
| | | </div> |
| | | <!-- 整数数组编辑器 --> |
| | | <div |
| | | v-else-if="intArrayFields.indexOf(field.field) !== -1" |
| | | class="int-array-editor"> |
| | | <div class="int-array-items"> |
| | | <div |
| | | v-for="(val, idx) in jsonEditorRows[field.field] || []" |
| | | :key="field.field + '-item-' + idx" |
| | | class="int-array-item"> |
| | | <el-input |
| | | v-model.trim="jsonEditorRows[field.field][idx]" |
| | | placeholder="值" |
| | | @input="syncIntArrayField(field.field)"> |
| | | </el-input> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeIntArrayValue(field.field, idx)">删除</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="json-editor-footer"> |
| | | <el-button size="mini" plain icon="el-icon-plus" @click="addIntArrayValue(field.field)">新增</el-button> |
| | | <span class="json-preview mono" :title="dialogForm[field.field]">{{ dialogForm[field.field] || '空' }}</span> |
| | | </div> |
| | | </div> |
| | | <el-input |
| | | v-else-if="field.textarea" |
| | | v-model.trim="dialogForm[field.field]" |
| | |
| | | |
| | | <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/js/jsonEditors.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/vue/js/vue.min.js"></script> |
| | | <script type="text/javascript" src="../../static/vue/element/element.js"></script> |
| | | <script type="text/javascript" src="../../static/js/basCrnp/basCrnp.js?v=20260310" charset="utf-8"></script> |
| | |
| | | font-family: Menlo, Monaco, Consolas, "Liberation Mono", monospace; |
| | | } |
| | | |
| | | .station-list-editor { |
| | | padding: 10px 12px; |
| | | border: 1px solid #dfe7f1; |
| | | border-radius: 10px; |
| | | background: #f8fbff; |
| | | max-height: 400px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .station-list-editor-row { |
| | | padding: 10px; |
| | | border: 1px solid #e8eef5; |
| | | border-radius: 8px; |
| | | background: #fff; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .station-list-editor-row-head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | } |
| | | |
| | | .station-fields-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(4, 1fr); |
| | | gap: 6px; |
| | | } |
| | | |
| | | .station-fields-grid label { |
| | | display: block; |
| | | font-size: 11px; |
| | | color: #66788f; |
| | | margin-bottom: 2px; |
| | | } |
| | | |
| | | .station-fields-grid .el-input__inner { |
| | | height: 28px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .nested-section { |
| | | margin-top: 8px; |
| | | padding: 8px; |
| | | border: 1px dashed #d0dbe8; |
| | | border-radius: 6px; |
| | | background: #f5f8fc; |
| | | } |
| | | |
| | | .nested-section-head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 6px; |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | } |
| | | |
| | | .json-editor-footer { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .json-preview { |
| | | min-width: 0; |
| | | color: #8a98ac; |
| | | font-size: 12px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | font-family: Menlo, Monaco, Consolas, monospace; |
| | | max-width: 400px; |
| | | } |
| | | |
| | | .pager-bar { |
| | | padding: 0 16px 16px; |
| | | display: flex; |
| | |
| | | active-color="#13ce66" |
| | | inactive-color="#c0c4cc"> |
| | | </el-switch> |
| | | <!-- StationObjModel 数组编辑器 --> |
| | | <div |
| | | v-else-if="stationEditorFields.indexOf(field.field) !== -1" |
| | | class="station-list-editor"> |
| | | <div |
| | | v-for="(station, sIdx) in jsonEditorRows[field.field] || []" |
| | | :key="field.field + '-station-' + sIdx" |
| | | class="station-list-editor-row"> |
| | | <div class="station-list-editor-row-head"> |
| | | <span>站点 {{ sIdx + 1 }}</span> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeStationRow(field.field, sIdx)">删除</el-button> |
| | | </div> |
| | | <div class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.deviceNo" placeholder="如 1" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.stationId" placeholder="如 11" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.deviceRow" placeholder="排" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.deviceBay" placeholder="列" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.deviceLev" placeholder="层" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.stationLev" placeholder="站点层" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.barcodeIdx" placeholder="条码索引" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.dualCrnExecuteStation" placeholder="双工位工位" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | <!-- 条码站点 --> |
| | | <div class="nested-section"> |
| | | <div class="nested-section-head"> |
| | | <span>条码站点 {{ station.barcodeStation ? '(已配置)' : '' }}</span> |
| | | <span> |
| | | <el-button v-if="!station.barcodeStation" type="text" size="mini" @click="addNestedStation(field.field, sIdx, 'barcodeStation')">添加</el-button> |
| | | <el-button v-if="station.barcodeStation" type="text" size="mini" @click="toggleNested(field.field, sIdx, 'barcodeStation')">{{ station._showBarcode ? '收起' : '展开' }}</el-button> |
| | | <el-button v-if="station.barcodeStation" type="text" size="mini" style="color:#f56c6c;" @click="removeNestedStation(field.field, sIdx, 'barcodeStation')">移除</el-button> |
| | | </span> |
| | | </div> |
| | | <div v-if="station.barcodeStation && station._showBarcode" class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.barcodeStation.deviceNo" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.barcodeStation.stationId" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.barcodeStation.deviceRow" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.barcodeStation.deviceBay" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.barcodeStation.deviceLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.barcodeStation.stationLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.barcodeStation.barcodeIdx" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.barcodeStation.dualCrnExecuteStation" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | </div> |
| | | <!-- 回库站点 --> |
| | | <div class="nested-section"> |
| | | <div class="nested-section-head"> |
| | | <span>回库站点 {{ station.backStation ? '(已配置)' : '' }}</span> |
| | | <span> |
| | | <el-button v-if="!station.backStation" type="text" size="mini" @click="addNestedStation(field.field, sIdx, 'backStation')">添加</el-button> |
| | | <el-button v-if="station.backStation" type="text" size="mini" @click="toggleNested(field.field, sIdx, 'backStation')">{{ station._showBack ? '收起' : '展开' }}</el-button> |
| | | <el-button v-if="station.backStation" type="text" size="mini" style="color:#f56c6c;" @click="removeNestedStation(field.field, sIdx, 'backStation')">移除</el-button> |
| | | </span> |
| | | </div> |
| | | <div v-if="station.backStation && station._showBack" class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.backStation.deviceNo" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.backStation.stationId" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.backStation.deviceRow" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.backStation.deviceBay" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.backStation.deviceLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.backStation.stationLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.backStation.barcodeIdx" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.backStation.dualCrnExecuteStation" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="json-editor-footer"> |
| | | <el-button size="mini" plain icon="el-icon-plus" @click="addStationRow(field.field)">新增站点</el-button> |
| | | <span class="json-preview mono" :title="dialogForm[field.field]">{{ dialogForm[field.field] || '空' }}</span> |
| | | </div> |
| | | </div> |
| | | <el-input |
| | | v-else-if="field.textarea" |
| | | v-model.trim="dialogForm[field.field]" |
| | |
| | | |
| | | <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/js/jsonEditors.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/vue/js/vue.min.js"></script> |
| | | <script type="text/javascript" src="../../static/vue/element/element.js"></script> |
| | | <script type="text/javascript" src="../../static/js/basDevp/basDevp.js?v=20260310" charset="utf-8"></script> |
| | |
| | | font-family: Menlo, Monaco, Consolas, "Liberation Mono", monospace; |
| | | } |
| | | |
| | | .station-list-editor, |
| | | .int-array2d-editor, |
| | | .int-array-editor { |
| | | padding: 10px 12px; |
| | | border: 1px solid #dfe7f1; |
| | | border-radius: 10px; |
| | | background: #f8fbff; |
| | | max-height: 400px; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .station-list-editor-row { |
| | | padding: 10px; |
| | | border: 1px solid #e8eef5; |
| | | border-radius: 8px; |
| | | background: #fff; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .station-list-editor-row-head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | } |
| | | |
| | | .station-fields-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(4, 1fr); |
| | | gap: 6px; |
| | | } |
| | | |
| | | .station-fields-grid label { |
| | | display: block; |
| | | font-size: 11px; |
| | | color: #66788f; |
| | | margin-bottom: 2px; |
| | | } |
| | | |
| | | .station-fields-grid .el-input__inner { |
| | | height: 28px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .nested-section { |
| | | margin-top: 8px; |
| | | padding: 8px; |
| | | border: 1px dashed #d0dbe8; |
| | | border-radius: 6px; |
| | | background: #f5f8fc; |
| | | } |
| | | |
| | | .nested-section-head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 6px; |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | } |
| | | |
| | | .json-editor-footer { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .json-preview { |
| | | min-width: 0; |
| | | color: #8a98ac; |
| | | font-size: 12px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | font-family: Menlo, Monaco, Consolas, monospace; |
| | | max-width: 400px; |
| | | } |
| | | |
| | | .int-array2d-group { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | margin-bottom: 8px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .int-array2d-group-label { |
| | | font-size: 12px; |
| | | font-weight: 700; |
| | | color: #66788f; |
| | | min-width: 36px; |
| | | } |
| | | |
| | | .int-array2d-values { |
| | | display: flex; |
| | | gap: 6px; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | } |
| | | |
| | | .int-array2d-values .el-input { |
| | | width: 70px; |
| | | } |
| | | |
| | | .int-array2d-values .el-input__inner { |
| | | height: 28px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .int-array-items { |
| | | display: flex; |
| | | gap: 8px; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | } |
| | | |
| | | .int-array-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .int-array-item .el-input { |
| | | width: 80px; |
| | | } |
| | | |
| | | .int-array-item .el-input__inner { |
| | | height: 28px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .pager-bar { |
| | | padding: 0 16px 16px; |
| | | display: flex; |
| | |
| | | active-color="#13ce66" |
| | | inactive-color="#c0c4cc"> |
| | | </el-switch> |
| | | <!-- StationObjModel 数组编辑器 --> |
| | | <div |
| | | v-else-if="stationEditorFields.indexOf(field.field) !== -1" |
| | | class="station-list-editor"> |
| | | <div |
| | | v-for="(station, sIdx) in jsonEditorRows[field.field] || []" |
| | | :key="field.field + '-station-' + sIdx" |
| | | class="station-list-editor-row"> |
| | | <div class="station-list-editor-row-head"> |
| | | <span>站点 {{ sIdx + 1 }}</span> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeStationRow(field.field, sIdx)">删除</el-button> |
| | | </div> |
| | | <div class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.deviceNo" placeholder="如 1" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.stationId" placeholder="如 11" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.deviceRow" placeholder="排" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.deviceBay" placeholder="列" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.deviceLev" placeholder="层" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.stationLev" placeholder="站点层" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.barcodeIdx" placeholder="条码索引" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.dualCrnExecuteStation" placeholder="双工位工位" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | <!-- 条码站点 --> |
| | | <div class="nested-section"> |
| | | <div class="nested-section-head"> |
| | | <span>条码站点 {{ station.barcodeStation ? '(已配置)' : '' }}</span> |
| | | <span> |
| | | <el-button v-if="!station.barcodeStation" type="text" size="mini" @click="addNestedStation(field.field, sIdx, 'barcodeStation')">添加</el-button> |
| | | <el-button v-if="station.barcodeStation" type="text" size="mini" @click="toggleNested(field.field, sIdx, 'barcodeStation')">{{ station._showBarcode ? '收起' : '展开' }}</el-button> |
| | | <el-button v-if="station.barcodeStation" type="text" size="mini" style="color:#f56c6c;" @click="removeNestedStation(field.field, sIdx, 'barcodeStation')">移除</el-button> |
| | | </span> |
| | | </div> |
| | | <div v-if="station.barcodeStation && station._showBarcode" class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.barcodeStation.deviceNo" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.barcodeStation.stationId" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.barcodeStation.deviceRow" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.barcodeStation.deviceBay" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.barcodeStation.deviceLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.barcodeStation.stationLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.barcodeStation.barcodeIdx" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.barcodeStation.dualCrnExecuteStation" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | </div> |
| | | <!-- 回库站点 --> |
| | | <div class="nested-section"> |
| | | <div class="nested-section-head"> |
| | | <span>回库站点 {{ station.backStation ? '(已配置)' : '' }}</span> |
| | | <span> |
| | | <el-button v-if="!station.backStation" type="text" size="mini" @click="addNestedStation(field.field, sIdx, 'backStation')">添加</el-button> |
| | | <el-button v-if="station.backStation" type="text" size="mini" @click="toggleNested(field.field, sIdx, 'backStation')">{{ station._showBack ? '收起' : '展开' }}</el-button> |
| | | <el-button v-if="station.backStation" type="text" size="mini" style="color:#f56c6c;" @click="removeNestedStation(field.field, sIdx, 'backStation')">移除</el-button> |
| | | </span> |
| | | </div> |
| | | <div v-if="station.backStation && station._showBack" class="station-fields-grid"> |
| | | <div><label>设备号</label><el-input v-model.trim="station.backStation.deviceNo" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点ID</label><el-input v-model.trim="station.backStation.stationId" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>排</label><el-input v-model.trim="station.backStation.deviceRow" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>列</label><el-input v-model.trim="station.backStation.deviceBay" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>层</label><el-input v-model.trim="station.backStation.deviceLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>站点层</label><el-input v-model.trim="station.backStation.stationLev" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>条码索引</label><el-input v-model.trim="station.backStation.barcodeIdx" @input="syncStationField(field.field)"></el-input></div> |
| | | <div><label>双工位工位</label><el-input v-model.trim="station.backStation.dualCrnExecuteStation" @input="syncStationField(field.field)"></el-input></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="json-editor-footer"> |
| | | <el-button size="mini" plain icon="el-icon-plus" @click="addStationRow(field.field)">新增站点</el-button> |
| | | <span class="json-preview mono" :title="dialogForm[field.field]">{{ dialogForm[field.field] || '空' }}</span> |
| | | </div> |
| | | </div> |
| | | <!-- 二维整数数组编辑器 --> |
| | | <div |
| | | v-else-if="intArray2dFields.indexOf(field.field) !== -1" |
| | | class="int-array2d-editor"> |
| | | <div |
| | | v-for="(group, gIdx) in jsonEditorRows[field.field] || []" |
| | | :key="field.field + '-group-' + gIdx" |
| | | class="int-array2d-group"> |
| | | <span class="int-array2d-group-label">组 {{ gIdx + 1 }}</span> |
| | | <div class="int-array2d-values"> |
| | | <el-input |
| | | v-for="(val, vIdx) in group.values" |
| | | :key="field.field + '-g' + gIdx + '-v' + vIdx" |
| | | v-model.trim="group.values[vIdx]" |
| | | placeholder="值" |
| | | @input="syncIntArray2DField(field.field)"> |
| | | </el-input> |
| | | <el-button type="text" icon="el-icon-plus" @click="addIntArray2DValue(field.field, gIdx)"></el-button> |
| | | </div> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeIntArray2DGroup(field.field, gIdx)">删除组</el-button> |
| | | </div> |
| | | <div class="json-editor-footer"> |
| | | <el-button size="mini" plain icon="el-icon-plus" @click="addIntArray2DGroup(field.field)">新增组</el-button> |
| | | <span class="json-preview mono" :title="dialogForm[field.field]">{{ dialogForm[field.field] || '空' }}</span> |
| | | </div> |
| | | </div> |
| | | <!-- 整数数组编辑器 --> |
| | | <div |
| | | v-else-if="intArrayFields.indexOf(field.field) !== -1" |
| | | class="int-array-editor"> |
| | | <div class="int-array-items"> |
| | | <div |
| | | v-for="(val, idx) in jsonEditorRows[field.field] || []" |
| | | :key="field.field + '-item-' + idx" |
| | | class="int-array-item"> |
| | | <el-input |
| | | v-model.trim="jsonEditorRows[field.field][idx]" |
| | | placeholder="值" |
| | | @input="syncIntArrayField(field.field)"> |
| | | </el-input> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeIntArrayValue(field.field, idx)">删除</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="json-editor-footer"> |
| | | <el-button size="mini" plain icon="el-icon-plus" @click="addIntArrayValue(field.field)">新增</el-button> |
| | | <span class="json-preview mono" :title="dialogForm[field.field]">{{ dialogForm[field.field] || '空' }}</span> |
| | | </div> |
| | | </div> |
| | | <el-input |
| | | v-else-if="field.textarea" |
| | | v-model.trim="dialogForm[field.field]" |
| | |
| | | |
| | | <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/js/jsonEditors.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/vue/js/vue.min.js"></script> |
| | | <script type="text/javascript" src="../../static/vue/element/element.js"></script> |
| | | <script type="text/javascript" src="../../static/js/basDualCrnp/basDualCrnp.js?v=20260310" charset="utf-8"></script> |