gongchunyi
2 小时以前 7ea8883ca6b47ec014a32ed57c3bea64544e893e
feat: 生产订单绑定工艺路线、BOM、工艺路线、工序参数新增修改
已添加3个文件
已修改29个文件
已删除6个文件
1268 ■■■■ 文件已修改
doc/宁夏-中盛建材.sql 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/controller/AppendixController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/controller/ProcessRouteItemInstanceController.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/controller/ProcessRouteItemParamInstanceController.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/controller/ProductProcessParamInstanceController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/controller/ProductStructureInstanceController.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/dto/ProcessRouteItemInstanceDto.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/dto/ProcessRouteItemParamInstanceDto.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/dto/ProductStructureInstanceDto.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/mapper/ProductProcessParamInstanceMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/pojo/ProcessRouteItemInstance.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/pojo/ProcessRouteItemParamInstance.java 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/pojo/ProductProcessParamInstance.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/pojo/ProductStructureInstance.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/AppendixService.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/ProcessRouteItemInstanceService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/ProcessRouteItemParamInstanceService.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/ProductProcessParamInstanceService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/ProductStructureInstanceService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/impl/AppendixServiceImpl.java 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/impl/ProcessRouteItemInstanceServiceImpl.java 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/impl/ProcessRouteItemParamInstanceServiceImpl.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/impl/ProductProcessParamInstanceServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/appendix/service/impl/ProductStructureInstanceServiceImpl.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductOrderDto.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProcessRouteItemParam.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductOrder.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcessParam.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductOrderService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProcessRouteItemParamServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/dto/ProductionPlanDto.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/productionPlan/service/impl/ProductionPlanServiceImpl.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/appendix/ProcessRouteItemInstanceMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/appendix/ProcessRouteItemParamInstanceMapper.xml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/appendix/ProductProcessParamInstanceMapper.xml 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/appendix/ProductStructureInstanceMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMapper.xml 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/ÄþÏÄ-ÖÐÊ¢½¨²Ä.sql
@@ -304,54 +304,36 @@
-- Table structure for process_route_item_param_instance
-- ----------------------------
DROP TABLE IF EXISTS `process_route_item_param_instance`;
CREATE TABLE `process_route_item_param_instance`
(
    `id`               bigint                                                        NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `order_id`         bigint                                                                 DEFAULT NULL COMMENT '生产订单ID',
    `route_item_id`    bigint                                                        NOT NULL COMMENT '关联工艺路线明细ID (process_route_item.id)',
    `param_id`         bigint                                                        NOT NULL COMMENT '关联基础参数定义ID (base_param.id)',
    `process_param_id` bigint                                                        NULL     DEFAULT NULL COMMENT '来源工序参数ID',
    `standard_value`   varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL     DEFAULT NULL COMMENT '此路线节点设定的标准值',
    `min_value`        decimal(10, 2)                                                NULL     DEFAULT NULL COMMENT '此路线节点设定的标准最小值',
    `max_value`        decimal(10, 2)                                                NULL     DEFAULT NULL COMMENT '此路线节点设定的标准最大值',
    `is_required`      tinyint                                                       NOT NULL DEFAULT 0 COMMENT '是否必填',
    `sort`             int                                                           NOT NULL DEFAULT 0 COMMENT '排序',
    `tenant_id`        bigint                                                        NULL     DEFAULT NULL COMMENT '租户ID',
    `create_time`      datetime                                                      NULL     DEFAULT CURRENT_TIMESTAMP,
    `update_time`      datetime                                                      NULL     DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `process_param_id` bigint                                                                 DEFAULT NULL COMMENT '来源工序参数ID',
    `param_key`        varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci          DEFAULT NULL COMMENT '参数唯一标识',
    `param_name`       varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '参数名称',
    `param_type`       tinyint                                                       NOT NULL COMMENT '参数类型(1数字 2文本 3下拉选择 4时间)',
    `param_format`     varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci          DEFAULT NULL COMMENT '参数格式',
    `value_mode`       tinyint                                                                DEFAULT '1' COMMENT '值模式(1单值 2区间)',
    `unit`             varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci           DEFAULT NULL COMMENT '单位',
    `remark`           varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci          DEFAULT NULL COMMENT '备注',
    `standard_value`   varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci          DEFAULT NULL COMMENT '标准值',
    `min_value`        decimal(10, 2)                                                         DEFAULT NULL COMMENT '此路线节点设定的标准最小值',
    `max_value`        decimal(10, 2)                                                         DEFAULT NULL COMMENT '此路线节点设定的标准最大值',
    `is_required`      tinyint                                                       NOT NULL DEFAULT '0' COMMENT '是否必填',
    `sort`             int                                                           NOT NULL DEFAULT '0' COMMENT '排序',
    `tenant_id`        bigint                                                                 DEFAULT NULL COMMENT '租户ID',
    `create_time`      datetime                                                               DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `update_time`      datetime                                                               DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    PRIMARY KEY (`id`) USING BTREE,
    INDEX `idx_route_item_id` (`route_item_id` ASC) USING BTREE,
    INDEX `idx_param_id` (`param_id` ASC) USING BTREE
    KEY `idx_route_item_id` (`route_item_id`) USING BTREE,
    KEY `idx_param_key` (`param_key`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 178
  CHARACTER SET = utf8mb4
  COLLATE = utf8mb4_0900_ai_ci COMMENT = '工艺路线工序参数-附表'
  ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for product_process_param_instance
-- ----------------------------
DROP TABLE IF EXISTS `product_process_param_instance`;
CREATE TABLE `product_process_param_instance`
(
    `id`             bigint                                                        NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `process_id`     bigint                                                        NOT NULL COMMENT '所属工序ID (product_process.id)',
    `param_id`       bigint                                                        NOT NULL COMMENT '关联基础参数ID (base_param.id)',
    `standard_value` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL     DEFAULT NULL COMMENT '在此工序设定的标准值(单值模式)',
    `min_value`      decimal(10, 2)                                                NULL     DEFAULT NULL COMMENT '在此工序设定的标准最小值(区间模式)',
    `max_value`      decimal(10, 2)                                                NULL     DEFAULT NULL COMMENT '在此工序设定的标准最大值(区间模式)',
    `is_required`    tinyint                                                       NOT NULL DEFAULT 0 COMMENT '在此工序中是否必填(0-否, 1-是)',
    `sort`           int                                                           NOT NULL DEFAULT 0 COMMENT '排序号',
    `tenant_id`      bigint                                                        NULL     DEFAULT NULL COMMENT '租户ID',
    `create_time`    datetime                                                      NULL     DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `update_time`    datetime                                                      NULL     DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    PRIMARY KEY (`id`) USING BTREE,
    INDEX `idx_process_id` (`process_id` ASC) USING BTREE,
    INDEX `idx_param_id` (`param_id` ASC) USING BTREE
) ENGINE = InnoDB
  AUTO_INCREMENT = 61
  CHARACTER SET = utf8mb4
  COLLATE = utf8mb4_0900_ai_ci COMMENT = '工序绑定参数-附表'
  ROW_FORMAT = Dynamic;
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8mb4
  COLLATE = utf8mb4_0900_ai_ci
  ROW_FORMAT = DYNAMIC COMMENT ='工艺路线工序参数实例表';
-- ----------------------------
-- Table structure for product_structure_instance
@@ -376,6 +358,22 @@
SET FOREIGN_KEY_CHECKS = 1;
ALTER TABLE `process_route_item_instance`
    ADD COLUMN `order_id` bigint NOT NULL COMMENT '生产订单id' AFTER `id`,
    ADD INDEX `idx_order_id` (`order_id`);
ALTER TABLE `process_route_item_param_instance`
    ADD COLUMN `order_id` bigint NOT NULL COMMENT '生产订单id' AFTER `id`,
    ADD INDEX `idx_order_id` (`order_id`);
ALTER TABLE `product_structure_instance`
    ADD COLUMN `order_id` bigint NOT NULL COMMENT '生产订单id' AFTER `id`,
    ADD INDEX `idx_order_id` (`order_id`);
ALTER TABLE `product-inventory-management-zsjc`.`product_order`
    ADD COLUMN `strength` varchar(255) NULL COMMENT '产品类型' AFTER `plan_complete_time`;
CREATE TABLE `product-inventory-management-zsjc`.`sales_delivery`  (
   `id` int NOT NULL AUTO_INCREMENT,
   `delivery_date` date NULL COMMENT '供货日期',
src/main/java/com/ruoyi/appendix/controller/AppendixController.java
@@ -1,8 +1,13 @@
package com.ruoyi.appendix.controller;
import com.ruoyi.appendix.service.AppendixService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.pojo.ProductOrder;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
 * <br>
@@ -17,4 +22,15 @@
@RequestMapping("/appendix")
@Api("BOM-工艺路线附表控制层")
public class AppendixController {
    @Resource
    private AppendixService appendixService;
    @PostMapping("/bindingRoute")
    @ApiOperation("生产订单绑定工艺路线")
    public AjaxResult bindingRoute(@RequestBody ProductOrder productOrder) {
        appendixService.populateData(productOrder);
        return AjaxResult.success();
    }
}
src/main/java/com/ruoyi/appendix/controller/ProcessRouteItemInstanceController.java
@@ -1,8 +1,14 @@
package com.ruoyi.appendix.controller;
import com.ruoyi.appendix.dto.ProcessRouteItemInstanceDto;
import com.ruoyi.appendix.service.ProcessRouteItemInstanceService;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <br>
@@ -17,4 +23,43 @@
@RequestMapping("/processRouteItemInstance")
@Api("艺路线子集-附表控制层")
public class ProcessRouteItemInstanceController {
    @Resource
    private ProcessRouteItemInstanceService processRouteItemInstanceService;
    @GetMapping("/list/{orderId}")
    @ApiOperation("获取工序列表")
    public AjaxResult getProcessItem(@PathVariable Long orderId) {
        List<ProcessRouteItemInstanceDto> list = processRouteItemInstanceService.getProcessItem(orderId);
        return AjaxResult.success(list);
    }
    @PostMapping("add")
    @ApiOperation("新增工序")
    public AjaxResult addProcessItem(@RequestBody ProcessRouteItemInstanceDto dto) {
        processRouteItemInstanceService.addProcessItem(dto);
        return AjaxResult.success();
    }
    @PutMapping("/update")
    @ApiOperation("修改工序")
    public AjaxResult updateProcessItem(@RequestBody ProcessRouteItemInstanceDto dto) {
        processRouteItemInstanceService.updateProcessItem(dto);
        return AjaxResult.success();
    }
    @DeleteMapping("/delete/{id}")
    @ApiOperation("删除工序")
    public AjaxResult deleteProcessItem(@PathVariable Long id) {
        processRouteItemInstanceService.deleteProcessItem(id);
        return AjaxResult.success();
    }
    @PostMapping("/sort")
    @ApiOperation("工序排序")
    public AjaxResult sortProcessItem(@RequestBody ProcessRouteItemInstanceDto dto) {
        processRouteItemInstanceService.sortProcessItem(dto);
        return AjaxResult.success();
    }
}
src/main/java/com/ruoyi/appendix/controller/ProcessRouteItemParamInstanceController.java
@@ -1,8 +1,14 @@
package com.ruoyi.appendix.controller;
import com.ruoyi.appendix.dto.ProcessRouteItemParamInstanceDto;
import com.ruoyi.appendix.service.ProcessRouteItemParamInstanceService;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <br>
@@ -18,4 +24,37 @@
@RestController
@RequestMapping("/processRouteItemParamInstance")
public class ProcessRouteItemParamInstanceController {
    @Resource
    private ProcessRouteItemParamInstanceService processRouteItemParamInstanceService;
    @GetMapping("/list")
    @ApiOperation("生产订单-获取工序绑定的参数列表")
    public AjaxResult routeItemParamList(@RequestParam("orderId") Long orderId, @RequestParam("routeItemId") Long routeItemId) {
        List<ProcessRouteItemParamInstanceDto> list = processRouteItemParamInstanceService.routeItemParamList(orderId, routeItemId);
        return AjaxResult.success(list);
    }
    @PostMapping("/add")
    @ApiOperation("生产订单-工序新增参数")
    public AjaxResult addRouteItemParam(@RequestBody ProcessRouteItemParamInstanceDto dto) {
        processRouteItemParamInstanceService.addRouteItemParam(dto);
        return AjaxResult.success();
    }
    @PutMapping("/update")
    @ApiOperation("生产订单-工序更新参数")
    public AjaxResult updateRouteItemParam(@RequestBody ProcessRouteItemParamInstanceDto dto){
        processRouteItemParamInstanceService.updateRouteItemParam(dto);
        return AjaxResult.success();
    }
    @DeleteMapping("/delete/{id}")
    @ApiOperation("生产订单-工序删除参数")
    public AjaxResult deleteRouteItemParam(@PathVariable Long id) {
        processRouteItemParamInstanceService.deleteRouteItemParam(id);
        return AjaxResult.success();
    }
}
src/main/java/com/ruoyi/appendix/controller/ProductProcessParamInstanceController.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/appendix/controller/ProductStructureInstanceController.java
@@ -1,8 +1,14 @@
package com.ruoyi.appendix.controller;
import com.ruoyi.appendix.dto.ProductStructureInstanceDto;
import com.ruoyi.appendix.service.ProductStructureInstanceService;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <br>
@@ -17,4 +23,22 @@
@RestController
@RequestMapping("/productStructureInstance")
public class ProductStructureInstanceController {
    @Resource
    private ProductStructureInstanceService productStructureInstanceService;
    @GetMapping("/getBomStructs/{orderId}")
    @ApiOperation("根据生产订单ID获取绑定的BOM子集结构树")
    public AjaxResult getBomStructs(@PathVariable Long orderId) {
        List<ProductStructureInstanceDto> list = productStructureInstanceService.listByOrderId(orderId);
        return AjaxResult.success(list);
    }
    @PutMapping("/addOrUpdateBomStructs")
    @ApiOperation("新增/更新BOM子集结构")
    public AjaxResult addOrUpdateBomStructs(@RequestBody ProductStructureInstanceDto instanceDto) {
        productStructureInstanceService.addOrUpdateBomStructs(instanceDto);
        return AjaxResult.success();
    }
}
src/main/java/com/ruoyi/appendix/dto/ProcessRouteItemInstanceDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.appendix.dto;
import com.ruoyi.appendix.pojo.ProcessRouteItemInstance;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * <br>
 * å·¥è‰ºè·¯çº¿å­é›†-附表Dto
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/03/19 10:46
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class ProcessRouteItemInstanceDto extends ProcessRouteItemInstance {
    @ApiModelProperty("工序名称")
    private String processName;
}
src/main/java/com/ruoyi/appendix/dto/ProcessRouteItemParamInstanceDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.appendix.dto;
import com.ruoyi.appendix.pojo.ProcessRouteItemParamInstance;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * <br>
 *
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/03/19 11:49
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class ProcessRouteItemParamInstanceDto extends ProcessRouteItemParamInstance {
    @ApiModelProperty("工序ID")
    private Long processId;
}
src/main/java/com/ruoyi/appendix/dto/ProductStructureInstanceDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.appendix.dto;
import com.ruoyi.appendix.pojo.ProductStructureInstance;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.ArrayList;
import java.util.List;
/**
 * <br>
 * BOM子集-附表Dto
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/03/19 10:08
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class ProductStructureInstanceDto extends ProductStructureInstance {
    @ApiModelProperty("子类")
    private List<ProductStructureInstanceDto> children = new ArrayList<>();
    @ApiModelProperty("临时ID")
    private String tempId;
    @ApiModelProperty("父节点临时ID")
    private String parentTempId;
}
src/main/java/com/ruoyi/appendix/mapper/ProductProcessParamInstanceMapper.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/appendix/pojo/ProcessRouteItemInstance.java
@@ -28,6 +28,9 @@
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("生产订单id")
    private Long orderId;
    @ApiModelProperty("工艺路线id")
    private Long routeId;
src/main/java/com/ruoyi/appendix/pojo/ProcessRouteItemParamInstance.java
@@ -28,14 +28,32 @@
    @ApiModelProperty("主键ID")
    private Long id;
    @ApiModelProperty("生产订单id")
    private Long orderId;
    @ApiModelProperty("关联工艺路线明细ID")
    private Long routeItemId;
    @ApiModelProperty("关联基础参数定义ID")
    private Long paramId;
    @ApiModelProperty("参数唯一标识")
    private String paramKey;
    @ApiModelProperty("来源工序参数ID")
    private Long processParamId;
    @ApiModelProperty("参数名称")
    private String paramName;
    @ApiModelProperty("参数类型(1数字 2文本 3下拉选择 4时间)")
    private Integer paramType;
    @ApiModelProperty("参数格式")
    private String paramFormat;
    @ApiModelProperty("值模式(1单值 2区间)")
    private Integer valueMode;
    @ApiModelProperty("单位")
    private String unit;
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("标准值")
    private String standardValue;
@@ -47,7 +65,7 @@
    private BigDecimal maxValue;
    @ApiModelProperty("是否必填")
    private Integer isRequired;
    private Boolean isRequired;
    @ApiModelProperty("排序")
    private Integer sort;
src/main/java/com/ruoyi/appendix/pojo/ProductProcessParamInstance.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/appendix/pojo/ProductStructureInstance.java
@@ -27,6 +27,9 @@
    @ApiModelProperty("主键ID")
    private Long id;
    @ApiModelProperty("生产订单id")
    private Long orderId;
    @ApiModelProperty("父节点ID")
    private Long parentId;
@@ -50,4 +53,5 @@
    @ApiModelProperty("BOM ID")
    private Long bomId;
}
src/main/java/com/ruoyi/appendix/service/AppendixService.java
@@ -1,5 +1,6 @@
package com.ruoyi.appendix.service;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.productionPlan.dto.ProductionPlanDto;
/**
@@ -13,33 +14,33 @@
 */
public interface AppendixService {
    /**
     * å°†å¯¹åº”的工艺路线子集与绑定的BOM子集填充到附表中
     *
     * @param productOrderId ç”Ÿäº§è®¢å•ID
     * @param processRouteId å·¥è‰ºè·¯çº¿ID
     */
    void populateData(Long productOrderId, Long processRouteId);
    void populateData(ProductOrder productOrder);
    /**
     * ç»™ä¸‹å‘的砌块拉取对应的工艺路线子集与绑定的BOM子集填充到附表中
     *
     * @param orderId           ç”Ÿäº§è®¢å•ID
     * @param productionPlanDto äº§å“è¯¦æƒ…
     */
    Long populateBlocks(ProductionPlanDto productionPlanDto);
    Long populateBlocks(Long orderId, ProductionPlanDto productionPlanDto);
    /**
     * ç»™ä¸‹å‘的板材拉取对应的工艺路线子集与绑定的BOM子集填充到附表中
     * <p>
     *
     * @param orderId           ç”Ÿäº§è®¢å•ID
     * @param productionPlanDto äº§å“è¯¦æƒ…
     */
    Long populatePlates(ProductionPlanDto productionPlanDto);
    Long populatePlates(Long orderId, ProductionPlanDto productionPlanDto);
    /**
     * åˆ é™¤è¯¥è®¢å•携带的附表数据
     *
     * @param orderId        ç”Ÿäº§è®¢å•ID
     * @param processRouteId å·¥è‰ºè·¯çº¿ID
     */
    void deleteData(Long processRouteId);
    void deleteData(Long orderId, Long processRouteId);
}
src/main/java/com/ruoyi/appendix/service/ProcessRouteItemInstanceService.java
@@ -1,11 +1,14 @@
package com.ruoyi.appendix.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.appendix.dto.ProcessRouteItemInstanceDto;
import com.ruoyi.appendix.pojo.ProcessRouteItemInstance;
import java.util.List;
/**
 * <br>
 *工艺路线子集-附表Service
 * å·¥è‰ºè·¯çº¿å­é›†-附表Service
 * </br>
 *
 * @author deslrey
@@ -13,4 +16,13 @@
 * @since 2026/03/18 13:07
 */
public interface ProcessRouteItemInstanceService extends IService<ProcessRouteItemInstance> {
    List<ProcessRouteItemInstanceDto> getProcessItem(Long orderId);
    void addProcessItem(ProcessRouteItemInstanceDto dto);
    void updateProcessItem(ProcessRouteItemInstanceDto dto);
    void deleteProcessItem(Long id);
    void sortProcessItem(ProcessRouteItemInstanceDto dto);
}
src/main/java/com/ruoyi/appendix/service/ProcessRouteItemParamInstanceService.java
@@ -1,7 +1,10 @@
package com.ruoyi.appendix.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.appendix.dto.ProcessRouteItemParamInstanceDto;
import com.ruoyi.appendix.pojo.ProcessRouteItemParamInstance;
import java.util.List;
/**
 * <br>
@@ -13,4 +16,13 @@
 * @since 2026/03/18 13:11
 */
public interface ProcessRouteItemParamInstanceService extends IService<ProcessRouteItemParamInstance> {
    List<ProcessRouteItemParamInstanceDto> routeItemParamList(Long orderId, Long routeItemId);
    void addRouteItemParam(ProcessRouteItemParamInstanceDto dto);
    void updateRouteItemParam(ProcessRouteItemParamInstanceDto dto);
    void deleteRouteItemParam(Long id);
}
src/main/java/com/ruoyi/appendix/service/ProductProcessParamInstanceService.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/appendix/service/ProductStructureInstanceService.java
@@ -1,7 +1,10 @@
package com.ruoyi.appendix.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.appendix.dto.ProductStructureInstanceDto;
import com.ruoyi.appendix.pojo.ProductStructureInstance;
import java.util.List;
/**
 * <br>
@@ -13,4 +16,8 @@
 * @since 2026/03/18 13:21
 */
public interface ProductStructureInstanceService extends IService<ProductStructureInstance> {
    List<ProductStructureInstanceDto> listByOrderId(Long orderId);
    void addOrUpdateBomStructs(ProductStructureInstanceDto instanceDto);
}
src/main/java/com/ruoyi/appendix/service/impl/AppendixServiceImpl.java
@@ -3,9 +3,10 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.appendix.pojo.ProcessRouteItemInstance;
import com.ruoyi.appendix.pojo.ProcessRouteItemParamInstance;
import com.ruoyi.appendix.pojo.ProductProcessParamInstance;
import com.ruoyi.appendix.pojo.ProductStructureInstance;
import com.ruoyi.appendix.service.*;
import com.ruoyi.basic.pojo.BaseParam;
import com.ruoyi.basic.service.BaseParamService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.production.pojo.*;
@@ -16,7 +17,9 @@
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -39,10 +42,10 @@
    private ProcessRouteItemParamInstanceService processRouteItemParamInstanceService;
    @Resource
    private ProductProcessParamInstanceService productProcessParamInstanceService;
    private ProductStructureInstanceService productStructureInstanceService;
    @Resource
    private ProductStructureInstanceService productStructureInstanceService;
    private BaseParamService baseParamService;
    @Resource
    private ProcessRouteService processRouteService;
@@ -54,16 +57,13 @@
    private ProcessRouteItemParamService processRouteItemParamService;
    @Resource
    private ProductProcessParamService productProcessParamService;
    @Resource
    private ProductStructureService productStructureService;
    @Resource
    private ProductOrderService productOrderService;
    @Override
    public Long populateBlocks(ProductionPlanDto productionPlanDto) {
    public Long populateBlocks(Long orderId, ProductionPlanDto productionPlanDto) {
        if (productionPlanDto == null) {
            throw new ServiceException("下发数据不能为空");
        }
@@ -75,12 +75,12 @@
            log.info("下发产品【{}】未查询出工艺路线", productionPlanDto.getProductName());
            return null;
        }
        migration(processRoute);
        migration(orderId, processRoute);
        return processRoute.getId();
    }
    @Override
    public Long populatePlates(ProductionPlanDto productionPlanDto) {
    public Long populatePlates(Long orderId, ProductionPlanDto productionPlanDto) {
        if (productionPlanDto == null) {
            throw new ServiceException("下发数据不能为空");
        }
@@ -90,127 +90,159 @@
            log.info("下发产品【{}】未查询出工艺路线", productionPlanDto.getProductName());
            return null;
        }
        migration(processRoute);
        migration(orderId, processRoute);
        return processRoute.getId();
    }
    @Override
    public void populateData(Long productOrderId, Long processRouteId) {
        ProcessRoute processRoute = processRouteService.getById(processRouteId);
        if (processRoute == null) {
            log.info("生产订单【{}】未查询出工艺路线【{}】", productOrderId, processRouteId);
            return;
    public void populateData(ProductOrder productOrder) {
        if (productOrder == null) {
            throw new ServiceException("绑定失败.数据不能为空");
        }
        migration(processRoute);
        if (productOrder.getId() == null || productOrder.getRouteId() == null) {
            throw new ServiceException("绑定失败,生产订单或工艺路线不能为空");
        }
        ProcessRoute processRoute = processRouteService.getById(productOrder.getRouteId());
        if (processRoute == null) {
            throw new ServiceException("该工艺路线不存在,绑定失败");
        }
        migration(productOrder.getId(), processRoute);
        //  å›žå†™å·¥è‰ºè·¯çº¿id到生产订单
        ProductOrder productOrder = new ProductOrder();
        productOrder.setId(productOrderId);
        productOrder.setRouteId(processRouteId);
        productOrderService.updateById(productOrder);
    }
    @Override
    public void deleteData(Long processRouteId) {
        //  æŸ¥å‡ºå·¥è‰ºè·¯çº¿å­é›†ï¼Œç”¨äºŽå…³è”删除参数附表
        List<ProcessRouteItem> itemList = processRouteItemService.list(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, processRouteId));
        if (itemList != null && !itemList.isEmpty()) {
            List<Long> itemIds = itemList.stream().map(ProcessRouteItem::getId).collect(Collectors.toList());
            List<Long> processIds = itemList.stream().map(ProcessRouteItem::getProcessId).collect(Collectors.toList());
            //  åˆ é™¤å·¥è‰ºè·¯çº¿å·¥åºå‚数附表
            processRouteItemParamInstanceService.remove(new LambdaQueryWrapper<ProcessRouteItemParamInstance>().in(ProcessRouteItemParamInstance::getRouteItemId, itemIds));
            //  åˆ é™¤å·¥åºç»‘定参数附表
            productProcessParamInstanceService.remove(new LambdaQueryWrapper<ProductProcessParamInstance>().in(ProductProcessParamInstance::getProcessId, processIds));
        }
    public void deleteData(Long orderId, Long processRouteId) {
        //  åˆ é™¤å·¥è‰ºè·¯çº¿å·¥åºå‚数附表
        processRouteItemParamInstanceService.remove(new LambdaQueryWrapper<ProcessRouteItemParamInstance>()
                .eq(ProcessRouteItemParamInstance::getOrderId, orderId));
        //  åˆ é™¤å·¥è‰ºè·¯çº¿å­é›†é™„表
        processRouteItemInstanceService.remove(
                new LambdaQueryWrapper<ProcessRouteItemInstance>().eq(ProcessRouteItemInstance::getRouteId, processRouteId));
        processRouteItemInstanceService.remove(new LambdaQueryWrapper<ProcessRouteItemInstance>()
                .eq(ProcessRouteItemInstance::getOrderId, orderId)
                .eq(ProcessRouteItemInstance::getRouteId, processRouteId));
        //  åˆ é™¤BOM子集附表
        ProcessRoute processRoute = processRouteService.getById(processRouteId);
        if (processRoute != null && processRoute.getBomId() != null) {
            productStructureInstanceService.remove(new LambdaQueryWrapper<ProductStructureInstance>().eq(ProductStructureInstance::getBomId, processRoute.getBomId()));
            productStructureInstanceService.remove(new LambdaQueryWrapper<ProductStructureInstance>()
                    .eq(ProductStructureInstance::getOrderId, orderId)
                    .eq(ProductStructureInstance::getBomId, processRoute.getBomId()));
        }
    }
    /**
     * æ ¹æ®å·¥è‰ºè·¯çº¿è¿ç§»å››å¼ é™„表数据
     * æ ¹æ®å·¥è‰ºè·¯çº¿è¿ç§»é™„表数据
     */
    private void migration(ProcessRoute processRoute) {
        //  è¿ç§»å·¥è‰ºè·¯çº¿å­é›†è¡¨æ•°æ®
        List<ProcessRouteItem> processRouteItemList = processRouteItemService.list(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
        migrationProcessRouteItem(processRouteItemList);
    private void migration(Long orderId, ProcessRoute processRoute) {
        //  è¿ç§»å·¥è‰ºè·¯çº¿å­é›†è¡¨æ•°æ®ï¼Œè¿”回旧id->新instance映射
        List<ProcessRouteItem> processRouteItemList = processRouteItemService.list(
                new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
        Map<Long, ProcessRouteItemInstance> routeItemOldIdMap = migrationProcessRouteItem(orderId, processRouteItemList);
        //  è¿ç§»å·¥è‰ºè·¯çº¿å†…绑定的工序及工序参数
        //  è¿ç§»å·¥è‰ºè·¯çº¿å†…绑定的工序参数
        if (processRouteItemList != null && !processRouteItemList.isEmpty()) {
            for (ProcessRouteItem item : processRouteItemList) {
                List<ProcessRouteItemParam> paramList = processRouteItemParamService.list(new LambdaQueryWrapper<ProcessRouteItemParam>().eq(ProcessRouteItemParam::getRouteItemId, item.getId()));
                migrationProcessRouteItemParam(paramList);
                ProcessRouteItemInstance newInstance = routeItemOldIdMap.get(item.getId());
                Long newRouteItemInstanceId = newInstance != null ? newInstance.getId() : item.getId();
                List<ProductProcessParam> processParamList = productProcessParamService.list(new LambdaQueryWrapper<ProductProcessParam>().eq(ProductProcessParam::getProcessId, item.getProcessId()));
                migrationProductProcessParam(processParamList);
                List<ProcessRouteItemParam> paramList = processRouteItemParamService.list(
                        new LambdaQueryWrapper<ProcessRouteItemParam>().eq(ProcessRouteItemParam::getRouteItemId, item.getId()));
                migrationProcessRouteItemParam(orderId, paramList, newRouteItemInstanceId);
            }
        }
        //  è¿ç§»BOM子集表数据
        if (processRoute.getBomId() != null) {
            List<ProductStructure> structureList = productStructureService.list(new LambdaQueryWrapper<ProductStructure>().eq(ProductStructure::getBomId, processRoute.getBomId()));
            migrationProductStructure(structureList);
            List<ProductStructure> structureList = productStructureService.list(
                    new LambdaQueryWrapper<ProductStructure>().eq(ProductStructure::getBomId, processRoute.getBomId()));
            migrationProductStructure(orderId, structureList);
        }
    }
    private void migrationProcessRouteItem(List<ProcessRouteItem> list) {
    private Map<Long, ProcessRouteItemInstance> migrationProcessRouteItem(Long orderId, List<ProcessRouteItem> list) {
        Map<Long, ProcessRouteItemInstance> oldIdMap = new HashMap<>();
        if (list == null || list.isEmpty()) {
            return;
            return oldIdMap;
        }
        List<ProcessRouteItemInstance> instances = list.stream().map(item -> {
            ProcessRouteItemInstance instance = new ProcessRouteItemInstance();
            BeanUtils.copyProperties(item, instance, "id");
            instance.setIsQuality(item.getIsQuality() != null && item.getIsQuality() ? 1 : 0);
            instance.setOrderId(orderId);
            if (item.getId() != null) {
                oldIdMap.put(item.getId(), instance);
            }
            return instance;
        }).collect(Collectors.toList());
        processRouteItemInstanceService.saveBatch(instances);
        return oldIdMap;
    }
    private void migrationProcessRouteItemParam(List<ProcessRouteItemParam> list) {
    private void migrationProcessRouteItemParam(Long orderId, List<ProcessRouteItemParam> list, Long newRouteItemInstanceId) {
        if (list == null || list.isEmpty()) {
            return;
        }
        // æ‰¹é‡æŸ¥è¯¢ base_param
        List<Long> paramIds = list.stream().map(ProcessRouteItemParam::getParamId)
                .filter(id -> id != null).distinct().collect(Collectors.toList());
        Map<Long, BaseParam> baseParamMap = new HashMap<>();
        if (!paramIds.isEmpty()) {
            baseParamService.listByIds(paramIds).forEach(bp -> baseParamMap.put(bp.getId(), bp));
        }
        List<ProcessRouteItemParamInstance> instances = list.stream().map(item -> {
            ProcessRouteItemParamInstance instance = new ProcessRouteItemParamInstance();
            BeanUtils.copyProperties(item, instance, "id");
            instance.setOrderId(orderId);
            instance.setRouteItemId(newRouteItemInstanceId);
            // ä»Ž base_param å¡«å……基础字段
            BaseParam bp = baseParamMap.get(item.getParamId());
            if (bp != null) {
                instance.setParamKey(bp.getParamKey());
                instance.setParamName(bp.getParamName());
                instance.setParamType(bp.getParamType());
                instance.setParamFormat(bp.getParamFormat());
                instance.setValueMode(bp.getValueMode());
                instance.setUnit(bp.getUnit());
                instance.setRemark(bp.getRemark());
            }
            return instance;
        }).collect(Collectors.toList());
        processRouteItemParamInstanceService.saveBatch(instances);
    }
    private void migrationProductProcessParam(List<ProductProcessParam> list) {
    private void migrationProductStructure(Long orderId, List<ProductStructure> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        List<ProductProcessParamInstance> instances = list.stream().map(item -> {
            ProductProcessParamInstance instance = new ProductProcessParamInstance();
            BeanUtils.copyProperties(item, instance, "id");
            instance.setIsRequired(item.getIsRequired() != null && item.getIsRequired() == 1);
            return instance;
        }).collect(Collectors.toList());
        productProcessParamInstanceService.saveBatch(instances);
    }
    private void migrationProductStructure(List<ProductStructure> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        Map<Long, ProductStructureInstance> oldIdMap = new HashMap<>();
        List<ProductStructureInstance> instances = list.stream().map(item -> {
            ProductStructureInstance instance = new ProductStructureInstance();
            BeanUtils.copyProperties(item, instance, "id");
            instance.setBomId(item.getBomId() != null ? item.getBomId().longValue() : null);
            instance.setOrderId(orderId);
            if (item.getId() != null) {
                oldIdMap.put(item.getId(), instance);
            }
            return instance;
        }).collect(Collectors.toList());
        productStructureInstanceService.saveBatch(instances);
        //  æ–°å¢žåŽæœ‰id,旧id->新id,修正parentId
        Map<Long, Long> oldToNewId = new HashMap<>();
        list.forEach(item -> {
            if (item.getId() != null && oldIdMap.containsKey(item.getId())) {
                oldToNewId.put(item.getId(), oldIdMap.get(item.getId()).getId());
            }
        });
        List<ProductStructureInstance> toUpdate = instances.stream()
                .filter(i -> i.getParentId() != null && oldToNewId.containsKey(i.getParentId()))
                .peek(i -> i.setParentId(oldToNewId.get(i.getParentId())))
                .collect(Collectors.toList());
        if (!toUpdate.isEmpty()) {
            productStructureInstanceService.updateBatchById(toUpdate);
        }
    }
}
src/main/java/com/ruoyi/appendix/service/impl/ProcessRouteItemInstanceServiceImpl.java
@@ -1,11 +1,31 @@
package com.ruoyi.appendix.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.appendix.dto.ProcessRouteItemInstanceDto;
import com.ruoyi.appendix.mapper.ProcessRouteItemInstanceMapper;
import com.ruoyi.appendix.pojo.ProcessRouteItemInstance;
import com.ruoyi.appendix.pojo.ProcessRouteItemParamInstance;
import com.ruoyi.appendix.service.ProcessRouteItemInstanceService;
import com.ruoyi.appendix.service.ProcessRouteItemParamInstanceService;
import com.ruoyi.basic.pojo.BaseParam;
import com.ruoyi.basic.service.BaseParamService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.production.pojo.ProcessRouteItemParam;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.service.ProcessRouteItemParamService;
import com.ruoyi.production.service.ProductProcessService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * <br>
@@ -20,5 +40,159 @@
@Service
public class ProcessRouteItemInstanceServiceImpl extends ServiceImpl<ProcessRouteItemInstanceMapper, ProcessRouteItemInstance> implements ProcessRouteItemInstanceService {
    @Resource
    private ProductProcessService productProcessService;
}
    @Resource
    private ProcessRouteItemParamInstanceService processRouteItemParamInstanceService;
    @Resource
    private ProcessRouteItemParamService processRouteItemParamService;
    @Resource
    private BaseParamService baseParamService;
    @Override
    public List<ProcessRouteItemInstanceDto> getProcessItem(Long orderId) {
        List<ProcessRouteItemInstance> list = list(new LambdaQueryWrapper<ProcessRouteItemInstance>()
                .eq(ProcessRouteItemInstance::getOrderId, orderId)
                .orderByAsc(ProcessRouteItemInstance::getDragSort));
        return list.stream().map(item -> {
            ProcessRouteItemInstanceDto dto = new ProcessRouteItemInstanceDto();
            BeanUtils.copyProperties(item, dto);
            if (item.getProcessId() != null) {
                ProductProcess process = productProcessService.getById(item.getProcessId());
                if (process != null) {
                    dto.setProcessName(process.getName());
                }
            }
            return dto;
        }).collect(Collectors.toList());
    }
    @Override
    public void addProcessItem(ProcessRouteItemInstanceDto dto) {
        if (dto == null) {
            throw new ServiceException("新增数据不能为空");
        }
        if (dto.getOrderId() == null) {
            throw new ServiceException("生产订单ID不能为空");
        }
        if (dto.getProcessId() == null) {
            throw new ServiceException("工序ID不能为空");
        }
        ProcessRouteItemInstance entity = new ProcessRouteItemInstance();
        BeanUtils.copyProperties(dto, entity);
        entity.setId(null);
        entity.setTenantId(SecurityUtils.getLoginUser().getTenantId());
        entity.setCreateTime(LocalDateTime.now());
        //  å–当前订单下最大 dragSort + 1
        ProcessRouteItemInstance maxSortItem = getOne(new LambdaQueryWrapper<ProcessRouteItemInstance>()
                .eq(ProcessRouteItemInstance::getOrderId, dto.getOrderId())
                .orderByDesc(ProcessRouteItemInstance::getDragSort)
                .last("limit 1"));
        entity.setDragSort(maxSortItem != null && maxSortItem.getDragSort() != null ? maxSortItem.getDragSort() + 1 : 1);
        save(entity);
    }
    @Override
    public void updateProcessItem(ProcessRouteItemInstanceDto dto) {
        if (dto == null || dto.getId() == null) {
            throw new ServiceException("更新数据或ID不能为空");
        }
        ProcessRouteItemInstance old = getById(dto.getId());
        if (old == null) {
            throw new ServiceException("数据不存在");
        }
        // å·¥åºå˜æ›´ï¼Œåˆ é™¤æ—§å‚数附表,迁移新工序参数
        if (dto.getProcessId() != null && !dto.getProcessId().equals(old.getProcessId())) {
            // åˆ é™¤å·¥è‰ºè·¯çº¿å·¥åºå‚数附表
            processRouteItemParamInstanceService.remove(new LambdaQueryWrapper<ProcessRouteItemParamInstance>()
                    .eq(ProcessRouteItemParamInstance::getOrderId, old.getOrderId())
                    .eq(ProcessRouteItemParamInstance::getRouteItemId, old.getId()));
            // è¿ç§»æ–°å·¥åºçš„ process_route_item_param
            List<ProcessRouteItemParam> routeItemParams = processRouteItemParamService.list(
                    new LambdaQueryWrapper<ProcessRouteItemParam>().eq(ProcessRouteItemParam::getRouteItemId, old.getId()));
            if (!routeItemParams.isEmpty()) {
                // æ‰¹é‡æŸ¥è¯¢ base_param
                List<Long> paramIds = routeItemParams.stream().map(ProcessRouteItemParam::getParamId)
                        .filter(id -> id != null).distinct().collect(Collectors.toList());
                Map<Long, BaseParam> baseParamMap = new HashMap<>();
                if (!paramIds.isEmpty()) {
                    baseParamService.listByIds(paramIds).forEach(bp -> baseParamMap.put(bp.getId(), bp));
                }
                List<ProcessRouteItemParamInstance> newInstances = routeItemParams.stream().map(p -> {
                    ProcessRouteItemParamInstance instance = new ProcessRouteItemParamInstance();
                    BeanUtils.copyProperties(p, instance, "id");
                    instance.setOrderId(old.getOrderId());
                    BaseParam bp = baseParamMap.get(p.getParamId());
                    if (bp != null) {
                        instance.setParamKey(bp.getParamKey());
                        instance.setParamName(bp.getParamName());
                        instance.setParamType(bp.getParamType());
                        instance.setParamFormat(bp.getParamFormat());
                        instance.setValueMode(bp.getValueMode());
                        instance.setUnit(bp.getUnit());
                        instance.setRemark(bp.getRemark());
                    }
                    return instance;
                }).collect(Collectors.toList());
                processRouteItemParamInstanceService.saveBatch(newInstances);
            }
        }
        ProcessRouteItemInstance entity = new ProcessRouteItemInstance();
        BeanUtils.copyProperties(dto, entity);
        entity.setUpdateTime(LocalDateTime.now());
        updateById(entity);
    }
    @Override
    public void deleteProcessItem(Long id) {
        if (id == null) {
            throw new ServiceException("ID不能为空");
        }
        ProcessRouteItemInstance old = getById(id);
        if (old == null) {
            throw new ServiceException("数据不存在");
        }
        // åˆ é™¤å·¥è‰ºè·¯çº¿å·¥åºå‚数附表
        processRouteItemParamInstanceService.remove(new LambdaQueryWrapper<ProcessRouteItemParamInstance>()
                .eq(ProcessRouteItemParamInstance::getOrderId, old.getOrderId())
                .eq(ProcessRouteItemParamInstance::getRouteItemId, id));
        removeById(id);
    }
    @Override
    public void sortProcessItem(ProcessRouteItemInstanceDto dto) {
        if (dto == null || dto.getId() == null) {
            throw new ServiceException("数据或ID不能为空");
        }
        ProcessRouteItemInstance old = getById(dto.getId());
        if (old == null) {
            throw new ServiceException("数据不存在");
        }
        List<ProcessRouteItemInstance> items = list(new LambdaQueryWrapper<ProcessRouteItemInstance>()
                .eq(ProcessRouteItemInstance::getOrderId, old.getOrderId())
                .orderByAsc(ProcessRouteItemInstance::getDragSort));
        Integer targetPosition = dto.getDragSort();
        if (targetPosition != null && targetPosition >= 1) {
            items.removeIf(item -> item.getId().equals(old.getId()));
            items.add(targetPosition - 1, old);
            for (int i = 0; i < items.size(); i++) {
                ProcessRouteItemInstance item = items.get(i);
                int newSort = i + 1;
                if (!item.getId().equals(old.getId())) {
                    if (!Integer.valueOf(newSort).equals(item.getDragSort())) {
                        item.setDragSort(newSort);
                        updateById(item);
                    }
                } else {
                    old.setDragSort(newSort);
                    updateById(old);
                }
            }
        }
    }
}
src/main/java/com/ruoyi/appendix/service/impl/ProcessRouteItemParamInstanceServiceImpl.java
@@ -1,11 +1,21 @@
package com.ruoyi.appendix.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.appendix.dto.ProcessRouteItemParamInstanceDto;
import com.ruoyi.appendix.mapper.ProcessRouteItemParamInstanceMapper;
import com.ruoyi.appendix.pojo.ProcessRouteItemParamInstance;
import com.ruoyi.appendix.service.ProcessRouteItemParamInstanceService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <br>
@@ -19,4 +29,77 @@
@Slf4j
@Service
public class ProcessRouteItemParamInstanceServiceImpl extends ServiceImpl<ProcessRouteItemParamInstanceMapper, ProcessRouteItemParamInstance> implements ProcessRouteItemParamInstanceService {
}
    @Override
    public List<ProcessRouteItemParamInstanceDto> routeItemParamList(Long orderId, Long routeItemId) {
        List<ProcessRouteItemParamInstance> list = list(new LambdaQueryWrapper<ProcessRouteItemParamInstance>()
                .eq(ProcessRouteItemParamInstance::getOrderId, orderId)
                .eq(ProcessRouteItemParamInstance::getRouteItemId, routeItemId)
                .orderByAsc(ProcessRouteItemParamInstance::getSort));
        return list.stream().map(item -> {
            ProcessRouteItemParamInstanceDto dto = new ProcessRouteItemParamInstanceDto();
            BeanUtils.copyProperties(item, dto);
            return dto;
        }).collect(Collectors.toList());
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addRouteItemParam(ProcessRouteItemParamInstanceDto dto) {
        if (dto == null) {
            throw new ServiceException("新增数据不能为空");
        }
        if (dto.getOrderId() == null) {
            throw new ServiceException("生产订单ID不能为空");
        }
        if (dto.getRouteItemId() == null) {
            throw new ServiceException("工艺路线明细ID不能为空");
        }
        Long tenantId = SecurityUtils.getLoginUser().getTenantId();
        ProcessRouteItemParamInstance entity = new ProcessRouteItemParamInstance();
        BeanUtils.copyProperties(dto, entity);
        entity.setId(null);
        entity.setOrderId(dto.getOrderId());
        entity.setRouteItemId(dto.getRouteItemId());
        entity.setIsRequired(dto.getIsRequired());
        //  å–当前订单+路线明细下最大 sort + 1
        ProcessRouteItemParamInstance maxSortItem = getOne(new LambdaQueryWrapper<ProcessRouteItemParamInstance>()
                .select(ProcessRouteItemParamInstance::getSort)
                .eq(ProcessRouteItemParamInstance::getOrderId, dto.getOrderId())
                .eq(ProcessRouteItemParamInstance::getRouteItemId, dto.getRouteItemId())
                .orderByDesc(ProcessRouteItemParamInstance::getSort)
                .last("limit 1"));
        entity.setSort(maxSortItem != null && maxSortItem.getSort() != null ? maxSortItem.getSort() + 1 : 1);
        entity.setTenantId(tenantId);
        entity.setCreateTime(LocalDateTime.now());
        save(entity);
    }
    @Override
    public void updateRouteItemParam(ProcessRouteItemParamInstanceDto dto) {
        if (dto == null || dto.getId() == null) {
            throw new ServiceException("更新数据或ID不能为空");
        }
        if (getById(dto.getId()) == null) {
            throw new ServiceException("数据不存在");
        }
        ProcessRouteItemParamInstance entity = new ProcessRouteItemParamInstance();
        BeanUtils.copyProperties(dto, entity);
        entity.setUpdateTime(LocalDateTime.now());
        updateById(entity);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRouteItemParam(Long id) {
        if (id == null) {
            throw new ServiceException("ID不能为空");
        }
        if (getById(id) == null) {
            throw new ServiceException("数据不存在");
        }
        removeById(id);
    }
}
src/main/java/com/ruoyi/appendix/service/impl/ProductProcessParamInstanceServiceImpl.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/appendix/service/impl/ProductStructureInstanceServiceImpl.java
@@ -1,11 +1,23 @@
package com.ruoyi.appendix.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.appendix.dto.ProductStructureInstanceDto;
import com.ruoyi.appendix.mapper.ProductStructureInstanceMapper;
import com.ruoyi.appendix.pojo.ProductStructureInstance;
import com.ruoyi.appendix.service.ProductStructureInstanceService;
import com.ruoyi.common.utils.bean.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
 * <br>
@@ -19,4 +31,123 @@
@Slf4j
@Service
public class ProductStructureInstanceServiceImpl extends ServiceImpl<ProductStructureInstanceMapper, ProductStructureInstance> implements ProductStructureInstanceService {
    @Override
    public List<ProductStructureInstanceDto> listByOrderId(Long orderId) {
        List<ProductStructureInstance> list = list(new LambdaQueryWrapper<ProductStructureInstance>().eq(ProductStructureInstance::getOrderId, orderId));
        List<ProductStructureInstanceDto> dtoList = list.stream().map(item -> {
            ProductStructureInstanceDto dto = new ProductStructureInstanceDto();
            BeanUtils.copyProperties(item, dto);
            return dto;
        }).collect(java.util.stream.Collectors.toList());
        Map<Long, ProductStructureInstanceDto> map = new HashMap<>();
        for (ProductStructureInstanceDto node : dtoList) {
            map.put(node.getId(), node);
        }
        List<ProductStructureInstanceDto> tree = new ArrayList<>();
        for (ProductStructureInstanceDto node : dtoList) {
            Long parentId = node.getParentId();
            if (parentId == null || !map.containsKey(parentId)) {
                tree.add(node);
            } else {
                map.get(parentId).getChildren().add(node);
            }
        }
        return tree;
    }
    @Override
    public void addOrUpdateBomStructs(ProductStructureInstanceDto instanceDto) {
        Long orderId = instanceDto.getOrderId();
        // æ‰å¹³åŒ–前端传入的树
        List<ProductStructureInstanceDto> flatList = new ArrayList<>();
        flattenTree(instanceDto.getChildren(), flatList);
        // æŸ¥è¯¢æ•°æ®åº“已有数据
        List<ProductStructureInstance> dbList = list(new LambdaQueryWrapper<ProductStructureInstance>()
                .eq(ProductStructureInstance::getOrderId, orderId));
        // å‰ç«¯å·²æœ‰id集合
        Set<Long> frontendIds = flatList.stream()
                .map(ProductStructureInstanceDto::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        // éœ€è¦åˆ é™¤çš„节点
        Set<Long> deleteIds = dbList.stream()
                .map(ProductStructureInstance::getId)
                .filter(id -> !frontendIds.contains(id))
                .collect(Collectors.toSet());
        if (!deleteIds.isEmpty()) {
            removeByIds(deleteIds);
        }
        List<ProductStructureInstance> insertList = new ArrayList<>();
        List<ProductStructureInstance> updateList = new ArrayList<>();
        Map<String, ProductStructureInstance> tempEntityMap = new HashMap<>();
        for (ProductStructureInstanceDto dto : flatList) {
            ProductStructureInstance entity = new ProductStructureInstance();
            BeanUtils.copyProperties(dto, entity);
            entity.setOrderId(orderId);
            if (dto.getId() == null) {
                entity.setId(null);
                entity.setParentId(null);
                insertList.add(entity);
                if (dto.getTempId() != null) {
                    tempEntityMap.put(dto.getTempId(), entity);
                }
            } else {
                updateList.add(entity);
            }
        }
        if (!insertList.isEmpty()) {
            saveBatch(insertList);
        }
        // å›žå†™æ–°å¢žèŠ‚ç‚¹çš„ parentId
        List<ProductStructureInstance> parentFixList = new ArrayList<>();
        for (ProductStructureInstanceDto dto : flatList) {
            if (dto.getId() != null) continue;
            ProductStructureInstance child = tempEntityMap.get(dto.getTempId());
            if (child == null) continue;
            String parentTempId = dto.getParentTempId();
            if (parentTempId != null && !parentTempId.isEmpty()) {
                Long realParentId;
                if (tempEntityMap.containsKey(parentTempId)) {
                    realParentId = tempEntityMap.get(parentTempId).getId();
                } else {
                    try {
                        realParentId = Long.valueOf(parentTempId);
                    } catch (NumberFormatException e) {
                        realParentId = 0L;
                    }
                }
                child.setParentId(realParentId);
            } else {
                child.setParentId(0L);
            }
            parentFixList.add(child);
        }
        if (!parentFixList.isEmpty()) {
            updateBatchById(parentFixList);
        }
        if (!updateList.isEmpty()) {
            updateBatchById(updateList);
        }
    }
    private void flattenTree(List<ProductStructureInstanceDto> source, List<ProductStructureInstanceDto> result) {
        if (source == null) return;
        for (ProductStructureInstanceDto node : source) {
            result.add(node);
            flattenTree(node.getChildren(), result);
        }
    }
}
src/main/java/com/ruoyi/production/dto/ProductOrderDto.java
@@ -15,25 +15,29 @@
@ExcelIgnoreUnannotated
public class ProductOrderDto extends ProductOrder {
    @ApiModelProperty(value = "销售合同号")
    @Excel(name = "销售合同号")
    private String salesContractNo;
    @ApiModelProperty(value = "项目名")
    @Excel(name = "项目名")
    private String projectName;
    @ApiModelProperty(value = "客户名称")
    @Excel(name = "客户名称")
    private String customerName;
    @ApiModelProperty(value = "产品名称")
    @Excel(name = "产品名称")
    private String productCategory;
    private String productName;
    @ApiModelProperty(value = "规格")
    @Excel(name = "规格")
    private String specificationModel;
    private String model;
    @ApiModelProperty(value = "产品类型")
    @Excel(name = "产品类型")
    private String strength;
    @ApiModelProperty(value = "工艺路线描述")
    @Excel(name = "工艺路线描述")
    private String description;
    @ApiModelProperty(value = "工艺路线产品类型")
    @Excel(name = "工艺路线产品类型")
    private String dictLabel;
    @ApiModelProperty(value = "物料编码")
    @Excel(name = "物料编码")
    private String materialCode;
    @ApiModelProperty(value = "工艺路线编号")
    @Excel(name = "工艺路线编号")
@@ -43,6 +47,10 @@
    @Excel(name = "完成进度", suffix = "%")
    private BigDecimal completionStatus;
    @ApiModelProperty(value = "BOM ID")
    @Excel(name = "BOM ID")
    private String bomId;
    @ApiModelProperty(value = "BOM编号")
    @Excel(name = "BOM编号")
    private String bomNo;
src/main/java/com/ruoyi/production/pojo/ProcessRouteItemParam.java
@@ -50,7 +50,7 @@
    private BigDecimal maxValue;
    @ApiModelProperty("是否必填")
    private Integer isRequired;
    private Boolean isRequired;
    @ApiModelProperty("排序")
    private Integer sort;
src/main/java/com/ruoyi/production/pojo/ProductOrder.java
@@ -92,6 +92,10 @@
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime endTime;
    @Excel(name = "产品类型")
    @ApiModelProperty("产品类型")
    private String strength;
    @ApiModelProperty(value = "状态(1.待开始、2.进行中、3.已完成、4.已取消)")
    private Integer status;
}
src/main/java/com/ruoyi/production/pojo/ProductProcessParam.java
@@ -46,7 +46,7 @@
    private BigDecimal maxValue;
    @ApiModelProperty("在此工序中是否必填(0-否, 1-是)")
    private Integer isRequired;
    private Boolean isRequired;
    @ApiModelProperty("排序号")
    private Integer sort;
src/main/java/com/ruoyi/production/service/ProductOrderService.java
@@ -29,5 +29,7 @@
    Boolean addProductOrder(ProductOrder productOrder);
    Long insertProductOrder(ProductOrder productOrder);
    Boolean delete(Long[] id);
}
src/main/java/com/ruoyi/production/service/impl/ProcessRouteItemParamServiceImpl.java
@@ -72,7 +72,7 @@
        BaseParam baseParam = baseParamService.getById(param.getParamId());
        if (baseParam == null) {
            throw new ServiceException("新增失败,改基础参数不存在");
            throw new ServiceException("新增失败,该基础参数不存在");
        }
        Integer maxSort = baseMapper.selectMaxSortByRouteItemId(param.getRouteItemId());
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -170,14 +170,24 @@
    @Override
    public Boolean addProductOrder(ProductOrder productOrder) {
        String string = generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        productOrder.setNpsNo(string);
        fillAndSaveProductOrder(productOrder);
        return true;
    }
    @Override
    public Long insertProductOrder(ProductOrder productOrder) {
        fillAndSaveProductOrder(productOrder);
        return productOrder.getId();
    }
    private void fillAndSaveProductOrder(ProductOrder productOrder) {
        String orderNo = generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        productOrder.setNpsNo(orderNo);
        productOrder.setCompleteQuantity(BigDecimal.ZERO);
        this.save(productOrder);
        if (ObjectUtils.isNotEmpty(productOrder.getRouteId())) {
            this.bindingRoute(productOrder);
        }
        return true;
    }
    @Override
@@ -248,7 +258,7 @@
        //  åˆ é™¤é™„表的工艺路线与BOM
        for (Long id : ids) {
            ProductOrder productOrder = baseMapper.selectById(id);
            appendixService.deleteData(productOrder.getRouteId());
            appendixService.deleteData(productOrder.getId(), productOrder.getRouteId());
        }
//        productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>().in(ProductProcessRouteItem::getProductOrderId, ids));
src/main/java/com/ruoyi/productionPlan/dto/ProductionPlanDto.java
@@ -55,4 +55,5 @@
     */
    @ApiModelProperty("关联物料信息表ID")
    private Long productMaterialId;
}
src/main/java/com/ruoyi/productionPlan/service/impl/ProductionPlanServiceImpl.java
@@ -147,15 +147,19 @@
        productOrder.setQuantity(productionPlanDto.getTotalAssignedQuantity());
        productOrder.setPlanCompleteTime(productionPlanDto.getPlanCompleteTime());
        productOrder.setStatus(ProductOrderStatusEnum.WAIT.getCode());
        productOrder.setStrength(productionPlanDto.getStrength());
        Long orderId = productOrderService.insertProductOrder(productOrder);
        //  å½“下发的产品为砌块或板材,就拉取BOM子集与工艺路线子集数据存入到附表中
        if ("砌块".equals(productionPlanDto.getProductName())) {
            productOrder.setRouteId(appendixService.populateBlocks(productionPlanDto));
            productOrder.setRouteId(appendixService.populateBlocks(orderId, productionPlanDto));
        }
        if ("板材".equals(productionPlanDto.getProductName())) {
            productOrder.setRouteId(appendixService.populatePlates(productionPlanDto));
            productOrder.setRouteId(appendixService.populatePlates(orderId, productionPlanDto));
        }
        productOrderService.addProductOrder(productOrder);
        //  æ›´æ–°ç»‘定的工艺路线
        productOrderService.updateById(productOrder);
        // æ ¹æ®ä¸‹å‘数量,从第一个生产计划开始分配方数
        BigDecimal assignedVolume = BigDecimal.ZERO;
src/main/resources/mapper/appendix/ProcessRouteItemInstanceMapper.xml
@@ -7,6 +7,7 @@
    <resultMap id="ProcessRouteItemInstanceMap" type="com.ruoyi.appendix.pojo.ProcessRouteItemInstance">
        <id property="id" column="id"/>
        <result property="orderId" column="order_id"/>
        <result property="routeId" column="route_id"/>
        <result property="productModelId" column="product_model_id"/>
        <result property="processId" column="process_id"/>
src/main/resources/mapper/appendix/ProcessRouteItemParamInstanceMapper.xml
@@ -7,9 +7,15 @@
    <resultMap id="BaseResultMap" type="com.ruoyi.appendix.pojo.ProcessRouteItemParamInstance">
        <id property="id" column="id"/>
        <result property="orderId" column="order_id"/>
        <result property="routeItemId" column="route_item_id"/>
        <result property="paramId" column="param_id"/>
        <result property="processParamId" column="process_param_id"/>
        <result property="paramKey" column="param_key"/>
        <result property="paramName" column="param_name"/>
        <result property="paramType" column="param_type"/>
        <result property="paramFormat" column="param_format"/>
        <result property="valueMode" column="value_mode"/>
        <result property="unit" column="unit"/>
        <result property="remark" column="remark"/>
        <result property="standardValue" column="standard_value"/>
        <result property="minValue" column="min_value"/>
        <result property="maxValue" column="max_value"/>
src/main/resources/mapper/appendix/ProductProcessParamInstanceMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/appendix/ProductStructureInstanceMapper.xml
@@ -7,6 +7,7 @@
    <resultMap id="BaseResultMap" type="com.ruoyi.appendix.pojo.ProductStructureInstance">
        <id property="id" column="id"/>
        <result property="orderId" column="order_id"/>
        <result property="parentId" column="parent_id"/>
        <result property="productModelId" column="product_model_id"/>
        <result property="processId" column="process_id"/>
src/main/resources/mapper/production/ProductOrderMapper.xml
@@ -15,23 +15,45 @@
    </resultMap>
    <select id="pageProductOrder" resultType="com.ruoyi.production.dto.ProductOrderDto">
        select po.*,
        ppr.process_route_code,
        ROUND(po.complete_quantity / po.quantity * 100, 2) AS completionStatus
        from product_order po
        left join product_process_route ppr on po.id = ppr.product_order_id
        SELECT
        po.id,
        po.nps_no,
        po.tenant_id,
        po.create_time,
        po.update_time,
        po.route_id,
        po.quantity,
        po.complete_quantity,
        po.start_time,
        po.end_time,
        po.plan_complete_time,
        po.status,
        pm.product_name,
        po.strength AS strength,
        pr.process_route_code AS processRouteCode,
        pr.description,
        pb.id AS bomId,
        pb.bom_no AS bomNo,
        ROUND(po.complete_quantity / po.quantity * 100, 2) AS completionStatus,
        pms.model,
        pms.material_code AS materialCode
        FROM product_order po
        LEFT JOIN process_route pr ON po.route_id = pr.id
        LEFT JOIN product_bom pb ON pr.bom_id = pb.id
        LEFT JOIN product_order_plan pop ON po.id = pop.product_order_id
        LEFT JOIN production_plan pp ON pop.production_plan_id = pp.id
        LEFT JOIN product_material_sku pms ON pms.id = pp.product_material_sku_id
        LEFT JOIN product_material pm ON pm.id = pms.product_id
        <where>
            <if test="c.npsNo != null and c.npsNo != ''">
                and po.nps_no like concat('%',#{c.npsNo},'%')
            </if>
            <if test="c.customerName != null and c.customerName != ''">
                and sl.customer_name like concat('%',#{c.customerName},'%')
                AND po.nps_no LIKE CONCAT('%', #{c.npsNo}, '%')
            </if>
            <if test="c.startTime != null and c.endTime != null">
                and po.create_time between #{c.startTime} and #{c.endTime}
                AND po.create_time BETWEEN #{c.startTime} AND #{c.endTime}
            </if>
        </where>
    </select>
    <select id="listProcessRoute" resultType="com.ruoyi.production.pojo.ProcessRoute">
        select pr.*
        from process_route pr
@@ -46,35 +68,40 @@
               ps.unit_quantity * po.quantity as demandedQuantity,
               ps.unit,
               p.product_name,
               pp.name as  process_name,
               pp.name                        as process_name,
               pm.product_id,
               pm.model
        from
            product_structure ps
                left join product_model pm on ps.product_model_id = pm.id
                left join product p on pm.product_id = p.id
                left join product_process pp on ps.process_id = pp.id
                left join product_process_route ppr on ps.bom_id = ppr.bom_id
                left join product_order po on po.id = ppr.product_order_id
        from product_structure ps
                 left join product_model pm on ps.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
                 left join product_process pp on ps.process_id = pp.id
                 left join product_process_route ppr on ps.bom_id = ppr.bom_id
                 left join product_order po on po.id = ppr.product_order_id
        where ppr.product_order_id = #{orderId}
        order by ps.id
    </select>
    <select id="countCreated" resultType="java.lang.Integer">
        SELECT count(1) FROM product_order
        WHERE create_time &gt;= #{startDate} AND create_time &lt;= #{endDate}
        SELECT count(1)
        FROM product_order
        WHERE create_time &gt;= #{startDate}
          AND create_time &lt;= #{endDate}
    </select>
    <select id="countCompleted" resultType="java.lang.Integer">
        SELECT count(1) FROM product_order
        WHERE end_time &gt;= #{startDate} AND end_time &lt;= #{endDate}
        SELECT count(1)
        FROM product_order
        WHERE end_time &gt;= #{startDate}
          AND end_time &lt;= #{endDate}
          AND complete_quantity &gt;= quantity
    </select>
    <select id="countPending" resultType="java.lang.Integer">
        SELECT count(1) FROM product_order
        WHERE create_time &gt;= #{startDate} AND create_time &lt;= #{endDate}
        SELECT count(1)
        FROM product_order
        WHERE create_time &gt;= #{startDate}
          AND create_time &lt;= #{endDate}
          AND complete_quantity &lt; quantity
    </select>
</mapper>