zhou zhou
15 小时以前 10776dd6f7f9ef9e47419427fcb1b692ed73d54d
Merge remote-tracking branch 'origin/devlop-phyz' into devlop-phyz
28个文件已修改
1347 ■■■■ 已修改文件
.gitignore 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/basStation/CrossZoneAreaField.jsx 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/MatnrEdit.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/PageDrawer.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/task/TaskList.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/controller/phyz/ERPController.java 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/constant/WmsConstant.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/phyz/InventorySummary.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/feign/wms/WmsServerFeignClient.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-open-api/src/main/java/com/vincent/rsf/openApi/feign/wms/fallback/WmsServerFeignClientFallback.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/ErpQueryController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/enums/CallBackEvent.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/ReceiveMsgService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/AgvServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/InBoundServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/PageParam.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Task.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/MissionStepType.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TaskStsType.java 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskMissionSchedules.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/entity/FlowStepInstance.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -39,3 +39,4 @@
logs
logs/**
/log.path_IS_UNDEFINED/*.log
/log.path_IS_UNDEFINED/*/*.log
rsf-admin/src/page/basicInfo/basStation/CrossZoneAreaField.jsx
@@ -20,31 +20,32 @@
    };
    const fetchAreaNames = async () => {
        if (!record?.areas || record.areas.length === 0) return;
        const areasData = record?.areaIds || record?.areas;
        if (!areasData || areasData.length === 0) return;
        setLoading(true);
        try {
            // 提取排序信息和ID
            // Old format: [1, 2, 3] (array of integers)
            // New format: [{id: 1, sort: 1}, {id: 2, sort: 2}] (array of objects)
            const isObjectArray = record.areas.length > 0 &&
                typeof record.areas[0] === 'object' &&
                record.areas[0] !== null &&
                'id' in record.areas[0];
            const isObjectArray = areasData.length > 0 &&
                typeof areasData[0] === 'object' &&
                areasData[0] !== null &&
                'id' in areasData[0];
            
            let areaIds = [];
            let sortMap = new Map(); // 存储 id -> sort 的映射
            
            if (isObjectArray) {
                // 对象数组格式,提取ID和排序信息
                areaIds = record.areas.map(area => {
                areaIds = areasData.map(area => {
                    const id = area.id;
                    sortMap.set(id, area.sort || 0);
                    return id;
                });
            } else {
                // 纯ID数组格式
                areaIds = record.areas.map(id => Number(id));
                areaIds = areasData.map(id => Number(id));
            }
            
            const res = await request.post(`/warehouseAreas/many/${areaIds.join(',')}`);
@@ -70,7 +71,8 @@
    };
    useEffect(() => {
        if (record?.areas && record.areas.length !== 0 && record.areas.length > 0) {
        const areasData = record?.areaIds || record?.areas;
        if (areasData && areasData.length > 0) {
            fetchAreaNames();
        }
    }, [record]);
@@ -101,10 +103,10 @@
                        label={`+${areaNames.length - 1}`}
                    />
                )}
                {areaNames.length === 0 && record.areas && record.areas.length > 0 && (
                {areaNames.length === 0 && (record?.areaIds || record?.areas) && (record?.areaIds || record?.areas).length > 0 && (
                    <Chip
                        size="small"
                        label={`${record.areas.length} 个区域`}
                        label={`${(record?.areaIds || record?.areas).length} 个区域`}
                    />
                )}
            </Stack>
rsf-admin/src/page/basicInfo/matnr/MatnrEdit.jsx
@@ -187,6 +187,13 @@
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.matnr.model"
                                        source="model"
                                        parse={v => v}
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.matnr.weight"
                                        source="weight"
rsf-admin/src/page/components/PageDrawer.jsx
@@ -23,26 +23,46 @@
        }
    }
    const isOpen = !!drawerVal;
    return (
        <Drawer
            variant="persistent"
            open={!!drawerVal}
            open={isOpen}
            anchor="right"
            onClose={handleClose}
            sx={{
                zIndex: 100,
                '& .MuiDrawer-paper': {
                    top: '86px', // AppBar(50px) + TabsBar(36px)
                    top: '86px', // AppBar(50px) + TabsBar(36px)
                    // 当关闭时,确保内容不可聚焦
                    ...(isOpen ? {} : {
                        pointerEvents: 'none',
                        visibility: 'hidden',
                    })
                }
            }}
            // 对于 persistent Drawer,使用 PaperProps 来控制可访问性
            PaperProps={{
                'aria-hidden': !isOpen,
                tabIndex: isOpen ? 0 : -1,
            }}
        >
            {!!drawerVal && (
                <Box pt={2} width={{ xs: '100vW', sm: width }} mt={{ xs: 2, sm: 1 }}>
            {isOpen && (
                <Box
                    pt={2}
                    width={{ xs: '100vW', sm: width }}
                    mt={{ xs: 2, sm: 1 }}
                >
                    <Stack direction="row" p={2}>
                        <Typography variant="h6" flex="1">
                            {title}
                        </Typography>
                        <IconButton onClick={handleClose} size="small">
                        <IconButton
                            onClick={handleClose}
                            size="small"
                            aria-label="关闭"
                        >
                            <CloseIcon />
                        </IconButton>
                    </Stack>
rsf-admin/src/page/task/TaskList.jsx
@@ -156,7 +156,7 @@
                    rowClick={false}
                    expand={<TaskPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy$', 'memo', 'robotCode', 'exceStatus', 'expDesc', 'expCode', 'status','warehType$']}
                    omit={['id', 'createTime', 'createBy$', 'memo', 'robotCode', 'exceStatus', 'expDesc', 'expCode', 'status','warehType$', 'orderType', 'order_type', 'orderType$']}
                >
                    <NumberField source="id" />
                    <TextField source="taskCode" label="table.field.task.taskCode" />
@@ -164,9 +164,9 @@
                    <NumberField source="taskType$" label="table.field.task.taskType" />
                    <NumberField source="warehType$" label="table.field.task.warehType" />
                    <TextField source="orgLoc" label="table.field.task.orgLoc" />
                    <TextField source="orgSite" label="table.field.task.orgSite" />
                    <TextField source="orgSite$" label="table.field.task.orgSite" />
                    <TextField source="targLoc" label="table.field.task.targLoc" />
                    <TextField source="targSite" label="table.field.task.targSite" />
                    <TextField source="targSite$" label="table.field.task.targSite" />
                    <TextField source="barcode" label="table.field.task.barcode" />
                    <TextField source="robotCode" label="table.field.task.robotCode" />
                    <NumberField source="exceStatus" label="table.field.task.exceStatus" />
rsf-open-api/src/main/java/com/vincent/rsf/openApi/controller/phyz/ERPController.java
@@ -2,17 +2,16 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.openApi.entity.dto.CommonResponse;
import com.vincent.rsf.openApi.entity.phyz.*;
import com.vincent.rsf.openApi.feign.wms.WmsServerFeignClient;
import com.vincent.rsf.openApi.feign.wms.fallback.WmsServerFeignClientFallback;
import com.vincent.rsf.openApi.service.phyz.ErpReportService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -20,6 +19,7 @@
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -153,9 +153,23 @@
        return CommonResponse.ok();
    }
    @ApiOperation("库存查询明细(表单提交)")
    @PostMapping(value = "/inventory/details", consumes = "application/x-www-form-urlencoded")
    public CommonResponse queryInventoryDetailsForm(HttpServletRequest request) {
        // 从表单参数构建查询条件
        InventoryQueryCondition condition = buildConditionFromRequestParams(request);
        // 调用JSON处理方法
        return queryInventoryDetails(condition);
    }
    @ApiOperation("库存查询明细")
    @PostMapping("/inventory/details")
    public CommonResponse queryInventoryDetails(@RequestBody InventoryQueryCondition condition) {
    @PostMapping(value = "/inventory/details", consumes = "application/json")
    public CommonResponse queryInventoryDetails(@RequestBody(required = false) InventoryQueryCondition condition) {
        // JSON方式:支持不传递参数({}或null或空请求体),创建默认的空查询条件对象
        if (condition == null) {
            condition = new InventoryQueryCondition();
        }
        if (SIMULATED_DATA_ENABLE.equals("1")) {
            String x = "[\n" +
                    "  {\n" +
@@ -207,11 +221,6 @@
                return CommonResponse.error("服务未初始化");
            }
            
            // 参数验证
            if (condition == null) {
                return CommonResponse.error("查询条件不能为空");
            }
            log.info("库存查询明细请求参数: {}", JSON.toJSONString(condition));
            
            // 直接传递实体类,Feign会自动序列化为JSON
@@ -247,87 +256,114 @@
            }
        } catch (Exception e) {
            log.error("库存查询明细失败", e);
            // 过滤错误消息中的URL,只保留错误类型
            String errorMessage = e.getMessage();
            if (errorMessage != null) {
                // 如果包含"executing",说明是HTTP请求错误,去掉URL部分
                if (errorMessage.contains("executing")) {
                    int executingIndex = errorMessage.indexOf("executing");
                    if (executingIndex > 0) {
                        // 提取"executing"之前的部分(如"Read timed out")
                        errorMessage = errorMessage.substring(0, executingIndex).trim();
                    } else {
                        // 如果"executing"在开头,使用默认错误消息
                        errorMessage = "请求超时";
                    }
                }
                // 如果包含"http://"或"https://",也尝试去掉URL部分
                else if (errorMessage.contains("http://") || errorMessage.contains("https://")) {
                    // 使用正则表达式去掉URL
                    errorMessage = errorMessage.replaceAll("https?://[^\\s]+", "").trim();
                    if (errorMessage.isEmpty()) {
                        errorMessage = "请求失败";
                    }
                }
            }
            return CommonResponse.error("查询失败:" + (errorMessage != null && !errorMessage.isEmpty() ? errorMessage : "未知错误"));
            String errorMessage = WmsServerFeignClientFallback.filterErrorMessage(e);
            return CommonResponse.error(errorMessage);
        }
    }
    @ApiOperation("库存查询汇总(表单提交)")
    @PostMapping(value = "/inventory/summary", consumes = "application/x-www-form-urlencoded")
    public CommonResponse queryInventorySummaryForm(HttpServletRequest request) {
        // 从表单参数构建查询条件
        InventoryQueryCondition condition = buildConditionFromRequestParams(request);
        // 调用JSON处理方法
        return queryInventorySummary(condition);
    }
    @ApiOperation("库存查询汇总")
    @PostMapping("/inventory/summary")
    public CommonResponse queryInventorySummary(@RequestBody JSONObject params) {
    @PostMapping(value = "/inventory/summary", consumes = "application/json")
    public CommonResponse queryInventorySummary(@RequestBody(required = false) InventoryQueryCondition condition) {
        // JSON方式:支持不传递参数({}或null或空请求体),创建默认的空查询条件对象
        if (condition == null) {
            condition = new InventoryQueryCondition();
        }
        if (SIMULATED_DATA_ENABLE.equals("1")) {
            String s = "{\n" +
                    "  \"code\": 200,\n" +
                    "  \"msg\": \"操作成功\",\n" +
                    "  \"data\": [\n" +
                    "    {\n" +
                    "      \"wareHouseId\": \"WH001\",\n" +
                    "      \"wareHouseName\": \"原料仓库\",\n" +
                    "      \"matNr\": \"MAT10001\",\n" +
                    "      \"makTx\": \"钢材Q235\",\n" +
                    "      \"spec\": \"国标GB/T700-2006\",\n" +
                    "      \"anfme\": 10.5,\n" +
                    "      \"unit\": \"吨\",\n" +
                    "      \"stockOrgId\": \"ORG001\",\n" +
                    "      \"batch\": \"BATCH20260106001\",\n" +
                    "      \"planNo\": \"Plan20260106006\"\n" +
                    "    },\n" +
                    "    {\n" +
                    "      \"wareHouseId\": \"WH001\",\n" +
                    "      \"wareHouseName\": \"原料仓库\",\n" +
                    "      \"matNr\": \"MAT10002\",\n" +
                    "      \"makTx\": \"铝型材6061\",\n" +
                    "      \"spec\": \"国标GB/T3190-2008\",\n" +
                    "      \"anfme\": 20.3,\n" +
                    "      \"unit\": \"吨\",\n" +
                    "      \"stockOrgId\": \"ORG001\",\n" +
                    "      \"batch\": \"BATCH20260106002\",\n" +
                    "      \"planNo\": \"Plan20260106005\"\n" +
                    "    },\n" +
                    "    {\n" +
                    "      \"wareHouseId\": \"WH002\",\n" +
                    "      \"wareHouseName\": \"成品仓库\",\n" +
                    "      \"matNr\": \"MAT30001\",\n" +
                    "      \"makTx\": \"电机成品\",\n" +
                    "      \"spec\": \"380V 50Hz 15KW\",\n" +
                    "      \"anfme\": 100,\n" +
                    "      \"unit\": \"台\",\n" +
                    "      \"stockOrgId\": \"ORG001\",\n" +
                    "      \"batch\": \"BATCH20260106003\",\n" +
                    "      \"planNo\": \"Plan20260106004\"\n" +
                    "    }\n" +
                    "  ]\n" +
                    "}";
            return JSONObject.parseObject(s, CommonResponse.class);
            String x = "[\n" +
                    "  {\n" +
                    "    \"wareHouseId\": \"WH001\",\n" +
                    "    \"wareHouseName\": \"原料仓库\",\n" +
                    "    \"matNr\": \"MAT10001\",\n" +
                    "    \"matTx\": \"钢材Q235\",\n" +
                    "    \"spec\": \"国标GB/T700-2006\",\n" +
                    "    \"anfme\": 10.5,\n" +
                    "    \"unit\": \"吨\",\n" +
                    "    \"stockOrgId\": \"ORG001\",\n" +
                    "    \"batch\": \"BATCH20260106001\",\n" +
                    "    \"planNo\": \"Plan20260106006\"\n" +
                    "  },\n" +
                    "  {\n" +
                    "    \"wareHouseId\": \"WH001\",\n" +
                    "    \"wareHouseName\": \"原料仓库\",\n" +
                    "    \"matNr\": \"MAT10002\",\n" +
                    "    \"matTx\": \"铝型材6061\",\n" +
                    "    \"spec\": \"国标GB/T3190-2008\",\n" +
                    "    \"anfme\": 20.3,\n" +
                    "    \"unit\": \"吨\",\n" +
                    "    \"stockOrgId\": \"ORG001\",\n" +
                    "    \"batch\": \"BATCH20260106002\",\n" +
                    "    \"planNo\": \"Plan20260106005\"\n" +
                    "  },\n" +
                    "  {\n" +
                    "    \"wareHouseId\": \"WH002\",\n" +
                    "    \"wareHouseName\": \"成品仓库\",\n" +
                    "    \"matNr\": \"MAT30001\",\n" +
                    "    \"matTx\": \"电机成品\",\n" +
                    "    \"spec\": \"380V 50Hz 15KW\",\n" +
                    "    \"anfme\": 100,\n" +
                    "    \"unit\": \"台\",\n" +
                    "    \"stockOrgId\": \"ORG001\",\n" +
                    "    \"batch\": \"BATCH20260106003\",\n" +
                    "    \"planNo\": \"Plan20260106004\"\n" +
                    "  }\n" +
                    "]";
            return CommonResponse.ok(JSONArray.parseArray(x, InventorySummary.class));
        }
        InventoryQueryCondition condition = JSON.parseObject(params.toJSONString(), InventoryQueryCondition.class);
        // 数据处理,转发server
        List<InventorySummary> inventorySummaries = Lists.newArrayList();
        return new CommonResponse().setCode(200).setData(inventorySummaries);
        try {
            if (wmsServerFeignClient == null) {
                log.warn("WmsServerFeignClient未注入,无法进行调用");
                return CommonResponse.error("服务未初始化");
            }
            log.info("库存查询汇总请求参数: {}", JSON.toJSONString(condition));
            // 直接传递实体类,Feign会自动序列化为JSON
            R result = wmsServerFeignClient.queryInventorySummary(condition);
            log.info("库存查询汇总返回结果: {}", JSON.toJSONString(result));
            if (result != null) {
                // R类继承自HashMap,使用get方法获取值
                Integer code = (Integer) result.get("code");
                String msg = (String) result.get("msg");
                Object data = result.get("data");
                if (code != null && code == 200) {
                    // 将Map列表转换为InventorySummary列表
                    if (data != null) {
                        @SuppressWarnings("unchecked")
                        List<Map<String, Object>> dataList = (List<Map<String, Object>>) data;
                        List<InventorySummary> inventorySummaries = new ArrayList<>();
                        for (Map<String, Object> item : dataList) {
                            InventorySummary summary = JSON.parseObject(JSON.toJSONString(item), InventorySummary.class);
                            inventorySummaries.add(summary);
                        }
                        return CommonResponse.ok(inventorySummaries);
                    } else {
                        return CommonResponse.ok(new ArrayList<>());
                    }
                } else {
                    return CommonResponse.error(msg != null ? msg : "查询失败");
                }
            } else {
                return CommonResponse.error("查询失败:返回结果为空");
            }
        } catch (Exception e) {
            log.error("库存查询汇总失败", e);
            String errorMessage = WmsServerFeignClientFallback.filterErrorMessage(e);
            return CommonResponse.error(errorMessage);
        }
    }
    @ApiOperation("盘点结果确认")
@@ -400,4 +436,47 @@
    }
    // endregion
    /**
     * 从请求参数(表单数据)构建查询条件对象
     * 支持 application/x-www-form-urlencoded 格式
     */
    private InventoryQueryCondition buildConditionFromRequestParams(HttpServletRequest request) {
        InventoryQueryCondition condition = new InventoryQueryCondition();
        // 从请求参数中获取字段值
        String wareHouseId = request.getParameter("wareHouseId");
        String locId = request.getParameter("locId");
        String matNr = request.getParameter("matNr");
        String matGroup = request.getParameter("matGroup");
        String orderNo = request.getParameter("orderNo");
        String planNo = request.getParameter("planNo");
        String batch = request.getParameter("batch");
        // 设置字段值(如果存在)
        if (wareHouseId != null && !wareHouseId.isEmpty()) {
            condition.setWareHouseId(wareHouseId);
        }
        if (locId != null && !locId.isEmpty()) {
            condition.setLocId(locId);
        }
        if (matNr != null && !matNr.isEmpty()) {
            condition.setMatNr(matNr);
        }
        if (matGroup != null && !matGroup.isEmpty()) {
            condition.setMatGroup(matGroup);
        }
        if (orderNo != null && !orderNo.isEmpty()) {
            condition.setOrderNo(orderNo);
        }
        if (planNo != null && !planNo.isEmpty()) {
            condition.setPlanNo(planNo);
        }
        if (batch != null && !batch.isEmpty()) {
            condition.setBatch(batch);
        }
        return condition;
    }
}
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/constant/WmsConstant.java
@@ -43,5 +43,8 @@
    //库存查询明细(ERP接口,对应open-api的/inventory/details)
    public static final String QUERY_INVENTORY_DETAILS = "/rsf-server/erp/inventory/details";
    //库存查询汇总(ERP接口,对应open-api的/inventory/summary)
    public static final String QUERY_INVENTORY_SUMMARY = "/rsf-server/erp/inventory/summary";
}
rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/phyz/InventorySummary.java
@@ -18,7 +18,7 @@
    // 物料编码
    private String matNr;
    // 物料名称
    private String makTx;
    private String matTx;
    // 规格
    private String spec;
    // 数量,小数点最长6位
rsf-open-api/src/main/java/com/vincent/rsf/openApi/feign/wms/WmsServerFeignClient.java
@@ -31,4 +31,12 @@
     */
    @PostMapping(WmsConstant.QUERY_INVENTORY_DETAILS)
    R queryInventoryDetails(@RequestBody InventoryQueryCondition condition);
    /**
     * 库存查询汇总(调用server端的erpQueryInventorySummary方法)
     * @param condition 查询条件实体类
     * @return 库存汇总列表
     */
    @PostMapping(WmsConstant.QUERY_INVENTORY_SUMMARY)
    R queryInventorySummary(@RequestBody InventoryQueryCondition condition);
}
rsf-open-api/src/main/java/com/vincent/rsf/openApi/feign/wms/fallback/WmsServerFeignClientFallback.java
@@ -15,7 +15,88 @@
    @Override
    public R queryInventoryDetails(InventoryQueryCondition condition) {
        log.error("调用WMS Server库存查询明细接口失败,触发降级处理");
        return R.error("服务调用失败,请稍后重试");
        return queryInventoryDetails(condition, null);
    }
    /**
     * 库存查询明细降级处理(带异常信息)
     * @param condition 查询条件
     * @param throwable 异常信息(可选)
     * @return 错误响应
     */
    public R queryInventoryDetails(InventoryQueryCondition condition, Throwable throwable) {
        log.error("调用WMS Server库存查询明细接口失败,触发降级处理", throwable);
        String errorMessage = filterErrorMessage(throwable);
        return R.error(errorMessage);
    }
    @Override
    public R queryInventorySummary(InventoryQueryCondition condition) {
        return queryInventorySummary(condition, null);
    }
    /**
     * 库存查询汇总降级处理(带异常信息)
     * @param condition 查询条件
     * @param throwable 异常信息(可选)
     * @return 错误响应
     */
    public R queryInventorySummary(InventoryQueryCondition condition, Throwable throwable) {
        log.error("调用WMS Server库存查询汇总接口失败,触发降级处理", throwable);
        String errorMessage = filterErrorMessage(throwable);
        return R.error(errorMessage);
    }
    /**
     * 过滤错误消息中的URL,只保留错误类型
     * @param throwable 异常对象(可选)
     * @return 过滤后的完整错误消息(包含"查询失败:"前缀)
     */
    public static String filterErrorMessage(Throwable throwable) {
        if (throwable == null) {
            return "查询失败:服务调用失败,请稍后重试";
        }
        return filterErrorMessage(throwable.getMessage());
    }
    /**
     * 过滤错误消息中的URL,只保留错误类型
     * @param errorMessage 错误消息字符串(可选)
     * @return 过滤后的完整错误消息(包含"查询失败:"前缀)
     */
    public static String filterErrorMessage(String errorMessage) {
        if (errorMessage == null || errorMessage.isEmpty()) {
            return "查询失败:未知错误";
        }
        String filteredMessage = errorMessage;
        // 如果包含"executing",说明是HTTP请求错误,去掉URL部分
        if (filteredMessage.contains("executing")) {
            int executingIndex = filteredMessage.indexOf("executing");
            if (executingIndex > 0) {
                // 提取"executing"之前的部分(如"Read timed out")
                filteredMessage = filteredMessage.substring(0, executingIndex).trim();
            } else {
                // 如果"executing"在开头,使用默认错误消息
                filteredMessage = "请求超时";
            }
        }
        // 如果包含"http://"或"https://",也尝试去掉URL部分
        else if (filteredMessage.contains("http://") || filteredMessage.contains("https://")) {
            // 使用正则表达式去掉URL
            filteredMessage = filteredMessage.replaceAll("https?://[^\\s]+", "").trim();
            if (filteredMessage.isEmpty()) {
                filteredMessage = "请求失败";
            }
        }
        // 如果过滤后的消息为空,使用默认错误消息
        if (filteredMessage.isEmpty()) {
            filteredMessage = "未知错误";
        }
        // 返回包含"查询失败:"前缀的完整错误消息
        return "查询失败:" + filteredMessage;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/WcsController.java
@@ -143,9 +143,9 @@
    @OperationLog("WCS任务上报通知")
    @PostMapping("/task/report")
    public R wcsTaskReport(@RequestBody TaskReportParam params) {
        if (params.getType() != 0){
            return wcsService.wcsTaskReport2(params);
        }
//        if (params.getType() != 0){
//            return wcsService.wcsTaskReport2(params);
//        }
        return wcsService.wcsTaskReport(params);
    }
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/ErpQueryController.java
@@ -121,4 +121,22 @@
        return receiveMsgService.erpQueryInventoryDetails(condition);
    }
    /**
     * ERP库存查询汇总(供open-api模块调用)
     * 对应open-api的 /inventory/summary 接口
     * @param condition 查询条件
     * @return 库存汇总列表
     */
    @PostMapping("/inventory/summary")
    @ApiOperation(value = "ERP库存查询汇总", hidden = true)
    @OperationLog("ERP库存查询汇总")
    public R erpQueryInventorySummary(@RequestBody InventoryQueryConditionParam condition) {
        // 参数验证
        if (condition == null) {
            return R.error("查询条件不能为空");
        }
        return receiveMsgService.erpQueryInventorySummary(condition);
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/enums/CallBackEvent.java
@@ -12,7 +12,6 @@
    CALL_BACK_EVENT_OBIT("OTBIN", "搬运中"),
    CALL_BACK_EVENT_BIN("BIN", "出站"),
    CALL_BACK_EVENT_END("END", "放箱完成"),
    CALL_BACK_EVENT_TRANSFER("TRANSFER", "中转"),
    ;
    CallBackEvent( String event,  String desc) {
rsf-server/src/main/java/com/vincent/rsf/server/api/service/ReceiveMsgService.java
@@ -159,4 +159,11 @@
     * @return 库存明细列表
     */
    R erpQueryInventoryDetails(InventoryQueryConditionParam condition);
    /**
     * 库存查询汇总(供open-api调用)
     * @param condition 查询条件
     * @return 库存汇总列表
     */
    R erpQueryInventorySummary(InventoryQueryConditionParam condition);
}
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/AgvServiceImpl.java
@@ -327,7 +327,7 @@
            throw new CoolException("站点状态不为空闲");
        }
        if (basStation.getType().equals(StationTypeEnum.STATION_TYPE_MUTI.type)) {
            throw new CoolException("站点为智能站点,禁止呼叫AGV");
            throw new CoolException("站点为光电站点,禁止呼叫AGV");
        }
        List<String> areaList = JSONObject.parseArray(basStation.getCrossZoneArea(), String.class);
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/InBoundServiceImpl.java
@@ -182,6 +182,9 @@
        }
        StringBuilder errorBuilder = new StringBuilder();
        List<Long> areaTypeList = LocUtils.getAreaTypeList(station.getStationName());
        if (areaTypeList.isEmpty()) {
            throw new CoolException("未查询到起点可入库区(库位规则未配置)!!!");
        }
        for (Long areaType : areaTypeList) {
            if (errorBuilder.length() > 0) {
                errorBuilder.append(",");
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
@@ -1200,4 +1200,186 @@
        return details;
    }
    /**
     * 库存查询汇总(供open-api调用)
     *
     * @param condition 查询条件实体类
     * @return 库存汇总列表
     */
    @Override
    public R erpQueryInventorySummary(InventoryQueryConditionParam condition) {
        try {
            // 参数验证
            if (condition == null) {
                return R.error("查询条件不能为空");
            }
            // 将ERP参数映射为数据库字段名(下划线格式)
            Map<String, Object> queryMap = new HashMap<>();
            // 从实体类中提取查询条件,映射为真实的数据库字段名
            if (StringUtils.isNotBlank(condition.getMatNr())) {
                queryMap.put("matnr_code", condition.getMatNr());
            }
            if (StringUtils.isNotBlank(condition.getPlanNo())) {
                queryMap.put("track_code", condition.getPlanNo());
            }
            if (StringUtils.isNotBlank(condition.getBatch())) {
                queryMap.put("batch", condition.getBatch());
            }
            BaseParam baseParam = new BaseParam();
            baseParam.syncMap(queryMap);
            PageParam<LocItem, BaseParam> pageParam = new PageParam<>(baseParam, LocItem.class);
            QueryWrapper<LocItem> wrapper = pageParam.buildWrapper(false);
            // 物料组(需要通过物料表关联查询)
            if (StringUtils.isNotBlank(condition.getMatGroup())) {
                // 调用物料Service查询物料组对应的物料ID列表(复用已有方法)
                LambdaQueryWrapper<Matnr> matnrWrapper = new LambdaQueryWrapper<>();
                matnrWrapper.eq(Matnr::getGroupId, condition.getMatGroup());
                List<Matnr> matnrs = matnrService.list(matnrWrapper);
                if (!matnrs.isEmpty()) {
                    List<Long> matnrIds = matnrs.stream().map(Matnr::getId).collect(Collectors.toList());
                    wrapper.in("matnr_id", matnrIds);
                } else {
                    // 如果没有找到物料,返回空结果
                    return R.ok().add(new ArrayList<>());
                }
            }
            // 只查询正常状态的库存(status=1表示正常)
            wrapper.eq("status", 1);
            // 设置分页参数,查询所有数据用于汇总
            pageParam.setCurrent(1);
            pageParam.setSize(Integer.MAX_VALUE);
            PageParam<LocItem, BaseParam> pageResult = locItemService.page(pageParam, wrapper);
            List<LocItem> locItems = pageResult.getRecords();
            if (locItems.isEmpty()) {
                return R.ok().add(new ArrayList<>());
            }
            // 获取所有需要关联的ID
            List<Long> locIds = locItems.stream()
                    .map(LocItem::getLocId)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());
            List<Long> warehouseIds = new ArrayList<>();
            // 调用LocService查询库位信息(复用Service层方法)
            Map<Long, Loc> locMap = new HashMap<>();
            if (!locIds.isEmpty()) {
                List<Loc> locs = locService.listByIds(locIds);
                locMap = locs.stream().collect(Collectors.toMap(Loc::getId, loc -> loc));
                // 收集仓库ID
                warehouseIds = locs.stream()
                        .map(Loc::getWarehouseId)
                        .filter(Objects::nonNull)
                        .distinct()
                        .collect(Collectors.toList());
            }
            // 仓库编码过滤
            if (StringUtils.isNotBlank(condition.getWareHouseId())) {
                String wareHouseId = condition.getWareHouseId();
                LambdaQueryWrapper<Warehouse> whWrapper = new LambdaQueryWrapper<>();
                whWrapper.eq(Warehouse::getCode, wareHouseId);
                // 调用WarehouseService查询仓库信息(复用Service层方法)
                List<Warehouse> warehouses = warehouseService.list(whWrapper);
                if (!warehouses.isEmpty()) {
                    Long targetWarehouseId = warehouses.get(0).getId();
                    // 过滤库位,只保留目标仓库的库位
                    locMap = locMap.entrySet().stream()
                            .filter(entry -> Objects.equals(entry.getValue().getWarehouseId(), targetWarehouseId))
                            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
                    // 过滤locItems,只保留目标仓库的
                    Set<Long> validLocIds = locMap.keySet();
                    locItems = locItems.stream()
                            .filter(item -> item.getLocId() != null && validLocIds.contains(item.getLocId()))
                            .collect(Collectors.toList());
                    warehouseIds = Collections.singletonList(targetWarehouseId);
                } else {
                    return R.ok().add(new ArrayList<>());
                }
            }
            // 调用WarehouseService查询仓库信息(复用Service层方法)
            Map<Long, Warehouse> warehouseMap = new HashMap<>();
            if (!warehouseIds.isEmpty()) {
                List<Warehouse> warehouses = warehouseService.listByIds(warehouseIds);
                warehouseMap = warehouses.stream().collect(Collectors.toMap(Warehouse::getId, wh -> wh));
            }
            // 按仓库、物料、批号、库存组织分组汇总
            // 使用Map的key作为分组键:wareHouseId_matNr_batch_stockOrgId
            Map<String, Map<String, Object>> summaryMap = new HashMap<>();
            for (LocItem locItem : locItems) {
                // 获取仓库信息
                Loc loc = null;
                if (locItem.getLocId() != null) {
                    loc = locMap.get(locItem.getLocId());
                }
                if (loc == null) {
                    continue;
                }
                Warehouse warehouse = null;
                if (loc.getWarehouseId() != null && warehouseMap.containsKey(loc.getWarehouseId())) {
                    warehouse = warehouseMap.get(loc.getWarehouseId());
                }
                if (warehouse == null) {
                    continue;
                }
                // 构建分组键:wareHouseId_matNr_batch_stockOrgId
                String wareHouseId = warehouse.getCode();
                String matNr = locItem.getMatnrCode();
                String batch = locItem.getBatch() != null ? locItem.getBatch() : "";
                String stockOrgId = locItem.getUseOrgId() != null ? locItem.getUseOrgId() : "";
                String groupKey = wareHouseId + "_" + matNr + "_" + batch + "_" + stockOrgId;
                // 如果该分组已存在,累加数量
                if (summaryMap.containsKey(groupKey)) {
                    Map<String, Object> summary = summaryMap.get(groupKey);
                    Double currentAnfme = (Double) summary.get("anfme");
                    Double newAnfme = currentAnfme + (locItem.getAnfme() != null ? locItem.getAnfme() : 0.0);
                    summary.put("anfme", newAnfme);
                } else {
                    // 创建新的汇总记录
                    Map<String, Object> summary = new HashMap<>();
                    summary.put("wareHouseId", wareHouseId);
                    summary.put("wareHouseName", warehouse.getName());
                    summary.put("matNr", matNr);
                    summary.put("matTx", locItem.getMaktx());
                    summary.put("spec", locItem.getSpec());
                    summary.put("unit", locItem.getUnit());
                    summary.put("anfme", locItem.getAnfme() != null ? locItem.getAnfme() : 0.0);
                    summary.put("batch", locItem.getBatch());
                    summary.put("stockOrgId", locItem.getUseOrgId());
                    summary.put("planNo", locItem.getTrackCode());
                    summaryMap.put(groupKey, summary);
                }
            }
            // 转换为列表
            List<Map<String, Object>> result = new ArrayList<>(summaryMap.values());
            return R.ok().add(result);
        } catch (Exception e) {
            log.error("库存查询汇总失败", e);
            return R.error("查询失败:" + e.getMessage());
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -31,8 +31,8 @@
import com.vincent.rsf.server.manager.service.impl.LocServiceImpl;
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.manager.enums.LocStsType;
import com.vincent.rsf.server.system.entity.User;
import com.vincent.rsf.server.system.service.impl.UserServiceImpl;
import com.vincent.rsf.server.system.entity.*;
import com.vincent.rsf.server.system.service.impl.*;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -86,6 +86,14 @@
    private RemotesInfoProperties.RcsApi rcsApi;
    @Autowired
    private UserServiceImpl userService;
    @Autowired
    private TaskInstanceServiceImpl taskInstanceService;
    @Autowired
    private TaskInstanceNodeServiceImpl taskInstanceNodeService;
    @Autowired
    private FlowStepInstanceServiceImpl flowStepInstanceService;
    @Autowired
    private FlowInstanceServiceImpl flowInstanceService;
    @Override
@@ -477,9 +485,40 @@
        if (Objects.isNull(task)) {
            throw new CoolException("任务不存在可以结束!!");
        }
        FlowStepInstance flowStepInstance = flowStepInstanceService.getOne(new LambdaQueryWrapper<FlowStepInstance>()
                .eq(FlowStepInstance::getTaskNo, task.getTaskCode())
                .eq(FlowStepInstance::getWmsNowTaskStatus, task.getTaskStatus())
                .eq(FlowStepInstance::getStatus, (short) 1).last("limit 1"));
        if (Cools.isEmpty(flowStepInstance)){
            return R.error(task.getTaskCode()+"任务号==>未查询到相关任务执行流程!!!");
        }
        if (!MissionStepType.getTaskRECEIVE().contains(flowStepInstance.getStepType())){
            return R.error(task.getTaskCode()+"任务号==>相关任务类型非接收型,步骤错乱!!!");
        }
        FlowInstance flowInstance = flowInstanceService.getById(flowStepInstance.getFlowInstanceId());
        if (Cools.isEmpty(flowInstance)) {
            return R.error(task.getTaskCode()+"任务号==>未查询到相关任务执行流程!!!");
        }
        List<FlowStepInstance> flowStepInstances = flowStepInstanceService.list(new LambdaQueryWrapper<FlowStepInstance>()
                .eq(FlowStepInstance::getFlowInstanceId, flowInstance.getId()).eq(FlowStepInstance::getStatus, (short) 0));
        flowInstance.setStatus(flowStepInstances.isEmpty()? (short) 2:(short) 1);
        TaskInstanceNode taskInstanceNode = taskInstanceNodeService.getById(flowInstance.getNodeInstanceId());
        if (Cools.isEmpty(taskInstanceNode)) {
            return R.error(task.getTaskCode()+"任务号==>未查询到相关任务执行流程!!!");
        }
        taskInstanceNode.setStatus(flowInstance.getStatus());
        TaskInstance taskInstance = taskInstanceService.getById(flowInstance.getTaskId());
        if (Cools.isEmpty(taskInstance)) {
            return R.error(task.getTaskCode()+"任务号==>未查询到相关任务执行流程!!!");
        }
        /**料箱搬运中, 修改站点状态*/
        if (params.getEventType().equals(CallBackEvent.CALL_BACK_EVENT_BIN.event)) {
            if (!flowStepInstance.getStepType().equals(MissionStepType.MISSION_STEP_TYPE_RECEIVE_BIN.type)) {
                return R.error(task.getTaskCode()+"任务号==>未查询到相关任务执行流程!!!");
            }
            if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)
@@ -504,92 +543,47 @@
                    || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_OUT.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_EMPTY_OUT.type)) {
                /**修改出库站点状态*/
                BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                        .eq(BasStation::getStationName, task.getOrgLoc()));
                if (Objects.isNull(station)) {
                    throw new CoolException("数据错误,站点不存在!!");
                }
                if (station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) {
                    station.setUseStatus(LocStsType.LOC_STS_TYPE_O.type);
                    station.setBarcode(null);
                    if (!basStationService.updateById(station)) {
                        throw new CoolException("站点状态修改失败!!");
                    }
                }
//                /**修改出库站点状态*/
//                BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
//                        .eq(BasStation::getStationName, task.getOrgLoc()));
//                if (Objects.isNull(station)) {
//                    throw new CoolException("数据错误,站点不存在!!");
//                }
//                if (station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) {
//                    station.setUseStatus(LocStsType.LOC_STS_TYPE_O.type);
//                    station.setBarcode(null);
//                    if (!basStationService.updateById(station)) {
//                        throw new CoolException("站点状态修改失败!!");
//                    }
//                }
            }
            /**取箱完成, 修改任务状态*/
        } else
        if (params.getEventType().equals(CallBackEvent.CALL_BACK_EVENT_END.event)) {
            if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_EMPTY_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) {
                if (!task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) {
                    BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, task.getOrgSite()));
                    if (Objects.isNull(station)) {
                        throw new CoolException("数据错误,站点不存在!!");
                    }
                    if (station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) {
                        station.setUseStatus(LocStsType.LOC_STS_TYPE_O.type);
                        if (!basStationService.updateById(station)) {
                            throw new CoolException("站点状态修改失败!!");
                        }
                    }
                }
                if (!taskService.update(new LambdaUpdateWrapper<Task>()
                        .lt(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id)
                        .eq(Task::getTaskCode, task.getTaskCode())
                        .set(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id))) {
                    throw new CoolException("任务状态修改失败!!");
                }
            } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_OUT.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_EMPTY_OUT.type)) {
                /**修改出库站点状态*/
                BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                        .eq(BasStation::getStationName, task.getTargSite()));
                if (Objects.isNull(station)) {
                    throw new CoolException("数据错误,站点不存在!!");
                }
                if (station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) {
                    station.setUseStatus(LocStsType.LOC_STS_TYPE_F.type);
                    if (!basStationService.updateById(station)) {
                        throw new CoolException("站点状态修改失败!!");
                    }
                }
                if (!taskService.update(new LambdaUpdateWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode())
                        .lt(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id)
                        .set(Task::getTaskStatus, TaskStsType.AWAIT.id))) {
                    throw new CoolException("任务状态修改失败!!");
                }
        } else if (params.getEventType().equals(CallBackEvent.CALL_BACK_EVENT_END.event)) {
            if (flowStepInstance.getStepType().equals(MissionStepType.MISSION_STEP_TYPE_RECEIVE_BIN.type)) {
                return R.error(task.getTaskCode()+"任务号==>请先出站请求!!!");
            }
        } else if (params.getEventType().equals(CallBackEvent.CALL_BACK_EVENT_TRANSFER.event)) {
            if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_EMPTY_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type)
                    || task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) {
                if (!taskService.update(new LambdaUpdateWrapper<Task>()
                        .lt(Task::getTaskStatus, TaskStsType.WCS_EXECUTE_IN.id)
                        .eq(Task::getTaskCode, task.getTaskCode())
                        .set(Task::getOrgSite, task.getTargSite())
                        .set(Task::getTaskStatus, TaskStsType.WCS_EXECUTE_IN.id))) {
                    throw new CoolException("任务状态修改失败!!");
                }
        }
        task.setTaskStatus(flowStepInstance.getWmsNextTaskStatus());
        flowStepInstance.setStatus((short)3);
        flowStepInstanceService.updateById(flowStepInstance);
        taskService.updateById(task);
        if (flowStepInstance.getWmsNextTaskStatus() != 9999) {
            FlowStepInstance nextFlowStepInstance = flowStepInstanceService.getOne(new LambdaQueryWrapper<FlowStepInstance>()
                    .eq(FlowStepInstance::getStatus, (short)0)
                    .eq(FlowStepInstance::getStepOrder, flowStepInstance.getStepOrder() + 1)
                    .eq(FlowStepInstance::getWmsNowTaskStatus, flowStepInstance.getWmsNextTaskStatus()));
            if (Cools.isEmpty(nextFlowStepInstance)) {
                return R.error(task.getTaskCode()+"任务号==>未查询到相关任务执行流程!!!");
            }
            nextFlowStepInstance.setStatus((short)1);
            flowStepInstanceService.updateById(nextFlowStepInstance);
        } else {
            taskInstance.setStatus((short)2);
            taskInstanceService.updateById(taskInstance);
        }
        log.info(JSONObject.toJSONString(params));
        return R.ok(JSONObject.toJSONString(params));
@@ -999,8 +993,8 @@
        }
        Task one = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, params.getBarcode()));
        if (!Cools.isEmpty(one)) {
            if (!one.getTaskStatus().equals(TaskStsType.WCS_EXECUTE_IN.id)) {
                return R.error("任务已存在但是状态不一致!!!").add("任务已存在但是状态不一致!!!");
            if (one.getTaskStatus().equals(TaskStsType.MISSION_TRANSFER.id)) {
                return R.error("任务已存在但是状态不一致!!!").add("任务已存在但是状态不一致!!!任务已完成!!!");
            }
            InTaskWcsReportParam inTaskWcsReportParam = new InTaskWcsReportParam();
            inTaskWcsReportParam.setTaskNo(one.getTaskCode());
@@ -1046,18 +1040,68 @@
        if (Objects.isNull(params)) {
            return R.error("参数不能为空!!");
        }
        Task one = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, params.getSuperTaskNo()));
        if (Cools.isEmpty(one)) {
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, params.getSuperTaskNo()));
        if (Cools.isEmpty(task)) {
            return R.error(params.getSuperTaskNo()+"任务号==>未查询到相关任务!!!");
        }
        if (params.getMsgType().equals(WcsMsgTypeEvent.TASK_COMPLETE.event)){
            if (!Cools.isEmpty(one)) {
                one.setTaskStatus(one.getTaskType() < 100 ? TaskStsType.COMPLETE_IN.id : TaskStsType.AWAIT.id);
                if (!taskService.updateById(one)) {
//                    throw new CoolException("完成任务失败");
                    return R.error("完成任务失败").add(one);
            if (!Cools.isEmpty(task)) {
                FlowStepInstance flowStepInstance = flowStepInstanceService.getOne(new LambdaQueryWrapper<FlowStepInstance>()
                        .eq(FlowStepInstance::getTaskNo, task.getTaskCode())
                        .eq(FlowStepInstance::getWmsNowTaskStatus, task.getTaskStatus())
                        .eq(FlowStepInstance::getStatus, (short) 1).last("limit 1"));
                if (Cools.isEmpty(flowStepInstance)){
                    return R.error(params.getSuperTaskNo()+"任务号==>未查询到相关任务执行流程!!!");
                }
                return R.ok("任务完成成功").add(one);
                if (!MissionStepType.getTaskRECEIVE().contains(flowStepInstance.getStepType())){
                    return R.error(params.getSuperTaskNo()+"任务号==>相关任务类型非接收型,步骤错乱!!!");
                }
                FlowInstance flowInstance = flowInstanceService.getById(flowStepInstance.getFlowInstanceId());
                if (Cools.isEmpty(flowInstance)) {
                    return R.error(params.getSuperTaskNo()+"任务号==>未查询到相关任务执行流程!!!");
                }
                List<FlowStepInstance> flowStepInstances = flowStepInstanceService.list(new LambdaQueryWrapper<FlowStepInstance>()
                        .eq(FlowStepInstance::getFlowInstanceId, flowInstance.getId()).eq(FlowStepInstance::getStatus, (short) 0));
                flowInstance.setStatus(flowStepInstances.isEmpty()? (short) 2:(short) 1);
                TaskInstanceNode taskInstanceNode = taskInstanceNodeService.getById(flowInstance.getNodeInstanceId());
                if (Cools.isEmpty(taskInstanceNode)) {
                    return R.error(params.getSuperTaskNo()+"任务号==>未查询到相关任务执行流程!!!");
                }
                taskInstanceNode.setStatus(flowInstance.getStatus());
                TaskInstance taskInstance = taskInstanceService.getById(flowInstance.getTaskId());
                if (Cools.isEmpty(taskInstance)) {
                    return R.error(params.getSuperTaskNo()+"任务号==>未查询到相关任务执行流程!!!");
                }
                task.setTaskStatus(flowStepInstance.getWmsNextTaskStatus());
                flowStepInstance.setStatus((short)3);
                flowStepInstanceService.updateById(flowStepInstance);
                taskService.updateById(task);
                if (flowStepInstance.getWmsNextTaskStatus() != 9999) {
                    FlowStepInstance nextFlowStepInstance = flowStepInstanceService.getOne(new LambdaQueryWrapper<FlowStepInstance>()
                            .eq(FlowStepInstance::getStatus, (short)0)
                            .eq(FlowStepInstance::getStepOrder, flowStepInstance.getStepOrder() + 1)
                            .eq(FlowStepInstance::getWmsNowTaskStatus, flowStepInstance.getWmsNextTaskStatus()));
                    if (Cools.isEmpty(nextFlowStepInstance)) {
                        return R.error(task.getTaskCode()+"任务号==>未查询到相关任务执行流程!!!");
                    }
                    nextFlowStepInstance.setStatus((short)1);
                    flowStepInstanceService.updateById(nextFlowStepInstance);
                } else {
                    taskInstance.setStatus((short)2);
                    taskInstanceService.updateById(taskInstance);
                }
                return R.ok("任务完成成功").add(task);
//                one.setTaskStatus(one.getTaskType() < 100 ? TaskStsType.COMPLETE_IN.id : TaskStsType.AWAIT.id);
//                if (!taskService.updateById(one)) {
////                    throw new CoolException("完成任务失败");
//                    return R.error("完成任务失败").add(one);
//                }
            }
        } else if (params.getMsgType().equals(WcsMsgTypeEvent.TASK_CANCEL.event)){
//            if (!Cools.isEmpty(one)) {
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/PageParam.java
@@ -8,7 +8,11 @@
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.DateUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
@@ -17,6 +21,7 @@
/**
 * Created by vincent on 2/13/2024
 */
@Slf4j
public class PageParam<T, U extends BaseParam> extends Page<T> {
    private static final long serialVersionUID = 1L;
@@ -31,6 +36,11 @@
    private final boolean isToUnderlineCase;
    private final Class<T> cls;
    /**
     * 额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证)
     */
    private List<Class<?>> additionalFieldClasses;
    public PageParam() {
        this(null);
@@ -129,7 +139,13 @@
        if (!Cools.isEmpty(where.getOrderBy())) {
            if (sortIsSQL(where.getOrderBy())) {
                setOrders(parseOrderSQL(where.getOrderBy()));
                List<OrderItem> orders = parseOrderSQL(where.getOrderBy());
                // 如果所有排序字段都无效,使用默认排序
                if (orders.isEmpty()) {
                    queryWrapper.orderByDesc("create_time");
                } else {
                    setOrders(orders);
                }
            }
        } else {
//            queryWrapper.orderByDesc("create_time");
@@ -221,7 +237,13 @@
        if (!Cools.isEmpty(where.getOrderBy())) {
            if (sortIsSQL(where.getOrderBy())) {
                setOrders(parseOrderSQL(where.getOrderBy()));
                List<OrderItem> orders = parseOrderSQL(where.getOrderBy());
                // 如果所有排序字段都无效,使用默认排序
                if (orders.isEmpty()) {
                    queryWrapper.orderByDesc("create_time");
                } else {
                    setOrders(orders);
                }
            }
        } else {
//            queryWrapper.orderByDesc("create_time");
@@ -282,10 +304,21 @@
    private List<OrderItem> parseOrderSQL(String orderSQL) {
        List<OrderItem> orders = new ArrayList<>();
        if (!Cools.isEmpty(orderSQL)) {
            // 获取实体类的有效字段列表
            Set<String> validColumns = getValidColumns();
            for (String item : orderSQL.split(",")) {
                String[] temp = item.trim().split(" ");
                if (!temp[0].isEmpty()) {
                    String column = this.isToUnderlineCase ? Utils.toSymbolCase(temp[0], '_') : temp[0];
                    // 验证字段是否存在,如果不存在则跳过
                    if (validColumns != null && !validColumns.isEmpty() && !validColumns.contains(column)) {
                        // 获取当前请求信息
                        String requestInfo = getRequestInfo();
//                        log.warn("跳过无效的排序字段: '{}' (原始值: '{}'),实体类: {},请求地址: {}",
//                                column, temp[0], cls != null ? cls.getSimpleName() : "null", requestInfo);
                        continue;
                    }
                    boolean asc = temp.length == 1 || !temp[temp.length - 1].toLowerCase().equals(ORDER_DESC_VALUE);
                    orders.add(new OrderItem(column, asc));
                }
@@ -294,6 +327,100 @@
        return orders;
    }
    /**
     * 获取当前请求信息(路径和方法)
     * @return 请求信息字符串,格式:HTTP方法 请求路径
     */
    private String getRequestInfo() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                if (request != null) {
                    String method = request.getMethod();
                    String uri = request.getRequestURI();
                    return String.format("%s %s", method, uri);
                }
            }
        } catch (Exception e) {
            // 忽略异常,避免影响主流程
            log.debug("获取请求信息失败: {}", e.getMessage());
        }
        return "未知";
    }
    /**
     * 获取实体类的有效字段列表(用于验证排序字段)
     * 包括:实体类字段、以及额外指定的DTO/VO类字段
     * 注意:BaseParam 的字段是查询参数,不用于数据库字段验证
     */
    private Set<String> getValidColumns() {
        Set<String> columns = new HashSet<>();
        // 1. 获取实体类(cls)的字段
        if (cls != null) {
            addFieldsFromClass(cls, columns);
        }
        // 2. 获取额外指定的类(DTO/VO等)的字段
        if (additionalFieldClasses != null && !additionalFieldClasses.isEmpty()) {
            for (Class<?> clazz : additionalFieldClasses) {
                addFieldsFromClass(clazz, columns);
            }
        }
        return columns.isEmpty() ? null : columns;
    }
    /**
     * 从指定类中提取字段并添加到集合中
     * @param clazz 要提取字段的类
     * @param columns 字段集合
     */
    private void addFieldsFromClass(Class<?> clazz, Set<String> columns) {
        for (Field field : Cools.getAllFields(clazz)) {
            // 跳过 final、static、transient 字段
            if (Modifier.isFinal(field.getModifiers())
                    || Modifier.isStatic(field.getModifiers())
                    || Modifier.isTransient(field.getModifiers())) {
                continue;
            }
            // 跳过标记为 exist=false 的字段(这些字段不存在于数据库中)
            if (field.isAnnotationPresent(TableField.class)) {
                TableField annotation = field.getAnnotation(TableField.class);
                if (!annotation.exist()) {
                    continue;
                }
            }
            String column = Utils.toSymbolCase(field.getName(), '_');
            columns.add(column);
        }
    }
    /**
     * 设置额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证)
     * @param classes 额外的类列表
     * @return 当前实例,支持链式调用
     */
    public PageParam<T, U> setAdditionalFieldClasses(Class<?>... classes) {
        if (classes != null && classes.length > 0) {
            this.additionalFieldClasses = Arrays.asList(classes);
        }
        return this;
    }
    /**
     * 设置额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证)
     * @param classes 额外的类列表
     * @return 当前实例,支持链式调用
     */
    public PageParam<T, U> setAdditionalFieldClasses(List<Class<?>> classes) {
        this.additionalFieldClasses = classes;
        return this;
    }
    public Map<String, Object> checkoutMap() {
        Map<String, Object> map = where.getMap();
        if (!Cools.isEmpty(where.getOrderBy())) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Task.java
@@ -34,7 +34,7 @@
import java.io.Serializable;
import java.util.Date;
import java.util.stream.Collectors;
import com.vincent.rsf.server.manager.service.BasStationService;
@Data
@Accessors(chain = true)
@TableName("man_task")
@@ -390,5 +390,36 @@
                return null;
        }
    }
    /**
     * 获取源站点名称(站点编号 + 站点名称)
     */
    public String getOrgSite$(){
        if (Cools.isEmpty(this.orgSite)) {
            return this.orgSite;
        }
        BasStationService basStationService = SpringUtils.getBean(BasStationService.class);
        BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                .eq(BasStation::getStationName, this.orgSite));
        if (!Cools.isEmpty(station) && !Cools.isEmpty(station.getStationId())) {
            return this.orgSite + "(" + station.getStationId() + ")";
        }
        return this.orgSite;
    }
    /**
     * 获取目标站点名称(站点编号 + 站点名称)
     */
    public String getTargSite$(){
        if (Cools.isEmpty(this.targSite)) {
            return this.targSite;
        }
        BasStationService basStationService = SpringUtils.getBean(BasStationService.class);
        BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                .eq(BasStation::getStationName, this.targSite));
        if (!Cools.isEmpty(station) && !Cools.isEmpty(station.getStationId())) {
            return this.targSite + "(" + station.getStationId() + ")";
        }
        return this.targSite;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/MissionStepType.java
@@ -1,5 +1,8 @@
package com.vincent.rsf.server.manager.enums;
import java.util.Arrays;
import java.util.List;
/**
 * @author Ryan
 * @version 1.0
@@ -10,13 +13,18 @@
public enum MissionStepType {
    MISSION_STEP_TYPE_RESPONSE("RESPONSE", "响应"),
    MISSION_STEP_TYPE_RECEIVE("RECEIVE", "接收"),
    MISSION_STEP_TYPE_RECEIVE_BIN("RECEIVE_BIN", "接收-解绑"),
    MISSION_STEP_TYPE_REQUEST("REQUEST", "请求"),
    MISSION_STEP_TYPE_BIND("BIND", "绑定"),
    MISSION_STEP_TYPE_UNBIND("UNBIND", "解绑"),
    MISSION_STEP_TYPE_VALIDATE("VALIDATE", "校验"),
    MISSION_STEP_TYPE_TRANSFORM("TRANSFORM", "转换"),
    MISSION_STEP_TYPE_BIND("BIND", "绑定"),
    MISSION_STEP_TYPE_OBTAIN("OBTAIN", "获取"),
    MISSION_STEP_TYPE_NO_EXECUTE("NO_EXECUTE", "越过"),
    MISSION_STEP_TYPE_VALIDATE("VALIDATE", "校验"),
    MISSION_STEP_TYPE_TRANSFORM("TRANSFORM", "转换"),
    ;
    public String type;
    public String desc;
@@ -26,4 +34,20 @@
        this.desc = desc;
    }
    public static List<String> getTaskISSUE(){
        return Arrays.asList(
                MissionStepType.MISSION_STEP_TYPE_REQUEST.type,
                MissionStepType.MISSION_STEP_TYPE_UNBIND.type,
                MissionStepType.MISSION_STEP_TYPE_BIND.type,
                MissionStepType.MISSION_STEP_TYPE_OBTAIN.type,
                MissionStepType.MISSION_STEP_TYPE_NO_EXECUTE.type);
    }
    public static List<String> getTaskRECEIVE(){
        return Arrays.asList(
                MissionStepType.MISSION_STEP_TYPE_RESPONSE.type,
                MissionStepType.MISSION_STEP_TYPE_RECEIVE_BIN.type,
                MissionStepType.MISSION_STEP_TYPE_RECEIVE.type);
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TaskStsType.java
@@ -36,38 +36,18 @@
    MISSION_TEMPLATE_EXECUTE_WCS_ONE1("1001", "1001.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_ONE2("1002", "1002.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE1("1003", "1003.RCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE2("1004", "1004.RCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_TWO1("1005", "1005.RCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_TWO2("1006", "1006.RCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_TWO1("1007", "1007.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_TWO2("1008", "1008.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_THREE1("1009", "1009.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_THREE2("1010", "1010.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_FOUR1("1011", "1011.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_FOUR2("1012", "1012.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_FIVE1("1013", "1013.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_FIVE2("1014", "1014.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_THREE1("1015", "1015.RCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_THREE2("1016", "1016.RCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_SIX1("1017", "1017.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_SIX2("1018", "1018.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_SEVEN1("1019", "1019.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_SEVEN2("1020", "1020.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_FOUR1("1021", "1021.RCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_FOUR2("1022", "1022.RCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_FIVE1("1023", "1023.RCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_FIVE2("1024", "1024.RCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_EIGHT1("1025", "1025.WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_EIGHT2("1026", "1026.WCS作业中等待上报完成"),
    MISSION_TEMPLATE_NO_EXECUTE1("1027", "1027.不执行任务"),
    MISSION_TEMPLATE_WEIGHING_ONE2("1028", "1028.称重作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_WCS_ONE11("1001", "WCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_WCS_ONE22("1002", "WCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE11("1003", "RCS请求下发中"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE12("1004", "RCS作业中等待上报完成"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE13("1005", "等待RCS出站反馈"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE3("1029", "1029.RCS绑定数据"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE4("1030", "1030.RCS解绑数据"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE3("1101", "RCS绑定数据"),
    MISSION_TEMPLATE_EXECUTE_HK_RCS_ONE4("1102", "RCS解绑数据"),
    MISSION_TEMPLATE_WEIGHING_ONE2("1901", "称重作业中等待上报完成"),
    MISSION_TEMPLATE_NO_EXECUTE1("9998", "1005.不执行任务"),
    MISSION_TRANSFER("9999", "9999.任务完成中"),
    ;
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskMissionSchedules.java
@@ -101,6 +101,10 @@
                Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc()));
                sou = loc.getAreaId().toString();
                end = task.getTargSite();
            } else if (task.getTaskType().equals(TaskType.TASK_TYPE_CROSS_DOCKING_OUT.type)){
                Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc()));
                sou = loc.getAreaId().toString();
                end = loc.getAreaId().toString();
            }
            List<TaskPathTemplateMerge> taskPathTemplateMergeList = taskPathTemplateMergeService.list(new LambdaQueryWrapper<TaskPathTemplateMerge>().eq(TaskPathTemplateMerge::getSourceType, sou).eq(TaskPathTemplateMerge::getTargetType, end));
            if (Objects.isNull(taskPathTemplateMergeList) || taskPathTemplateMergeList.isEmpty()) {
@@ -156,7 +160,7 @@
            }
            List<TaskPathTemplateNode> taskPathTemplateNodeList = taskPathTemplateNodeService.list(
                    new LambdaQueryWrapper<TaskPathTemplateNode>()
                            .eq(TaskPathTemplateNode::getTemplateId, taskPathTemplate.getId()));
                            .eq(TaskPathTemplateNode::getTemplateId, taskPathTemplate.getId()).orderByAsc(TaskPathTemplateNode::getNodeOrder));
            for (TaskPathTemplateNode taskPathTemplateNode : taskPathTemplateNodeList) {
                List<SubsystemFlowTemplate> subsystemFlowTemplateList = subsystemFlowTemplateService.list(
@@ -167,7 +171,7 @@
                for (SubsystemFlowTemplate subsystemFlowTemplate : subsystemFlowTemplateList) {
                    List<FlowStepTemplate> flowStepTemplateList = flowStepTemplateService.list(
                            new LambdaQueryWrapper<FlowStepTemplate>()
                                    .eq(FlowStepTemplate::getFlowId, subsystemFlowTemplate.getId()));
                                    .eq(FlowStepTemplate::getFlowId, subsystemFlowTemplate.getId()).orderByAsc(FlowStepTemplate::getStepOrder));
                    allFlowStepTemplates.addAll(flowStepTemplateList);
                }
@@ -190,7 +194,7 @@
            }
            List<TaskPathTemplateNode> taskPathTemplateNodeList = taskPathTemplateNodeService.list(
                    new LambdaQueryWrapper<TaskPathTemplateNode>()
                            .eq(TaskPathTemplateNode::getTemplateId, taskPathTemplate.getId()));
                            .eq(TaskPathTemplateNode::getTemplateId, taskPathTemplate.getId()).orderByAsc(TaskPathTemplateNode::getNodeOrder));
            for (TaskPathTemplateNode taskPathTemplateNode : taskPathTemplateNodeList) {
                TaskInstanceNode taskInstanceNode = new TaskInstanceNode(taskPathTemplateNode);
@@ -217,7 +221,7 @@
                    List<FlowStepTemplate> flowStepTemplateList = flowStepTemplateService.list(
                            new LambdaQueryWrapper<FlowStepTemplate>()
                                    .eq(FlowStepTemplate::getFlowId, subsystemFlowTemplate.getId()));
                                    .eq(FlowStepTemplate::getFlowId, subsystemFlowTemplate.getId()).orderByAsc(FlowStepTemplate::getStepOrder));
                    for (FlowStepTemplate flowStepTemplate : flowStepTemplateList) {
                        j++;
@@ -227,21 +231,21 @@
                        flowStepInstance.setStepOrder(j);
                        flowStepInstance.setStepCode(String.valueOf(snowflakeIdWorker.nextId()));
                        flowStepInstance.setWmsNowTaskStatus(flowStepTemplate.getWmsNowTaskStatus());
                        flowStepInstance.setTaskNo(taskInstance.getTaskNo());
                        // 判断是否是最后一个
                        if (globalIndex < allFlowStepTemplates.size() - 1) {
                            // 不是最后一个,取下一个的WmsNowTaskStatus
                            FlowStepTemplate nextFlowStep = allFlowStepTemplates.get(globalIndex + 1);
                            flowStepInstance.setWmsNextTaskStatus(nextFlowStep.getWmsNowTaskStatus());
                            if (globalIndex == 0){
                                task.setTaskStatus(flowStepTemplate.getWmsNowTaskStatus());
                                flowStepInstance.setStatus((short)1);
                            }
                        } else {
                            // 是最后一个,设置为9999
                            flowStepInstance.setWmsNextTaskStatus(9999);
                        }
                        if (globalIndex == 0){
                            task.setTaskStatus(flowStepTemplate.getWmsNowTaskStatus());
                            flowStepInstance.setStatus((short)1);
                        }
                        flowStepInstanceService.save(flowStepInstance);
                        globalIndex++; // 更新全局索引
                    }
rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/TaskSchedules.java
@@ -113,19 +113,17 @@
    @Scheduled(cron = "0/2 * * * * ?  ")
    @Transactional(rollbackFor = Exception.class)
    public void missionTaskEXECUTE() {
        List<String> typeList = Arrays.asList(
                MissionStepType.MISSION_STEP_TYPE_REQUEST.type,
                MissionStepType.MISSION_STEP_TYPE_UNBIND.type,
                MissionStepType.MISSION_STEP_TYPE_BIND.type,
                MissionStepType.MISSION_STEP_TYPE_OBTAIN.type,
                MissionStepType.MISSION_STEP_TYPE_NO_EXECUTE.type);
        List<FlowStepInstance> flowStepInstanceList = flowStepInstanceService.list(new LambdaQueryWrapper<FlowStepInstance>()
                .eq(FlowStepInstance::getStatus, 1).in(FlowStepInstance::getStepType,typeList));
                .eq(FlowStepInstance::getStatus, 1).in(FlowStepInstance::getStepType,MissionStepType.getTaskISSUE()));
        for (FlowStepInstance flowStepInstance : flowStepInstanceList) {
            FlowInstance flowInstance = flowInstanceService.getById(flowStepInstance.getFlowInstanceId());
            if (Cools.isEmpty(flowInstance)) { continue;}
            List<FlowStepInstance> flowStepInstances = flowStepInstanceService.list(new LambdaQueryWrapper<FlowStepInstance>()
                    .eq(FlowStepInstance::getFlowInstanceId, flowInstance.getId()).eq(FlowStepInstance::getStatus, (short) 0));
            flowInstance.setStatus(flowStepInstances.isEmpty()? (short) 2:(short) 1);
            TaskInstanceNode taskInstanceNode = taskInstanceNodeService.getById(flowInstance.getNodeInstanceId());
            if (Cools.isEmpty(taskInstanceNode)) { continue;}
            taskInstanceNode.setStatus(flowInstance.getStatus());
            TaskInstance taskInstance = taskInstanceService.getById(flowInstance.getTaskId());
            if (Cools.isEmpty(taskInstance)) { continue;}
            Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, taskInstance.getTaskNo()));
@@ -147,14 +145,21 @@
                    if (flowStepInstance.getWmsNextTaskStatus() != 9999) {
                        FlowStepInstance nextFlowStepInstance = flowStepInstanceService.getOne(new LambdaQueryWrapper<FlowStepInstance>()
                                .eq(FlowStepInstance::getFlowInstanceId, flowStepInstance.getFlowInstanceId())
                                .eq(FlowStepInstance::getFlowInstanceNo, flowStepInstance.getFlowInstanceNo())
                                .eq(FlowStepInstance::getStatus, (short)0)
                                .eq(FlowStepInstance::getStepOrder, flowStepInstance.getStepOrder() + 1)
                                .eq(FlowStepInstance::getWmsNowTaskStatus, flowStepInstance.getWmsNextTaskStatus()));
                        if (Cools.isEmpty(nextFlowStepInstance)) {
                            throw new CoolException("任务号"+task.getTaskCode()+"任务步骤丢失!!!");
                        }
                        nextFlowStepInstance.setStatus((short)1);
                        flowStepInstanceService.updateById(nextFlowStepInstance);
                    } else {
                        taskInstance.setStatus((short)2);
                        taskInstanceService.updateById(taskInstance);
                    }
                    flowInstanceService.updateById(flowInstance);
                    taskInstanceNodeService.updateById(taskInstanceNode);
                } catch (Exception e) {
                    throw new CoolException(e.getMessage());
                }
@@ -192,13 +197,18 @@
                            if (flowStepInstance.getWmsNextTaskStatus() != 9999) {
                                FlowStepInstance nextFlowStepInstance = flowStepInstanceService.getOne(new LambdaQueryWrapper<FlowStepInstance>()
                                        .eq(FlowStepInstance::getFlowInstanceId, flowStepInstance.getFlowInstanceId())
                                        .eq(FlowStepInstance::getFlowInstanceNo, flowStepInstance.getFlowInstanceNo())
                                        .eq(FlowStepInstance::getStatus, (short)0)
                                        .eq(FlowStepInstance::getStepOrder, flowStepInstance.getStepOrder() + 1)
                                        .eq(FlowStepInstance::getWmsNowTaskStatus, flowStepInstance.getWmsNextTaskStatus()));
                                if (Cools.isEmpty(nextFlowStepInstance)) {
                                    throw new CoolException("任务号"+task.getTaskCode()+"任务步骤丢失!!!");
                                }
                                nextFlowStepInstance.setStatus((short)1);
                                flowStepInstanceService.updateById(nextFlowStepInstance);
                            } else {
                                taskInstance.setStatus((short)2);
                                taskInstanceService.updateById(taskInstance);
                            }
                        } else {
                            flowStepInstance.setRetryTimes(flowStepInstance.getRetryTimes() + 1);
@@ -237,7 +247,7 @@
    public void completeStock9999() throws Exception {
        try{
            List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getTaskStatus, TaskStsType.MISSION_TRANSFER.id).select(Task::getId));
            List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getTaskStatus, TaskStsType.MISSION_TRANSFER.id));
            if (tasks.isEmpty()) {
                return;
            }
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -217,14 +217,25 @@
                    }
                    task.setTaskType(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type).setWarehType(deviceSite.getDevice());
                } else {
                    //全板出库
                    DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                            .eq(!Objects.isNull(loc.getChannel()), DeviceSite::getChannel, loc.getChannel())
                            .eq(DeviceSite::getSite, siteNo).eq(DeviceSite::getType, TaskType.TASK_TYPE_OUT.type));
                    if (Objects.isNull(deviceSite)) {
                        throw new CoolException("站点不支持全板出库!!");
                    if (resouce.equals(TaskResouceType.TASK_RESOUCE_STOCK_UP.val)){
                        //全板出库
                        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                                .eq(DeviceSite::getSite, siteNo).eq(DeviceSite::getType, TaskType.TASK_TYPE_CROSS_DOCKING_OUT.type));
//                                .eq(!Objects.isNull(loc.getChannel()), DeviceSite::getChannel, loc.getChannel())
                        if (Objects.isNull(deviceSite)) {
                            throw new CoolException("站点不支持越库!!");
                        }
                        task.setTaskType(TaskType.TASK_TYPE_CROSS_DOCKING_OUT.type).setWarehType(deviceSite.getDevice());//越库
                    } else {
                        //全板出库
                        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                                .eq(DeviceSite::getSite, siteNo).eq(DeviceSite::getType, TaskType.TASK_TYPE_OUT.type));
//                                .eq(!Objects.isNull(loc.getChannel()), DeviceSite::getChannel, loc.getChannel())
                        if (Objects.isNull(deviceSite)) {
                            throw new CoolException("站点不支持全板出库!!");
                        }
                        task.setTaskType(TaskType.TASK_TYPE_OUT.type).setWarehType(deviceSite.getDevice());
                    }
                    task.setTaskType(TaskType.TASK_TYPE_OUT.type).setWarehType(deviceSite.getDevice());
                }
            } else if (map.getType().equals(Constants.TASK_TYPE_OUT_CHECK)) {
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -518,8 +518,8 @@
                WkOrderItem orderItem = outStockItemService.getOne(new LambdaQueryWrapper<WkOrderItem>()
                        .eq(WkOrderItem::getOrderId, outId)
                        .eq(StringUtils.isNotBlank(locItem.getBatch()), WkOrderItem::getSplrBatch, locItem.getBatch())
                        .eq(StringUtils.isNotBlank(locItem.getFieldsIndex()), WkOrderItem::getFieldsIndex, locItem.getFieldsIndex())
                        .eq(WkOrderItem::getMatnrId, locItem.getMatnrId()));
//                        .eq(StringUtils.isNotBlank(locItem.getFieldsIndex()), WkOrderItem::getFieldsIndex, locItem.getFieldsIndex())
                if (Objects.isNull(orderItem)) {
                    throw new CoolException("单据明细不存在!!");
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -154,7 +154,7 @@
                    .setTaskType(TaskType.TASK_TYPE_IN.type)
                    .setWarehType(WarehType.WAREHOUSE_TYPE_AGV.val)
                    .setTargLoc(targetLoc)
                    .setTargSite(targSite)
                    //.setTargSite(targSite)//入库没有目标站点
                    .setOrgSite(orgSta)
                    .setBarcode(pakin.getBarcode())
                    .setCreateBy(loginUserId)
@@ -366,7 +366,7 @@
            }
            Task task = new Task();
            task.setTaskCode(ruleCode)
                    .setTaskStatus(TaskStsType.MISSION_INITIAL.id)
                    .setTaskStatus(TaskStsType.GENERATE_IN.id)
                    .setTaskType(TaskType.TASK_TYPE_IN.type)
                    .setResource(TaskResouceType.TASK_RESOUCE_PAKIN_TYPE.val)
                    .setTargLoc(targetLoc)
@@ -664,7 +664,7 @@
                }
                Task task = new Task();
                task.setTaskCode(ruleCode)
                        .setTaskStatus(TaskStsType.WCS_EXECUTE_IN.id)
                        .setTaskStatus(TaskStsType.MISSION_INITIAL.id)
                        .setTaskType(TaskType.TASK_TYPE_IN.type)
                        .setResource(TaskResouceType.TASK_RESOUCE_PAKIN_TYPE.val)
                        .setTargLoc(targetLoc)
@@ -761,6 +761,9 @@
                } else if (task.getTaskType().equals(TaskType.TASK_TYPE_EMPTY_IN.type)) {
                    //移库
                    complateInstockE(task, loginUserId);
                } else if (task.getTaskType().equals(TaskType.TASK_TYPE_CROSS_DOCKING_OUT.type)) {
                    //越库
                    complateInstockDocking(task, loginUserId);
                }
            }
        }
@@ -776,7 +779,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Task taskToTop(Long id, Long loginUserId) throws Exception {
        List<Integer> longs = Arrays.asList(TaskStsType.MISSION_INITIAL.id, TaskStsType.MISSION_INITIAL.id);
        List<Integer> longs = Arrays.asList(TaskStsType.GENERATE_IN.id, TaskStsType.GENERATE_OUT.id);
        Task tasks = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getId, id).in(Task::getTaskStatus, longs));
        if (Objects.isNull(tasks)) {
            throw new CoolException("任务已处执行状态不可一键置顶!!");
@@ -800,7 +803,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Task operateComplete(Long id, Long loginUserId) {
        List<Integer> longs = Arrays.asList(TaskStsType.MISSION_INITIAL.id, TaskStsType.MISSION_INITIAL.id);
        List<Integer> longs = Arrays.asList(TaskStsType.GENERATE_IN.id, TaskStsType.GENERATE_OUT.id);
        Task task = taskService.getOne(new LambdaQueryWrapper<Task>()
                .eq(Task::getId, id)
                .in(Task::getTaskStatus, longs));
@@ -984,6 +987,9 @@
                if (task.getTaskType().equals(TaskType.TASK_TYPE_EMPTY_OUT.type)) {
                    //110.空板出库
                    complateOutStockEmpty(task, loginUserId);
                } else if (task.getTaskType().equals(TaskType.TASK_TYPE_CROSS_DOCKING_OUT.type)) {
                    //110.空板出库
                    complateOutStockDocking(task, loginUserId);
                } else {
                    complateOutStock(task, loginUserId);
                }
@@ -1062,6 +1068,50 @@
    }
    /**
     * 越库回库
     *
     * @param task
     * @param loginUserId
     */
    @Transactional(rollbackFor = Exception.class)
    public void complateInstockDocking(Task task, Long loginUserId) {
        if (Objects.isNull(task)) {
            return;
        }
        Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getTargLoc()));
        if (Objects.isNull(loc)) {
            throw new CoolException("库存不存在!!");
        }
//        if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_S.type)) {
//            throw new CoolException("当前库位状态不处于S.入库预约,不可执行入库操作!");
//        }
        loc.setUseStatus(LocStsType.LOC_STS_TYPE_F.type)
                .setBarcode(task.getBarcode())
                .setUpdateBy(loginUserId).setUpdateTime(new Date());
        if (!locService.updateById(loc)) {
            throw new CoolException("库位信息更新失败!!");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (taskItems.isEmpty()) {
            throw new CoolException("任务明细不存在!!");
        }
        TaskItem taskItem = taskItems.stream().findFirst().get();
        //保存入出库流水
        saveStockItems(taskItems, task, null, null, taskItem.getWkType(), OrderType.ORDER_IN.type, loginUserId);
        locItemWorkingService.remove(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId()));
        task.setTaskStatus(TaskStsType.UPDATED_IN.id).setUpdateTime(new Date()).setUpdateBy(loginUserId);
        if (!taskService.updateById(task)) {
            throw new CoolException("任务状态修改失败!!");
        }
    }
    /**
     * 任务取消
     *
     * @param ids
@@ -1071,7 +1121,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R removeTask(Long[] ids, Long loginUserId) {
        List<Integer> longs = Arrays.asList(TaskStsType.MISSION_INITIAL.id, TaskStsType.MISSION_INITIAL.id);
        List<Integer> longs = Arrays.asList(TaskStsType.GENERATE_IN.id, TaskStsType.GENERATE_OUT.id);
        List<Integer> list = Arrays.asList(TaskType.TASK_TYPE_IN.type, TaskType.TASK_TYPE_OUT.type, TaskType.TASK_TYPE_PICK_AGAIN_OUT.type,
                TaskType.TASK_TYPE_CHECK_OUT.type, TaskType.TASK_TYPE_EMPTY_IN.type, TaskType.TASK_TYPE_LOC_MOVE.type,
                TaskType.TASK_TYPE_EMPTY_OUT.type, TaskType.TASK_TYPE_MERGE_OUT.type);
@@ -1084,7 +1134,7 @@
        }
        for (Task task : tasks) {
            //取消移库任务
            if (task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type) && task.getTaskStatus().equals(TaskStsType.MISSION_INITIAL.id)) {
            if (task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type) && task.getTaskStatus().equals(TaskStsType.GENERATE_IN.id)) {
                if (!locService.update(new LambdaUpdateWrapper<Loc>()
                        .eq(Loc::getCode, task.getOrgLoc())
                        .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_F.type))) {
@@ -1312,7 +1362,7 @@
        task.setTaskCode(ruleCode)
                .setTaskType(type)
                .setBarcode(task.getBarcode())
                .setTaskStatus(TaskStsType.MISSION_INITIAL.id);
                .setTaskStatus(TaskStsType.GENERATE_IN.id);
        TaskInParam param = new TaskInParam();
        param.setSourceStaNo(task.getTargSite())
@@ -1572,6 +1622,100 @@
     */
    @Synchronized
    @Transactional(rollbackFor = Exception.class)
    public void complateOutStockDocking(Task task, Long loginUserId) throws Exception {
        if (Objects.isNull(task)) {
            throw new CoolException("参数不能为空!!");
        }
        Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc()));
        if (Objects.isNull(loc)) {
            throw new CoolException("库位不存在!!");
        }
        if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_R.type)) {
            throw new CoolException("库位状态不处理于R.出库预约!!");
        }
        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
        if (taskItems.isEmpty()) {
            throw new CoolException("任务明细不存在!!");
        }
        List<LocItem> locItems = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, loc.getId()));
        if (locItems.isEmpty()) {
            throw new CoolException("库位明细不存在!!");
        }
        List<LocItemWorking> workings = new ArrayList<>();
        for (LocItem item : locItems) {
            LocItemWorking working = new LocItemWorking();
            BeanUtils.copyProperties(item, working);
            working.setId(null)
                    .setTaskId(task.getId())
                    .setLocItemId(item.getId())
                    .setUpdateBy(loginUserId)
                    .setUpdateTime(new Date());
            workings.add(working);
        }
        //添加出入库记录信息
        Map<Short, List<TaskItem>> listMap = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getWkType));
        /***获取库存出库值,如果为空表示正常单据出库,非空表明是库存出库
         * 1. 库存出库没有单据信息,单据信息默认为空
         * 2. 单据库存需通过波次查询原始单据信息,将单据信息填入stock中
         * */
        List<TaskItem> list = listMap.get(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type));
        if (Objects.isNull(list) || list.isEmpty()) {
            Map<Long, List<TaskItem>> maps = taskItems.stream().collect(Collectors.groupingBy(TaskItem::getSource));
            maps.keySet().forEach(key -> {
                if (task.getResource().equals(TaskResouceType.TASK_RESOUCE_STOCK_UP.val)) {
                    WkOrderItem orderItem = asnOrderItemService.getById(key);
                    if (Objects.isNull(orderItem)) {
                        throw new CoolException("单据明细不存在!!");
                    }
                    try {
                        saveOutStockItem(maps.get(key), orderItem,  loginUserId);
                    } catch (Exception e) {
                        throw new CoolException(e.getMessage());
                    }
                }
            });
        } else {
            try {
                saveOutStockItem(taskItems, null, null, null, loginUserId);
            } catch (Exception e) {
                throw new CoolException(e.getMessage());
            }
        }
        /**修改为库位状态为O.空库*/
        if (!locService.update(new LambdaUpdateWrapper<Loc>()
                .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_S.type)
                .set(Loc::getBarcode, loc.getBarcode())
                .set(Loc::getUpdateBy, loginUserId)
                .set(Loc::getUpdateTime, new Date())
                .eq(Loc::getId, loc.getId()))) {
            throw new CoolException("库位状态修改失败!!");
        }
        if (!this.update(new LambdaUpdateWrapper<Task>()
                .eq(Task::getId, task.getId())
                .set(Task::getUpdateBy, loginUserId)
                .set(Task::getUpdateTime, new Date())
                .set(Task::getTargLoc, task.getOrgLoc())
                .set(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id))) {
            throw new CoolException("库存状态更新失败!!");
        }
    }
    /**
     * @author Ryan
     * @date 2025/5/20
     * @description: 完成出库任务,更新出库库存信息
     * @version 1.0
     */
    @Synchronized
    @Transactional(rollbackFor = Exception.class)
    public void complateOutStockEmpty(Task task, Long loginUserId) throws Exception {
        if (Objects.isNull(task)) {
            throw new CoolException("参数不能为空!!");
@@ -1693,7 +1837,7 @@
        if (Objects.isNull(ids) || ids.isEmpty()) {
            return R.error("任务编码不能为空!!");
        }
        List<Integer> integers = Arrays.asList(TaskStsType.MISSION_INITIAL.id, TaskStsType.MISSION_INITIAL.id);
        List<Integer> integers = Arrays.asList(TaskStsType.GENERATE_IN.id, TaskStsType.GENERATE_OUT.id);
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>()
                .in(Task::getId, ids)
                .in(Task::getTaskStatus, integers)
@@ -1739,7 +1883,7 @@
                }
            }
            /**判断是否智能站点,非光店站点需管控站点状态*/
            /**判断是否光电站点,非光店站点需管控站点状态*/
            if (!Objects.isNull(station) && station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) {
                if (task.getTaskType() <= TaskType.TASK_TYPE_CHECK_IN.type && !task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) {
                    station.setUseStatus(LocStsType.LOC_STS_TYPE_R.type);
rsf-server/src/main/java/com/vincent/rsf/server/system/entity/FlowStepInstance.java
@@ -152,6 +152,12 @@
    @ApiModelProperty(value= "wms当前任务类型ID")
    private Integer wmsNowTaskStatus;
    /**
     * 任务号
     */
    @ApiModelProperty(value= "任务号")
    private String taskNo;
    public FlowStepInstance() {}
    public FlowStepInstance(FlowStepTemplate  flowStepTemplate) {
        this.stepTemplateId = flowStepTemplate.getId();