gongchunyi
2026-04-16 18cfe1dfbe035089d1f132850004a74641f253b5
feat: 部件已产品绑定
已添加1个文件
已修改8个文件
287 ■■■■ 文件已修改
doc/君歌化工.sql 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductProcessController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductProcessDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductProcessImportDto.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductProcessMapper.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcess.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductProcessService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductProcessServiceImpl.java 150 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessMapper.xml 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/¾ý¸è»¯¹¤.sql
@@ -3,4 +3,17 @@
    MODIFY COLUMN `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '工序编号' AFTER `name`,
    MODIFY COLUMN `type` int NULL DEFAULT NULL COMMENT '类型1-加工,2-刮板冷芯制作、3-管路组对、4-罐体连接及调试,5-测试打压,6-其他' AFTER `is_quality`;
ALTER TABLE `product-inventory-management-jghg`.`product_process`
    COMMENT = '工序表';
    COMMENT = '工序表';
ALTER TABLE `product-inventory-management-jghg`.`product_process`
    MODIFY COLUMN `salary_quota` decimal(16, 3) NULL DEFAULT NULL COMMENT '计划工时' AFTER `tenant_id`;
ALTER TABLE `product_process`
    ADD COLUMN `planner_id`   bigint                                                       NULL COMMENT '计划人员ID' AFTER `device_ledger_id`,
    ADD COLUMN `planner_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '计划人员姓名' AFTER `planner_id`;
ALTER TABLE `product-inventory-management-jghg`.`product_process`
    ADD COLUMN `product_model_id` bigint NULL COMMENT '产品ID' AFTER `id`,
    MODIFY COLUMN `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '工序名称' AFTER `no`,
    MODIFY COLUMN `create_time` datetime NULL DEFAULT NULL COMMENT '录入时间' AFTER `dept_id`,
    MODIFY COLUMN `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间' AFTER `create_time`;
src/main/java/com/ruoyi/production/controller/ProductProcessController.java
@@ -8,7 +8,7 @@
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.dto.ProductProcessImportDto;
import com.ruoyi.production.service.ProductProcessService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -78,7 +78,7 @@
    @PostMapping("/downloadTemplate")
    @Log(title = "工序-下载模板", businessType = BusinessType.EXPORT)
    public void downloadTemplate(HttpServletResponse response) {
        ExcelUtil<ProductProcess> util = new ExcelUtil<>(ProductProcess.class);
        ExcelUtil<ProductProcessImportDto> util = new ExcelUtil<>(ProductProcessImportDto.class);
        util.importTemplateExcel(response, "工序模板");
    }
}
src/main/java/com/ruoyi/production/dto/ProductProcessDto.java
@@ -10,4 +10,8 @@
@Data
@ApiModel
public class ProductProcessDto extends ProductProcess {
    @ApiModelProperty("产品规格")
    private String productModel;
}
src/main/java/com/ruoyi/production/dto/ProductProcessImportDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package com.ruoyi.production.dto;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
/**
 * <br>
 * éƒ¨ä»¶å¯¼å…¥å¯¹è±¡
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/4/16 13:26
 */
@Data
public class ProductProcessImportDto {
    /**
     * éƒ¨ä»¶åç§°
     */
    @Excel(name = "部件名称")
    private String name;
    /**
     * éƒ¨ä»¶è§„æ ¼
     */
    @Excel(name = "部件规格")
    private String productModel;
    /**
     * å·¥åºç¼–号
     */
    @Excel(name = "部件编号")
    private String no;
    /**
     * è®¡åˆ’工时
     */
    @Excel(name = "计划工时")
    private BigDecimal salaryQuota;
    /**
     * éƒ¨ä»¶ç±»åž‹
     */
    @Excel(name = "部件类型")
    private String productProcessType;
    /**
     * è®¡åˆ’人员姓名
     */
    @Excel(name = "计划人员姓名")
    private String plannerName;
    /**
     * å¤‡æ³¨
     */
    @Excel(name = "备注")
    private String remark;
}
src/main/java/com/ruoyi/production/mapper/ProductProcessMapper.java
@@ -14,7 +14,8 @@
@Mapper
public interface ProductProcessMapper extends BaseMapper<ProductProcess> {
    IPage<ProductProcessDto> listPage(Page page,@Param("productProcessDto") ProductProcessDto productProcessDto);
    IPage<ProductProcessDto> listPage(Page page, @Param("productProcessDto") ProductProcessDto productProcessDto);
    List<processDataProductionStatisticsDto> calculateProductionStatistics(LocalDateTime startDateTime, LocalDateTime endDateTime, Long userId, List<Long> processIds);
}
src/main/java/com/ruoyi/production/pojo/ProductProcess.java
@@ -1,9 +1,7 @@
package com.ruoyi.production.pojo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -15,7 +13,6 @@
@TableName("product_process")
@Data
@ExcelIgnoreUnannotated
@ApiModel(value = "productProcess", description = "工序表")
public class ProductProcess implements Serializable {
@@ -24,23 +21,26 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * äº§å“è§„æ ¼ID
     */
    private Long productModelId;
    /**
     * å·¥åºåç§°
     */
    @Excel(name = "部件名称")
    private String name;
    /**
     * å·¥åºç¼–号
     */
    @Excel(name = "部件编号")
    private String no;
    /**
     * å·¥èµ„定额
     */
    @Excel(name = "工资定额")
    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private BigDecimal salaryQuota;
@@ -48,14 +48,9 @@
    @ApiModelProperty("类型1-加工,2-刮板冷芯制作、3-管路组对、4-罐体连接及调试,5-测试打压,6-其他")
    private Integer type;
    @TableField(exist = false)
    @Excel(name = "部件类型")
    private String ProductProcessType;
    /**
     * å¤‡æ³¨
     */
    @Excel(name = "备注")
    private String remark;
    /**
@@ -91,4 +86,10 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty("计划人员ID")
    private Long plannerId;
    @ApiModelProperty("计划人员姓名")
    private String plannerName;
}
src/main/java/com/ruoyi/production/service/ProductProcessService.java
@@ -14,6 +14,7 @@
 * @date : 2025/7/21 14:39
 */
public interface ProductProcessService extends IService<ProductProcess> {
    IPage<ProductProcessDto> listPage(Page page, ProductProcessDto productProcessDto);
    void add(ProductProcessDto productProcessDto);
src/main/java/com/ruoyi/production/service/impl/ProductProcessServiceImpl.java
@@ -1,13 +1,20 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.service.IProductModelService;
import com.ruoyi.basic.service.IProductService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.dto.ProductProcessImportDto;
import com.ruoyi.production.enums.ProductProcessEnum;
import com.ruoyi.production.mapper.ProcessRouteItemMapper;
import com.ruoyi.production.mapper.ProductProcessMapper;
@@ -16,6 +23,9 @@
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.ProductProcessRouteItem;
import com.ruoyi.production.service.ProductProcessService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.project.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -24,11 +34,14 @@
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class ProductProcessServiceImpl extends ServiceImpl<ProductProcessMapper, ProductProcess> implements ProductProcessService {
public class ProductProcessServiceImpl extends ServiceImpl<ProductProcessMapper, ProductProcess>
        implements ProductProcessService {
    @Autowired
    private ProductProcessMapper productProcessMapper;
@@ -38,6 +51,15 @@
    @Autowired
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    @Autowired
    private IProductModelService productModelService;
    @Autowired
    private IProductService productService;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Override
    public IPage<ProductProcessDto> listPage(Page page, ProductProcessDto productProcessDto) {
@@ -50,10 +72,6 @@
        if (ObjectUtils.isEmpty(productProcessDto.getName())) {
            throw new ServiceException("部件名称不能为空");
        }
        long count = this.count(Wrappers.<ProductProcess>lambdaQuery().eq(ProductProcess::getName, productProcessDto.getName()));
        if (count > 0) {
            throw new ServiceException("部件名称已存在,不能重复");
        }
        if (ObjectUtils.isNotEmpty(productProcessDto.getNo())) {
            long noCount = this.count(Wrappers.<ProductProcess>lambdaQuery().eq(ProductProcess::getNo, productProcessDto.getNo()));
@@ -61,13 +79,28 @@
                throw new ServiceException("工序编号已存在,不能重复");
            }
        }
        // åˆ¤æ–­è®¡åˆ’工时是否为空
        if (ObjectUtils.isEmpty(productProcessDto.getSalaryQuota())) {
            throw new ServiceException("新增失败,计划工时不能为空");
        }
        // åˆ¤æ–­äº§å“æ˜¯å¦å­˜åœ¨
        if (ObjectUtils.isEmpty(productProcessDto.getProductModelId())) {
            throw new ServiceException("新增失败,部件不能为空");
        }
        ProductModel productModel = productModelService.getById(productProcessDto.getProductModelId());
        if (productModel == null) {
            throw new ServiceException("新增失败,该部件不存在");
        }
        ProductProcess productProcess = new ProductProcess();
        BeanUtils.copyProperties(productProcessDto, productProcess);
        productProcess.setProductModelId(productModel.getId());
        validatePlanner(productProcessDto.getPlannerId(), productProcessDto.getPlannerName(), null);
        boolean save = productProcessMapper.insert(productProcess) > 0;
        if (save && ObjectUtils.isEmpty(productProcess.getNo())) {
            String no = "GX" + String.format("%08d", productProcess.getId());
            // æ³¨æ„ï¼šè¿™é‡Œç”±äºŽæ˜¯è‡ªåŠ¨ç”Ÿæˆçš„ ID è¡¥å…¨ï¼Œé€šå¸¸ä¸ä¼šé‡å¤ï¼Œä½†å»ºè®® set ä¹‹åŽæ›´æ–°
            productProcess.setNo(no);
            productProcessMapper.updateById(productProcess);
        }
@@ -79,13 +112,6 @@
        if (ObjectUtils.isEmpty(productProcessDto.getName())) {
            throw new ServiceException("部件名称不能为空");
        }
        long nameCount = this.count(Wrappers.<ProductProcess>lambdaQuery()
                .eq(ProductProcess::getName, productProcessDto.getName())
                .ne(ProductProcess::getId, productProcessDto.getId()));
        if (nameCount > 0) {
            throw new ServiceException("部件名称已存在,不能重复");
        }
        if (ObjectUtils.isNotEmpty(productProcessDto.getNo())) {
            long noCount = this.count(Wrappers.<ProductProcess>lambdaQuery()
                    .eq(ProductProcess::getNo, productProcessDto.getNo())
@@ -94,6 +120,17 @@
                throw new ServiceException("工序编号已存在,不能重复");
            }
        }
        // åˆ¤æ–­å…³è”产品是否存在
        if (ObjectUtils.isNotEmpty(productProcessDto.getProductModelId())) {
            ProductModel productModel = productModelService.getById(productProcessDto.getProductModelId());
            if (productModel == null) {
                throw new ServiceException("修改失败,关联部件不存在");
            }
        }
        // æ ¡éªŒè®¡åˆ’人员
        validatePlanner(productProcessDto.getPlannerId(), productProcessDto.getPlannerName(), null);
        ProductProcess productProcess = new ProductProcess();
        BeanUtils.copyProperties(productProcessDto, productProcess);
@@ -104,31 +141,66 @@
    @Transactional(rollbackFor = Exception.class)
    public void importData(MultipartFile file) {
        try {
            ExcelUtil<ProductProcess> util = new ExcelUtil<>(ProductProcess.class);
            List<ProductProcess> productProcessList = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(productProcessList)) {
            ExcelUtil<ProductProcessImportDto> util = new ExcelUtil<>(ProductProcessImportDto.class);
            List<ProductProcessImportDto> importList = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(importList)) {
                throw new ServiceException("模板错误或导入数据为空");
            }
            for (int i = 0; i < productProcessList.size(); i++) {
                ProductProcess productProcess = productProcessList.get(i);
            List<ProductProcess> productProcessList = new ArrayList<>();
            for (int i = 0; i < importList.size(); i++) {
                ProductProcessImportDto importDto = importList.get(i);
                int rowNum = i + 2;
                SysUser sysUser = null;
                if (ObjectUtils.isEmpty(productProcess)) {
                if (ObjectUtils.isEmpty(importDto)) {
                    throw new ServiceException("第" + rowNum + "行数据为空,请使用正确的模板进行导入");
                }
                if (ObjectUtils.isEmpty(productProcess.getName())) {
                if (ObjectUtils.isEmpty(importDto.getName())) {
                    throw new ServiceException("第" + rowNum + "行:部件名称不能为空");
                }
                if (ObjectUtils.isEmpty(productProcess.getProductProcessType())) {
                    throw new ServiceException("第" + rowNum + "行:部件【" + productProcess.getName() + "】的类型不能为空");
                if (ObjectUtils.isEmpty(importDto.getProductModel())) {
                    throw new ServiceException("第" + rowNum + "行:部件规格不能为空");
                }
                ProductProcessEnum enumByInfo = ProductProcessEnum.getEnumByInfo(productProcess.getProductProcessType());
                //  æ£€éªŒäº§å“ä¸Žç±»åž‹æ˜¯å¦å­˜åœ¨
                Product product = productService.getOne(new LambdaQueryWrapper<Product>().eq(Product::getProductName, importDto.getName()));
                if (product == null) {
                    throw new ServiceException("第" + rowNum + "行: éƒ¨ä»¶ã€" + importDto.getName() + "】不存在");
                }
                ProductModel productModel = productModelService.getOne(new LambdaQueryWrapper<ProductModel>().eq(ProductModel::getProductId, product.getId()).eq(ProductModel::getModel, importDto.getProductModel()));
                if (ObjectUtils.isEmpty(productModel)) {
                    throw new ServiceException("第" + rowNum + "行:部件规格【" + importDto.getProductModel() + "】不存在");
                }
                if (ObjectUtils.isEmpty(importDto.getProductProcessType())) {
                    throw new ServiceException("第" + rowNum + "行:部件【" + importDto.getName() + "】的类型不能为空");
                }
                ProductProcessEnum enumByInfo = ProductProcessEnum.getEnumByInfo(importDto.getProductProcessType());
                if (ObjectUtils.isEmpty(enumByInfo)) {
                    throw new ServiceException("第" + rowNum + "行:部件【" + productProcess.getName() + "】的类型【" + productProcess.getProductProcessType() + "】不存在,请填写正确的类型:加工、刮板冷芯制作、管路组对、罐体连接及调试、测试打压、其他");
                }else {
                    productProcess.setType(enumByInfo.getCode());
                    throw new ServiceException("第" + rowNum + "行:部件【" + importDto.getName() + "】的类型【"
                            + importDto.getProductProcessType() + "】不存在,请填写正确的类型:加工、刮板冷芯制作、管路组对、罐体连接及调试、测试打压、其他");
                }
                // æ£€éªŒè®¡åˆ’工时
                if (importDto.getSalaryQuota() == null || importDto.getSalaryQuota().compareTo(BigDecimal.ZERO) < 0) {
                    throw new ServiceException("第" + rowNum + "行:计划工时不能为空与负数");
                }
                // æ£€éªŒè®¡åˆ’人员
                if (StringUtils.isNotEmpty(importDto.getPlannerName())) {
                    sysUser = sysUserMapper.selectUserByNickName(importDto.getPlannerName());
                    if (ObjectUtils.isEmpty(sysUser)) {
                        throw new ServiceException("第" + rowNum + "行:计划人员【" + importDto.getPlannerName() + "】不存在");
                    }
                }
                ProductProcess productProcess = new ProductProcess();
                BeanUtils.copyProperties(importDto, productProcess);
                productProcess.setProductModelId(productModel.getId());
                productProcess.setType(enumByInfo.getCode());
                if (sysUser != null) {
                    productProcess.setPlannerId(sysUser.getUserId());
                    productProcess.setPlannerName(sysUser.getUserName());
                }
                productProcessList.add(productProcess);
            }
            saveOrUpdateBatch(productProcessList);
@@ -140,12 +212,34 @@
        }
    }
    /**
     * æ ¡éªŒè®¡åˆ’人员是否存在
     *
     * @param plannerId   è®¡åˆ’人员ID
     * @param plannerName è®¡åˆ’人员姓名
     * @param rowNum      è¡Œå·
     */
    private void validatePlanner(Long plannerId, String plannerName, Integer rowNum) {
        String prefix = rowNum != null ? "第" + rowNum + "行:" : "";
        if (plannerId != null) {
            if (sysUserMapper.selectUserById(plannerId) == null) {
                throw new ServiceException(prefix + "计划人员ID【" + plannerId + "】不存在");
            }
        } else if (ObjectUtils.isNotEmpty(plannerName)) {
            if (sysUserMapper.selectUserByNickName(plannerName) == null) {
                throw new ServiceException(prefix + "计划人员姓名【" + plannerName + "】不存在");
            }
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<Integer> ids) {
        // æŸ¥è¯¢æ˜¯å¦ç”Ÿäº§ä¸­å·²ç»å¼•用了这些工序
        List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(Wrappers.<ProcessRouteItem>lambdaQuery().in(ProcessRouteItem::getProcessId, ids));
        List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().in(ProductProcessRouteItem::getProcessId, ids));
        List<ProcessRouteItem> processRouteItems = processRouteItemMapper
                .selectList(Wrappers.<ProcessRouteItem>lambdaQuery().in(ProcessRouteItem::getProcessId, ids));
        List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(
                Wrappers.<ProductProcessRouteItem>lambdaQuery().in(ProductProcessRouteItem::getProcessId, ids));
        if (!CollectionUtils.isEmpty(processRouteItems) || !CollectionUtils.isEmpty(productProcessRouteItems)) {
            throw new ServiceException("该工序已经被使用,无法删除");
        }
src/main/resources/mapper/production/ProductProcessMapper.xml
@@ -4,18 +4,33 @@
    <select id="listPage" resultType="com.ruoyi.production.dto.ProductProcessDto">
        SELECT
        *
        pp.id,
        pp.no,
        pp.remark,
        pp.salary_quota,
        pp.is_quality,
        pp.planner_id,
        pp.planner_name,
        pp.update_time,
        pp.type,
        p.product_name AS name,
        pm.model AS productModel
        FROM
        product_process p
        product_process pp
        left join product_model pm ON pm.id = pp.product_model_id
        left join product p ON p.id = pm.product_id
        <where>
            <if test="productProcessDto.name != null and productProcessDto.name != '' ">
                AND  p.name LIKE CONCAT('%',#{productProcessDto.name},'%')
                AND p.product_name LIKE CONCAT('%',#{productProcessDto.name},'%')
            </if>
            <if test="productProcessDto.no != null and productProcessDto.no != '' ">
                AND  p.no LIKE CONCAT('%',#{productProcessDto.no},'%')
                AND pp.no LIKE CONCAT('%',#{productProcessDto.no},'%')
            </if>
            <if test="productProcessDto.type != null">
                AND pp.type = #{productProcessDto.type}
            </if>
        </where>
        order by p.id asc
        order by pp.id asc
    </select>
    <select id="calculateProductionStatistics" resultType="com.ruoyi.home.dto.processDataProductionStatisticsDto">