#
Junjie
16 小时以前 c0df58a6fb50ee32e7336b5901000549700ebc82
#
12个文件已修改
3个文件已添加
374 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/OpenController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/domain/param/ManualRollbackTaskParam.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/WrkMast.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/WrkMastLog.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/WrkStsType.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/service/WrkCommandRollbackService.java 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZySiemensCrnThread.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZySiemensCrnV2Thread.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZySiemensDualCrnThread.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/WrkMastLogMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/WrkMastMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/sql/20260316_add_wrk_send_fail_rollback.sql 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/wrkMast/wrkMast.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/wrkMast/wrkMast.html 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -152,6 +152,19 @@
        return R.error("任务取消失败");
    }
    @PostMapping("/manualRollbackTask")
    @OpenApiLog(memo = "任务人工回滚")
    public R manualRollbackTask(@RequestBody ManualRollbackTaskParam param) {
        if (param == null) {
            return R.error("参数不能为空");
        }
        boolean rollback = commonService.manualRollbackTask(param);
        if (rollback) {
            return R.ok();
        }
        return R.error("任务人工回滚失败");
    }
    @PostMapping("/cancelTaskBatch")
    @OpenApiLog(memo = "任务批量取消")
    public R cancelTaskBatch(@RequestBody CancelTaskBatchParam param) {
src/main/java/com/zy/asrs/domain/param/ManualRollbackTaskParam.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.domain.param;
import lombok.Data;
@Data
public class ManualRollbackTaskParam {
    private Integer wrkNo;
    // wms任务号
    private String taskNo;
}
src/main/java/com/zy/asrs/entity/WrkMast.java
@@ -175,6 +175,13 @@
    private String systemMsg;
    /**
     * 下发失败次数
     */
    @ApiModelProperty(value= "下发失败次数")
    @TableField(value = "send_fail_count")
    private Integer sendFailCount;
    /**
     * 批次号
     */
    @ApiModelProperty(value= "批次号")
@@ -194,6 +201,9 @@
        if (entity != null) {
            return entity.getWrkDesc();
        }
        try {
            return com.zy.core.enums.WrkStsType.query(this.wrkSts).desc;
        } catch (Exception ignore) {}
        return null;
    }
@@ -275,6 +285,10 @@
    }
    public void setErrorMemo(String errorMemo) {
        if (errorMemo == null) {
            this.errorMemo = null;
            return;
        }
        if (errorMemo.length() > 255) {
            errorMemo = errorMemo.substring(0, 150);
        }
src/main/java/com/zy/asrs/entity/WrkMastLog.java
@@ -181,6 +181,13 @@
    private String systemMsg;
    /**
     * 下发失败次数
     */
    @ApiModelProperty(value= "下发失败次数")
    @TableField(value = "send_fail_count")
    private Integer sendFailCount;
    /**
     * 批次号
     */
    @ApiModelProperty(value= "批次号")
@@ -202,6 +209,9 @@
        if (entity != null) {
            return entity.getWrkDesc();
        }
        try {
            return com.zy.core.enums.WrkStsType.query(this.wrkSts).desc;
        } catch (Exception ignore) {}
        return null;
    }
src/main/java/com/zy/common/service/CommonService.java
@@ -13,6 +13,7 @@
import com.zy.common.utils.NavigateUtils;
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.core.service.WrkCommandRollbackService;
import com.zy.core.enums.*;
import com.zy.core.model.StationObjModel;
import lombok.extern.slf4j.Slf4j;
@@ -44,6 +45,8 @@
    private RedisUtil redisUtil;
    @Autowired
    private BasOutStationAreaService basOutStationAreaService;
    @Autowired
    private WrkCommandRollbackService wrkCommandRollbackService;
    /**
     * 生成工作号
@@ -186,6 +189,10 @@
        return result;
    }
    public boolean manualRollbackTask(ManualRollbackTaskParam param) {
        return wrkCommandRollbackService.manualRollbackTask(param);
    }
    //移库任务
    public boolean createLocMoveTask(CreateLocMoveTaskParam param) {
        Date now = new Date();
src/main/java/com/zy/core/enums/WrkStsType.java
@@ -8,6 +8,7 @@
    INBOUND_DEVICE_RUN(2, "设备上走"),
    INBOUND_RUN(3, "设备搬运中"),
    INBOUND_RUN_COMPLETE(4, "设备搬运完成"),
    INBOUND_MANUAL(6, "入库待人工回滚"),
    COMPLETE_INBOUND(9, "入库完成"),
    SETTLE_INBOUND(10, "入库库存更新"),
@@ -16,12 +17,14 @@
    OUTBOUND_RUN_COMPLETE(103, "设备搬运完成"),
    STATION_RUN(104, "站点运行中"),
    STATION_RUN_COMPLETE(105, "站点运行完成"),
    OUTBOUND_MANUAL(106, "出库待人工回滚"),
    COMPLETE_OUTBOUND(109, "出库完成"),
    SETTLE_OUTBOUND(110, "出库库存更新"),
    NEW_LOC_MOVE(501, "生成移库任务"),
    LOC_MOVE_RUN(502, "设备搬运中"),
    LOC_MOVE_RUN_COMPLETE(503, "设备搬运完成"),
    LOC_MOVE_MANUAL(506, "移库待人工回滚"),
    COMPLETE_LOC_MOVE(509, "移库完成"),
    ;
src/main/java/com/zy/core/service/WrkCommandRollbackService.java
New file
@@ -0,0 +1,212 @@
package com.zy.core.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.core.common.Cools;
import com.core.exception.CoolException;
import com.zy.asrs.domain.param.ManualRollbackTaskParam;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.service.WrkMastLogService;
import com.zy.asrs.service.WrkMastService;
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.core.enums.CrnTaskModeType;
import com.zy.core.enums.RedisKeyType;
import com.zy.core.enums.WrkStsType;
import com.zy.core.model.CommandResponse;
import com.zy.core.model.command.CrnCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.HashMap;
@Slf4j
@Service
public class WrkCommandRollbackService {
    private static final int DEFAULT_AUTO_ROLLBACK_LIMIT = 3;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
    private WrkMastLogService wrkMastLogService;
    @Autowired
    private RedisUtil redisUtil;
    @Transactional(rollbackFor = Exception.class)
    public void handleSingleCrnSendResult(CrnCommand command, CommandResponse response, String deviceName) {
        if (command == null || command.getTaskNo() == null || command.getTaskNo() <= 0) {
            return;
        }
        if (CrnTaskModeType.RESET.id.equals(command.getTaskMode())) {
            return;
        }
        WrkMast wrkMast = wrkMastService.selectByWorkNo(command.getTaskNo());
        if (wrkMast == null) {
            return;
        }
        if (!isSingleCrnRunStatus(wrkMast.getWrkSts())) {
            return;
        }
        if (response != null && Boolean.TRUE.equals(response.getResult())) {
            clearSendFailState(wrkMast);
            return;
        }
        String failMessage = buildFailMessage(deviceName, response);
        int nextFailCount = (wrkMast.getSendFailCount() == null ? 0 : wrkMast.getSendFailCount()) + 1;
        int rollbackLimit = getAutoRollbackLimit();
        boolean manualRequired = nextFailCount >= rollbackLimit;
        Long updateStatus = manualRequired ? getManualStatus(wrkMast.getWrkSts()) : getRollbackStatus(wrkMast.getWrkSts());
        if (updateStatus == null) {
            return;
        }
        saveWrkLog(wrkMast.getWrkNo());
        wrkMast.setWrkSts(updateStatus);
        wrkMast.setSendFailCount(nextFailCount);
        wrkMast.setErrorTime(new Date());
        wrkMast.setErrorMemo(failMessage);
        wrkMast.setSystemMsg(failMessage);
        wrkMast.setModiTime(new Date());
        wrkMastService.updateById(wrkMast);
        if (manualRequired) {
            News.taskError(wrkMast.getWrkNo(), "{}下发命令失败,已达到自动回滚上限({}),请在工作档手动回滚。原因: {}", deviceName, rollbackLimit, failMessage);
        } else {
            News.taskWarn(wrkMast.getWrkNo(), "{}下发命令失败,任务已自动回滚({}/{}). 原因: {}", deviceName, nextFailCount, rollbackLimit, failMessage);
        }
    }
    @Transactional(rollbackFor = Exception.class)
    public boolean manualRollbackTask(ManualRollbackTaskParam param) {
        WrkMast wrkMast = findWrkMast(param == null ? null : param.getWrkNo(), param == null ? null : param.getTaskNo());
        if (wrkMast == null) {
            throw new CoolException("任务不存在");
        }
        Long rollbackStatus = getRollbackStatusFromManual(wrkMast.getWrkSts());
        if (rollbackStatus == null) {
            throw new CoolException("当前任务不处于待人工回滚状态");
        }
        saveWrkLog(wrkMast.getWrkNo());
        wrkMast.setWrkSts(rollbackStatus);
        wrkMast.setSendFailCount(0);
        wrkMast.setSystemMsg("人工回滚完成,等待重新下发");
        wrkMast.setModiTime(new Date());
        wrkMastService.updateById(wrkMast);
        News.taskInfo(wrkMast.getWrkNo(), "人工回滚完成,任务状态已恢复为待执行");
        return true;
    }
    private void clearSendFailState(WrkMast wrkMast) {
        boolean needUpdate = (wrkMast.getSendFailCount() != null && wrkMast.getSendFailCount() > 0)
                || wrkMast.getErrorTime() != null
                || !Cools.isEmpty(wrkMast.getErrorMemo());
        if (!needUpdate) {
            return;
        }
        saveWrkLog(wrkMast.getWrkNo());
        wrkMast.setSendFailCount(0);
        wrkMast.setErrorTime(null);
        wrkMast.setErrorMemo(null);
        wrkMast.setSystemMsg("");
        wrkMast.setModiTime(new Date());
        wrkMastService.updateById(wrkMast);
    }
    private WrkMast findWrkMast(Integer wrkNo, String taskNo) {
        if (wrkNo != null) {
            return wrkMastService.selectByWorkNo(wrkNo);
        }
        if (!Cools.isEmpty(taskNo)) {
            return wrkMastService.getOne(new QueryWrapper<WrkMast>().eq("wms_wrk_no", taskNo));
        }
        return null;
    }
    private void saveWrkLog(Integer wrkNo) {
        try {
            wrkMastLogService.save(wrkNo);
        } catch (Exception e) {
            log.warn("保存工作档日志失败, wrkNo={}", wrkNo, e);
        }
    }
    private int getAutoRollbackLimit() {
        Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
        if (!(systemConfigMapObj instanceof HashMap)) {
            return DEFAULT_AUTO_ROLLBACK_LIMIT;
        }
        try {
            HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
            return Math.max(1, Integer.parseInt(systemConfigMap.getOrDefault("deviceCommandAutoRollbackLimit", String.valueOf(DEFAULT_AUTO_ROLLBACK_LIMIT))));
        } catch (Exception ignore) {
            return DEFAULT_AUTO_ROLLBACK_LIMIT;
        }
    }
    private String buildFailMessage(String deviceName, CommandResponse response) {
        if (response != null && !Cools.isEmpty(response.getMessage())) {
            return response.getMessage();
        }
        return deviceName + "命令下发失败";
    }
    private boolean isSingleCrnRunStatus(Long wrkSts) {
        return Long.valueOf(WrkStsType.INBOUND_RUN.sts).equals(wrkSts)
                || Long.valueOf(WrkStsType.OUTBOUND_RUN.sts).equals(wrkSts)
                || Long.valueOf(WrkStsType.LOC_MOVE_RUN.sts).equals(wrkSts);
    }
    private Long getRollbackStatus(Long wrkSts) {
        if (Long.valueOf(WrkStsType.INBOUND_RUN.sts).equals(wrkSts)) {
            return WrkStsType.INBOUND_DEVICE_RUN.sts;
        }
        if (Long.valueOf(WrkStsType.OUTBOUND_RUN.sts).equals(wrkSts)) {
            return WrkStsType.NEW_OUTBOUND.sts;
        }
        if (Long.valueOf(WrkStsType.LOC_MOVE_RUN.sts).equals(wrkSts)) {
            return WrkStsType.NEW_LOC_MOVE.sts;
        }
        return null;
    }
    private Long getManualStatus(Long wrkSts) {
        if (Long.valueOf(WrkStsType.INBOUND_RUN.sts).equals(wrkSts)) {
            return WrkStsType.INBOUND_MANUAL.sts;
        }
        if (Long.valueOf(WrkStsType.OUTBOUND_RUN.sts).equals(wrkSts)) {
            return WrkStsType.OUTBOUND_MANUAL.sts;
        }
        if (Long.valueOf(WrkStsType.LOC_MOVE_RUN.sts).equals(wrkSts)) {
            return WrkStsType.LOC_MOVE_MANUAL.sts;
        }
        return null;
    }
    private Long getRollbackStatusFromManual(Long wrkSts) {
        if (Long.valueOf(WrkStsType.INBOUND_MANUAL.sts).equals(wrkSts)) {
            return WrkStsType.INBOUND_DEVICE_RUN.sts;
        }
        if (Long.valueOf(WrkStsType.OUTBOUND_MANUAL.sts).equals(wrkSts)) {
            return WrkStsType.NEW_OUTBOUND.sts;
        }
        if (Long.valueOf(WrkStsType.LOC_MOVE_MANUAL.sts).equals(wrkSts)) {
            return WrkStsType.NEW_LOC_MOVE.sts;
        }
        return null;
    }
}
src/main/java/com/zy/core/thread/impl/ZySiemensCrnThread.java
@@ -24,6 +24,7 @@
import com.zy.core.network.DeviceConnectPool;
import com.zy.core.network.ZyCrnConnectDriver;
import com.zy.core.network.entity.ZyCrnStatusEntity;
import com.zy.core.service.WrkCommandRollbackService;
import com.zy.core.thread.CrnThread;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@@ -307,12 +308,13 @@
            response = zyCrnConnectDriver.sendCommand(command);
            return response;
        } finally {
            if (command != null) {
            String sourceLocNo = Utils.getLocNo(command.getSourcePosX(), command.getSourcePosY(), command.getSourcePosZ());
            String targetLocNo = Utils.getLocNo(command.getDestinationPosX(), command.getDestinationPosY(), command.getDestinationPosZ());
            BasCrnpOptService bean = SpringUtils.getBean(BasCrnpOptService.class);
            ZyCrnStatusEntity statusEntity = zyCrnConnectDriver.getStatus();
            BasCrnpOpt basCrnpOpt = new BasCrnpOpt(
                    command.getTaskNo().intValue(),
                        command.getTaskNo(),
                    command.getCrnNo(),
                    new Date(),
                    String.valueOf(command.getTaskMode()),
@@ -326,8 +328,15 @@
                    1,
                    JSON.toJSONString(response)
            );
            if (bean != null) {
                bean.save(basCrnpOpt);
                try {
                    WrkCommandRollbackService rollbackService = SpringUtils.getBean(WrkCommandRollbackService.class);
                    if (rollbackService != null) {
                        rollbackService.handleSingleCrnSendResult(command, response, "单工位堆垛机");
                    }
                } catch (Exception e) {
                    log.error("处理单工位命令下发结果失败, wrkNo={}", command.getTaskNo(), e);
                }
            }
        }
    }
src/main/java/com/zy/core/thread/impl/ZySiemensCrnV2Thread.java
@@ -22,6 +22,7 @@
import com.zy.core.network.DeviceConnectPool;
import com.zy.core.network.ZyCrnV2ConnectDriver;
import com.zy.core.network.entity.ZyCrnStatusEntity;
import com.zy.core.service.WrkCommandRollbackService;
import com.zy.core.thread.CrnThread;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@@ -307,12 +308,13 @@
            response = zyCrnConnectDriver.sendCommand(command);
            return response;
        } finally {
            if (command != null) {
            String sourceLocNo = Utils.getLocNo(command.getSourcePosX(), command.getSourcePosY(), command.getSourcePosZ());
            String targetLocNo = Utils.getLocNo(command.getDestinationPosX(), command.getDestinationPosY(), command.getDestinationPosZ());
            BasCrnpOptService bean = SpringUtils.getBean(BasCrnpOptService.class);
            ZyCrnStatusEntity statusEntity = zyCrnConnectDriver.getStatus();
            BasCrnpOpt basCrnpOpt = new BasCrnpOpt(
                    command.getTaskNo().intValue(),
                        command.getTaskNo(),
                    command.getCrnNo(),
                    new Date(),
                    String.valueOf(command.getTaskMode()),
@@ -326,8 +328,15 @@
                    1,
                    JSON.toJSONString(response)
            );
            if (bean != null) {
                bean.save(basCrnpOpt);
                try {
                    WrkCommandRollbackService rollbackService = SpringUtils.getBean(WrkCommandRollbackService.class);
                    if (rollbackService != null) {
                        rollbackService.handleSingleCrnSendResult(command, response, "单工位堆垛机V2");
                    }
                } catch (Exception e) {
                    log.error("处理单工位V2命令下发结果失败, wrkNo={}", command.getTaskNo(), e);
                }
            }
        }
    }
src/main/java/com/zy/core/thread/impl/ZySiemensDualCrnThread.java
@@ -523,7 +523,7 @@
            BasDualCrnpOptService bean = SpringUtils.getBean(BasDualCrnpOptService.class);
            ZyDualCrnStatusEntity statusEntity = zyDualCrnConnectDriver.getStatus();
            BasDualCrnpOpt basDualCrnpOpt = new BasDualCrnpOpt(
                    command.getTaskNo().intValue(),
                    command.getTaskNo(),
                    command.getCrnNo(),
                    new Date(),
                    String.valueOf(command.getTaskMode()),
@@ -537,9 +537,7 @@
                    1,
                    JSON.toJSONString(response)
            );
            if (bean != null) {
                bean.save(basDualCrnpOpt);
            }
        }
    }
src/main/resources/mapper/WrkMastLogMapper.xml
@@ -28,6 +28,7 @@
        <result column="rgv_no" property="rgvNo" />
        <result column="wms_wrk_no" property="wmsWrkNo" />
        <result column="system_msg" property="systemMsg" />
        <result column="send_fail_count" property="sendFailCount" />
        <result column="batch" property="batch" />
        <result column="batch_seq" property="batchSeq" />
    </resultMap>
src/main/resources/mapper/WrkMastMapper.xml
@@ -27,6 +27,7 @@
        <result column="rgv_no" property="rgvNo" />
        <result column="wms_wrk_no" property="wmsWrkNo" />
        <result column="system_msg" property="systemMsg" />
        <result column="send_fail_count" property="sendFailCount" />
        <result column="batch" property="batch" />
        <result column="batch_seq" property="batchSeq" />
src/main/resources/sql/20260316_add_wrk_send_fail_rollback.sql
New file
@@ -0,0 +1,21 @@
ALTER TABLE `asr_wrk_mast`
    ADD COLUMN `send_fail_count` INT NOT NULL DEFAULT 0 COMMENT '命令下发失败次数' AFTER `system_msg`;
ALTER TABLE `asr_wrk_mast_log`
    ADD COLUMN `send_fail_count` INT NOT NULL DEFAULT 0 COMMENT '命令下发失败次数' AFTER `system_msg`;
INSERT INTO `asr_bas_wrk_status` (`wrk_sts`, `wrk_desc`, `modi_user`, `modi_time`, `appe_user`, `appe_time`)
SELECT 6, '入库待人工回滚', NULL, NOW(), NULL, NOW()
WHERE NOT EXISTS (SELECT 1 FROM `asr_bas_wrk_status` WHERE `wrk_sts` = 6);
INSERT INTO `asr_bas_wrk_status` (`wrk_sts`, `wrk_desc`, `modi_user`, `modi_time`, `appe_user`, `appe_time`)
SELECT 106, '出库待人工回滚', NULL, NOW(), NULL, NOW()
WHERE NOT EXISTS (SELECT 1 FROM `asr_bas_wrk_status` WHERE `wrk_sts` = 106);
INSERT INTO `asr_bas_wrk_status` (`wrk_sts`, `wrk_desc`, `modi_user`, `modi_time`, `appe_user`, `appe_time`)
SELECT 506, '移库待人工回滚', NULL, NOW(), NULL, NOW()
WHERE NOT EXISTS (SELECT 1 FROM `asr_bas_wrk_status` WHERE `wrk_sts` = 506);
INSERT INTO `sys_config` (`name`, `code`, `value`, `type`, `status`, `select_type`)
SELECT '设备命令自动回滚上限', 'deviceCommandAutoRollbackLimit', '3', 1, 1, 'crn'
WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `code` = 'deviceCommandAutoRollbackLimit');
src/main/webapp/static/js/wrkMast/wrkMast.js
@@ -17,8 +17,13 @@
        { key: "dualCrnNo", prop: "dualCrnNo", label: "双工位堆垛机", minWidth: 120, sortable: true, align: "center" },
        { key: "batch", prop: "batch", label: "批次", minWidth: 120, sortable: true },
        { key: "batchSeq", prop: "batchSeq", label: "批次序列", width: 100, sortable: true, align: "center" },
        { key: "sendFailCount", prop: "sendFailCount", label: "失败次数", width: 96, sortable: true, align: "center" },
        { key: "errorTime$", prop: "errorTime$", label: "失败时间", minWidth: 168, sortable: true },
        { key: "errorMemo", prop: "errorMemo", label: "失败原因", minWidth: 220, sortable: false, showOverflow: false },
        { key: "systemMsg", prop: "systemMsg", label: "系统消息", minWidth: 220, sortable: false, showOverflow: false }
    ];
    var MANUAL_ROLLBACK_STATUSES = [6, 106, 506];
    function cloneSearchForm() {
        return {
@@ -237,7 +242,14 @@
                }
                if (command === "cancel") {
                    this.cancelTask(row);
                    return;
                }
                if (command === "manualRollback") {
                    this.manualRollbackTask(row);
                }
            },
            canManualRollback: function (row) {
                return !!row && MANUAL_ROLLBACK_STATUSES.indexOf(Number(row.wrkSts)) > -1;
            },
            completeTask: function (row) {
                var vm = this;
@@ -301,6 +313,41 @@
                    });
                }).catch(function () {});
            },
            manualRollbackTask: function (row) {
                var vm = this;
                if (!vm.canManualRollback(row)) {
                    vm.$message.warning("当前任务不处于待人工回滚状态");
                    return;
                }
                vm.$confirm("确定手动回滚该任务吗?回滚后任务会恢复为待执行状态。", "提示", {
                    type: "warning",
                    confirmButtonText: "确定",
                    cancelButtonText: "取消"
                }).then(function () {
                    $.ajax({
                        url: baseUrl + "/openapi/manualRollbackTask",
                        contentType: "application/json",
                        headers: { token: localStorage.getItem("token") },
                        data: JSON.stringify({ wrkNo: row.wrkNo }),
                        method: "POST",
                        success: function (res) {
                            if (res.code === 200) {
                                vm.$message.success("人工回滚成功");
                                vm.loadList();
                                return;
                            }
                            if (res.code === 403) {
                                top.location.href = baseUrl + "/";
                                return;
                            }
                            vm.$message.error(res.msg || "人工回滚失败");
                        },
                        error: function () {
                            vm.$message.error("人工回滚失败");
                        }
                    });
                }).catch(function () {});
            },
            updateTableHeight: function () {
                var viewport = window.innerHeight || document.documentElement.clientHeight || 860;
                this.tableHeight = Math.max(340, viewport - (this.advancedVisible ? 276 : 222));
src/main/webapp/views/wrkMast/wrkMast.html
@@ -378,7 +378,7 @@
                        :show-overflow-tooltip="column.showOverflow !== false"
                        :align="column.align || 'left'">
                        <template slot-scope="scope">
                            <span :class="column.key === 'systemMsg' ? 'payload-cell' : ''">
                            <span :class="(column.key === 'systemMsg' || column.key === 'errorMemo') ? 'payload-cell' : ''">
                                {{ displayCellValue(scope.row, column) }}
                            </span>
                        </template>
@@ -390,6 +390,7 @@
                                    操作<i class="el-icon-arrow-down el-icon--right"></i>
                                </el-button>
                                <el-dropdown-menu slot="dropdown">
                                    <el-dropdown-item v-if="canManualRollback(scope.row)" command="manualRollback">手动回滚</el-dropdown-item>
                                    <el-dropdown-item command="complete">完成任务</el-dropdown-item>
                                    <el-dropdown-item command="cancel" divided>取消任务</el-dropdown-item>
                                </el-dropdown-menu>