Junjie
2026-04-24 b97d8158437dd61c3fc85921fe2bbf15ee518770
#堆垛机命令增加排映射关系V3.0.0.8
1个文件已添加
7个文件已修改
274 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/entity/BasCrnp.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZySiemensCrnThread.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZySiemensCrnV2Thread.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/BasCrnpMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/sql/20260424_add_crnp_row_map.sql 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/basCrnp/basCrnp.js 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/basCrnp/basCrnp.html 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/BasCrnp.java
@@ -1,6 +1,7 @@
package com.zy.asrs.entity;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.core.common.Cools;
import com.zy.core.model.StationObjModel;
import com.baomidou.mybatisplus.annotation.TableId;
@@ -81,6 +82,10 @@
    @ApiModelProperty(value= "深库位排号")
    @TableField("deep_rows")
    private String deepRows;
    @ApiModelProperty(value= "堆垛机命令排号映射JSON")
    @TableField("row_map")
    private String rowMap;
    /**
     * 入站列表
@@ -196,4 +201,25 @@
        return rowList;
    }
    public Integer getCommandRow(Integer locationRow){
        if (locationRow == null || Cools.isEmpty(this.rowMap)){
            return locationRow;
        }
        try {
            JSONObject rowMapJson = JSON.parseObject(this.rowMap);
            String locationRowKey = String.valueOf(locationRow);
            Object commandRowValue = rowMapJson.get(locationRowKey);
            if (commandRowValue == null){
                return locationRow;
            }
            if (commandRowValue instanceof Number){
                return ((Number) commandRowValue).intValue();
            }
            return Integer.valueOf(String.valueOf(commandRowValue));
        } catch (Exception exception) {
            return locationRow;
        }
    }
}
src/main/java/com/zy/core/thread/impl/ZySiemensCrnThread.java
@@ -259,14 +259,15 @@
    @Override
    public CrnCommand getPickAndPutCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo) {
        BasCrnp basCrnp = getBasCrnp(crnNo);
        CrnCommand crnCommand = new CrnCommand();
        crnCommand.setCrnNo(crnNo); // 堆垛机编号
        crnCommand.setTaskNo(taskNo); // 工作号
        crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE.id); // 任务模式:  库位移转
        crnCommand.setSourcePosX(Utils.getRow(sourceLocNo));     // 源库位排
        crnCommand.setSourcePosX(resolveCommandRow(sourceLocNo, basCrnp));     // 源库位排
        crnCommand.setSourcePosY(Utils.getBay(sourceLocNo));     // 源库位列
        crnCommand.setSourcePosZ(Utils.getLev(sourceLocNo));     // 源库位层
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // 目标库位排
        crnCommand.setDestinationPosX(resolveCommandRow(targetLocNo, basCrnp));     // 目标库位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // 目标库位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // 目标库位层
        crnCommand.setCommand(1);     // 任务确认
@@ -275,21 +276,39 @@
    @Override
    public CrnCommand getMoveCommand(String targetLocNo, Integer taskNo, Integer crnNo) {
        Integer targetRow = resolveCommandRow(targetLocNo, crnNo);
        CrnCommand crnCommand = new CrnCommand();
        crnCommand.setCrnNo(crnNo); // 堆垛机编号
        crnCommand.setTaskNo(taskNo); // 工作号
        crnCommand.setAckFinish(0);  // 任务完成确认位
        crnCommand.setTaskMode(CrnTaskModeType.CRN_MOVE.id); // 任务模式:  堆垛机移动
        crnCommand.setSourcePosX(Utils.getRow(targetLocNo));     // 目标库位排
        crnCommand.setSourcePosX(targetRow);     // 目标库位排
        crnCommand.setSourcePosY(Utils.getBay(targetLocNo));     // 目标库位列
        crnCommand.setSourcePosZ(Utils.getLev(targetLocNo));     // 目标库位层
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // 目标库位排
        crnCommand.setDestinationPosX(targetRow);     // 目标库位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // 目标库位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // 目标库位层
        crnCommand.setCommand(1);     // 任务确认
        return crnCommand;
    }
    private Integer resolveCommandRow(String locNo, Integer crnNo) {
        return resolveCommandRow(locNo, getBasCrnp(crnNo));
    }
    private Integer resolveCommandRow(String locNo, BasCrnp basCrnp) {
        Integer locationRow = Utils.getRow(locNo);
        if (basCrnp == null) {
            return locationRow;
        }
        return basCrnp.getCommandRow(locationRow);
    }
    private BasCrnp getBasCrnp(Integer crnNo) {
        BasCrnpService basCrnpService = SpringUtils.getBean(BasCrnpService.class);
        return basCrnpService.getById(crnNo);
    }
    @Override
    public CrnCommand getResetCommand(Integer taskNo, Integer crnNo) {
        CrnCommand crnCommand = new CrnCommand();
src/main/java/com/zy/core/thread/impl/ZySiemensCrnV2Thread.java
@@ -258,14 +258,15 @@
    @Override
    public CrnCommand getPickAndPutCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo) {
        BasCrnp basCrnp = getBasCrnp(crnNo);
        CrnCommand crnCommand = new CrnCommand();
        crnCommand.setCrnNo(crnNo); // 堆垛机编号
        crnCommand.setTaskNo(taskNo); // 工作号
        crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE.id); // 任务模式:  库位移转
        crnCommand.setSourcePosX(Utils.getRow(sourceLocNo));     // 源库位排
        crnCommand.setSourcePosX(resolveCommandRow(sourceLocNo, basCrnp));     // 源库位排
        crnCommand.setSourcePosY(Utils.getBay(sourceLocNo));     // 源库位列
        crnCommand.setSourcePosZ(Utils.getLev(sourceLocNo));     // 源库位层
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // 目标库位排
        crnCommand.setDestinationPosX(resolveCommandRow(targetLocNo, basCrnp));     // 目标库位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // 目标库位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // 目标库位层
        crnCommand.setCommand(1);     // 任务确认
@@ -274,21 +275,39 @@
    @Override
    public CrnCommand getMoveCommand(String targetLocNo, Integer taskNo, Integer crnNo) {
        Integer targetRow = resolveCommandRow(targetLocNo, crnNo);
        CrnCommand crnCommand = new CrnCommand();
        crnCommand.setCrnNo(crnNo); // 堆垛机编号
        crnCommand.setTaskNo(taskNo); // 工作号
        crnCommand.setAckFinish(0);  // 任务完成确认位
        crnCommand.setTaskMode(CrnTaskModeType.CRN_MOVE.id); // 任务模式:  堆垛机移动
        crnCommand.setSourcePosX(Utils.getRow(targetLocNo));     // 目标库位排
        crnCommand.setSourcePosX(targetRow);     // 目标库位排
        crnCommand.setSourcePosY(Utils.getBay(targetLocNo));     // 目标库位列
        crnCommand.setSourcePosZ(Utils.getLev(targetLocNo));     // 目标库位层
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // 目标库位排
        crnCommand.setDestinationPosX(targetRow);     // 目标库位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // 目标库位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // 目标库位层
        crnCommand.setCommand(1);     // 任务确认
        return crnCommand;
    }
    private Integer resolveCommandRow(String locNo, Integer crnNo) {
        return resolveCommandRow(locNo, getBasCrnp(crnNo));
    }
    private Integer resolveCommandRow(String locNo, BasCrnp basCrnp) {
        Integer locationRow = Utils.getRow(locNo);
        if (basCrnp == null) {
            return locationRow;
        }
        return basCrnp.getCommandRow(locationRow);
    }
    private BasCrnp getBasCrnp(Integer crnNo) {
        BasCrnpService basCrnpService = SpringUtils.getBean(BasCrnpService.class);
        return basCrnpService.getById(crnNo);
    }
    @Override
    public CrnCommand getResetCommand(Integer taskNo, Integer crnNo) {
        CrnCommand crnCommand = new CrnCommand();
src/main/resources/application.yml
@@ -1,6 +1,6 @@
# 系统版本信息
app:
  version: 3.0.0.7
  version: 3.0.0.8
  version-type: prd  # prd 或 dev
  i18n:
    default-locale: zh-CN
src/main/resources/mapper/BasCrnpMapper.xml
@@ -20,6 +20,7 @@
        <result column="max_in_task" property="maxInTask" />
        <result column="max_out_task" property="maxOutTask" />
        <result column="deep_rows" property="deepRows" />
        <result column="row_map" property="rowMap" />
    </resultMap>
src/main/resources/sql/20260424_add_crnp_row_map.sql
New file
@@ -0,0 +1,16 @@
SET @crnp_row_map_column_exists := (
  SELECT COUNT(1)
  FROM information_schema.COLUMNS
  WHERE TABLE_SCHEMA = DATABASE()
    AND TABLE_NAME = 'asr_bas_crnp'
    AND COLUMN_NAME = 'row_map'
);
SET @add_crnp_row_map_sql := IF(@crnp_row_map_column_exists = 0,
  'ALTER TABLE `asr_bas_crnp` ADD COLUMN `row_map` varchar(1000) DEFAULT NULL COMMENT ''堆垛机命令排号映射JSON'' AFTER `deep_rows`',
  'SELECT 1'
);
PREPARE stmt_add_crnp_row_map FROM @add_crnp_row_map_sql;
EXECUTE stmt_add_crnp_row_map;
DEALLOCATE PREPARE stmt_add_crnp_row_map;
src/main/webapp/static/js/basCrnp/basCrnp.js
@@ -220,6 +220,24 @@
        checkboxInactiveRaw: 'N'
    },
    {
        field: 'rowMap',
        columnName: 'row_map',
        label: '命令排号映射',
        tableProp: 'rowMap',
        exportField: 'rowMap',
        kind: 'text',
        valueType: 'string',
        required: false,
        primaryKey: false,
        sortable: false,
        textarea: true,
        minWidth: 180,
        enumOptions: [],
        foreignQuery: '',
        checkboxActiveRaw: 'Y',
        checkboxInactiveRaw: 'N'
    },
    {
        field: 'inStationList',
        columnName: 'in_station_list',
        label: '入库站点',
@@ -507,6 +525,65 @@
        return payload;
    }
    function parseRowMapRows(rowMapText) {
        if (isEmptyValue(rowMapText)) {
            return [];
        }
        try {
            var rowMapObject = JSON.parse(rowMapText);
            if (!rowMapObject || Array.isArray(rowMapObject) || typeof rowMapObject !== 'object') {
                return [];
            }
            return Object.keys(rowMapObject).map(function (locationRow) {
                return {
                    locationRow: String(locationRow),
                    commandRow: String(rowMapObject[locationRow])
                };
            });
        } catch (error) {
            return [];
        }
    }
    function buildRowMapJson(rowMapRows) {
        var rowMapObject = {};
        (rowMapRows || []).forEach(function (item) {
            var locationRow = item && item.locationRow ? String(item.locationRow).trim() : '';
            var commandRow = item && item.commandRow ? String(item.commandRow).trim() : '';
            if (!locationRow || !commandRow) {
                return;
            }
            rowMapObject[locationRow] = Number(commandRow);
        });
        if (Object.keys(rowMapObject).length === 0) {
            return '';
        }
        return JSON.stringify(rowMapObject);
    }
    function validateRowMapRows(rowMapRows) {
        var locationRowMap = {};
        for (var rowIndex = 0; rowIndex < rowMapRows.length; rowIndex++) {
            var item = rowMapRows[rowIndex];
            var locationRow = item && item.locationRow ? String(item.locationRow).trim() : '';
            var commandRow = item && item.commandRow ? String(item.commandRow).trim() : '';
            if (!locationRow && !commandRow) {
                continue;
            }
            if (!/^\d+$/.test(locationRow)) {
                return '第' + (rowIndex + 1) + '行库位排必须为整数';
            }
            if (!/^\d+$/.test(commandRow)) {
                return '第' + (rowIndex + 1) + '行命令 row 必须为整数';
            }
            if (locationRowMap[locationRow]) {
                return '库位排 ' + locationRow + ' 重复配置';
            }
            locationRowMap[locationRow] = true;
        }
        return '';
    }
    function fillFormFromRow(row, form, display) {
        fieldMeta.forEach(function (field) {
            if (field.primaryKey) {
@@ -699,6 +776,7 @@
                    tableResizeHandler: null,
                    dialogForm: createFormDefaults(),
                    dialogDisplay: createDisplayDefaults(),
                    rowMapRows: [],
                    dialogRules: createFormRules()
                };
            },
@@ -932,6 +1010,7 @@
                resetDialogState: function () {
                    this.dialogForm = createFormDefaults();
                    this.dialogDisplay = createDisplayDefaults();
                    this.rowMapRows = [];
                    if (this.$refs.dialogForm) {
                        this.$refs.dialogForm.clearValidate();
                    }
@@ -948,16 +1027,37 @@
                    self.$nextTick(function () {
                        self.resetDialogState();
                        fillFormFromRow(row, self.dialogForm, self.dialogDisplay);
                        self.rowMapRows = parseRowMapRows(self.dialogForm.rowMap);
                        if (self.$refs.dialogForm) {
                            self.$refs.dialogForm.clearValidate();
                        }
                    });
                },
                addRowMapRow: function () {
                    this.rowMapRows.push({
                        locationRow: '',
                        commandRow: ''
                    });
                    this.syncRowMapJson();
                },
                removeRowMapRow: function (index) {
                    this.rowMapRows.splice(index, 1);
                    this.syncRowMapJson();
                },
                syncRowMapJson: function () {
                    this.$set(this.dialogForm, 'rowMap', buildRowMapJson(this.rowMapRows));
                },
                submitDialog: function () {
                    var self = this;
                    if (!self.$refs.dialogForm) {
                        return;
                    }
                    self.syncRowMapJson();
                    var rowMapMessage = validateRowMapRows(self.rowMapRows);
                    if (rowMapMessage) {
                        self.$message.warning(rowMapMessage);
                        return;
                    }
                    self.$refs.dialogForm.validate(function (valid) {
                        if (!valid) {
                            return false;
src/main/webapp/views/basCrnp/basCrnp.html
@@ -196,6 +196,49 @@
            font-family: Menlo, Monaco, Consolas, "Liberation Mono", monospace;
        }
        .row-map-editor {
            padding: 10px 12px;
            border: 1px solid #dfe7f1;
            border-radius: 10px;
            background: #f8fbff;
        }
        .row-map-editor-head,
        .row-map-editor-row {
            display: grid;
            grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 72px;
            gap: 8px;
            align-items: center;
        }
        .row-map-editor-head {
            margin-bottom: 8px;
            color: #66788f;
            font-size: 12px;
            font-weight: 700;
        }
        .row-map-editor-row + .row-map-editor-row {
            margin-top: 8px;
        }
        .row-map-editor-footer {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
            margin-top: 10px;
        }
        .row-map-json-preview {
            min-width: 0;
            color: #8a98ac;
            font-size: 12px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .pager-bar {
            padding: 0 16px 16px;
            display: flex;
@@ -638,6 +681,38 @@
                            active-color="#13ce66"
                            inactive-color="#c0c4cc">
                        </el-switch>
                        <div
                            v-else-if="field.field === 'rowMap'"
                            class="row-map-editor">
                            <div class="row-map-editor-head">
                                <span>库位排</span>
                                <span>命令 row</span>
                                <span>操作</span>
                            </div>
                            <div
                                v-for="(item, index) in rowMapRows"
                                :key="'row-map-' + index"
                                class="row-map-editor-row">
                                <el-input
                                    v-model.trim="item.locationRow"
                                    placeholder="如 1"
                                    @input="syncRowMapJson">
                                </el-input>
                                <el-input
                                    v-model.trim="item.commandRow"
                                    placeholder="如 11"
                                    @input="syncRowMapJson">
                                </el-input>
                                <el-button
                                    type="text"
                                    style="color:#f56c6c;"
                                    @click="removeRowMapRow(index)">删除</el-button>
                            </div>
                            <div class="row-map-editor-footer">
                                <el-button size="mini" plain icon="el-icon-plus" @click="addRowMapRow">新增映射</el-button>
                                <span class="row-map-json-preview mono" :title="dialogForm.rowMap">{{ dialogForm.rowMap || '未配置时使用库位排原值' }}</span>
                            </div>
                        </div>
                        <el-input
                            v-else-if="field.textarea"
                            v-model.trim="dialogForm[field.field]"