liyong
2026-04-23 8c8ff31cdca25f579d3c1f688f46c877bf28aaa1
feat(approve): 重构审批流程配置功能

- 将VO类移动到bean.vo包下并更新导入路径
- 添加审批流程配置节点相关实体、控制器、服务和映射器
- 实现审批流程配置节点的增删改查功能
- 重构审批流程服务逻辑,集成新的配置节点功能
- 更新设备维修状态更新逻辑,移除审批完成后的状态变更
- 优化审批流程配置节点的数据结构和业务处理
已添加1个文件
已修改8个文件
434 ■■■■ 文件已修改
src/main/java/com/ruoyi/approve/bean/vo/ApproveProcessVO.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/vo/KnowledgeBaseVo.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/controller/KnowledgeBaseController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/mapper/KnowledgeBaseMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/KnowledgeBaseService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessConfigNodeServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java 282 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/bean/vo/ApproveProcessVO.java
@@ -3,9 +3,12 @@
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import com.ruoyi.sales.pojo.CommonFile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@@ -44,8 +47,6 @@
     * å®¡æ‰¹ç†ç”±
     */
    private String approveReason;
    private Long recordId;
    @Excel(name = "开始时间", dateFormat = "yyyy-MM-dd",width = 30)
    @JsonFormat(pattern = "yyyy-MM-dd")
src/main/java/com/ruoyi/approve/bean/vo/KnowledgeBaseVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.ruoyi.approve.bean.vo;
import com.ruoyi.approve.pojo.KnowledgeBase;
import com.ruoyi.approve.pojo.KnowledgeBaseFile;
import lombok.Data;
import java.util.List;
@Data
public class KnowledgeBaseVo extends KnowledgeBase {
    private List<KnowledgeBaseFile> files;
}
src/main/java/com/ruoyi/approve/controller/KnowledgeBaseController.java
@@ -3,8 +3,11 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.mapper.KnowledgeBaseMapper;
import com.ruoyi.approve.bean.vo.KnowledgeBaseVo;
import com.ruoyi.approve.pojo.KnowledgeBase;
import com.ruoyi.approve.pojo.RpaProcessAutomation;
import com.ruoyi.approve.pojo.KnowledgeBaseFile;
import com.ruoyi.approve.service.KnowledgeBaseFileService;
import com.ruoyi.approve.service.KnowledgeBaseService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
src/main/java/com/ruoyi/approve/mapper/KnowledgeBaseMapper.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.bean.vo.KnowledgeBaseVo;
import com.ruoyi.approve.pojo.KnowledgeBase;
import org.apache.ibatis.annotations.Mapper;
src/main/java/com/ruoyi/approve/service/KnowledgeBaseService.java
@@ -3,8 +3,10 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.approve.bean.vo.KnowledgeBaseVo;
import com.ruoyi.approve.pojo.KnowledgeBase;
public interface KnowledgeBaseService extends IService<KnowledgeBase> {
    IPage<KnowledgeBase> listpage(Page page, KnowledgeBase knowledgeBase);
}
src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.mapper.ApproveNodeMapper;
@@ -12,8 +13,10 @@
import com.ruoyi.approve.service.IApproveNodeService;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.device.mapper.DeviceRepairMapper;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.other.service.impl.TempFileServiceImpl;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.project.system.domain.SysUser;
@@ -38,7 +41,6 @@
import com.ruoyi.sales.pojo.SalesQuotation;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
import com.ruoyi.sales.service.impl.SalesLedgerProductServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@@ -71,7 +73,6 @@
    private final QualityTestStandardMapper qualityTestStandardMapper;
    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
    private final QualityInspectParamMapper qualityInspectParamMapper;
    private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
    public ApproveProcess getApproveById(String id) {
@@ -167,11 +168,11 @@
        approveProcessMapper.updateById(approveProcess);
        //采购审核
        if (approveProcess.getApproveType().equals(5)) {
        if(approveProcess.getApproveType().equals(5)){
            PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
                    .eq(PurchaseLedger::getPurchaseContractNumber, approveProcess.getApproveReason())
                    .last("limit 1"));
            if (purchaseLedger != null) {
            if(purchaseLedger != null) {
                if (status.equals(2)) {
                    // åŒæ„
                    purchaseLedger.setApprovalStatus(3);
@@ -180,8 +181,7 @@
                    for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
                        // è´¨æ£€
                        if (salesLedgerProduct.getIsChecked()) {
                            addQualityInspect(purchaseLedger, salesLedgerProduct);
                        } else {
                            addQualityInspect(purchaseLedger, salesLedgerProduct);                        }else {
                            //直接入库
                            stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId());
                        }
@@ -197,47 +197,41 @@
            }
        }
        // é”€å”®æŠ¥ä»·çŠ¶æ€ä¿®æ”¹
        if (approveProcess.getApproveType().equals(6)) {
        if(approveProcess.getApproveType().equals(6)){
            SalesQuotation salesQuote = salesQuotationMapper.selectOne(new LambdaQueryWrapper<SalesQuotation>()
                    .eq(SalesQuotation::getQuotationNo, approveProcess.getApproveReason())
                    .last("limit 1"));
            // åŒæ„
            if (status.equals(2) && salesQuote != null) {
            if(status.equals(2) && salesQuote != null){
                salesQuote.setStatus("通过");
            } else if (status.equals(3) && salesQuote != null) {
            }else if(status.equals(3) && salesQuote != null){
                salesQuote.setStatus("拒绝");
            } else if (status.equals(1) && salesQuote != null) {
            }else if(status.equals(1) && salesQuote != null){
                salesQuote.setStatus("审核中");
            }
            salesQuotationMapper.updateById(salesQuote);
        }
        // å‡ºåº“审批修改
        if (approveProcess.getApproveType().equals(7)) {
        if(approveProcess.getApproveType().equals(7)){
            String[] split = approveProcess.getApproveReason().split(":");
            ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
                    .eq(ShippingInfo::getShippingNo, split[1])
                    .orderByDesc(ShippingInfo::getCreateTime)
                    .last("limit 1"));
            if (shippingInfo != null) {
                if (status.equals(2)) {
            if(shippingInfo != null){
                if(status.equals(2)){
                    shippingInfo.setStatus("审核通过");
                } else if (status.equals(3)) {
                }else if(status.equals(3)){
                    shippingInfo.setStatus("审核拒绝");
                } else if (status.equals(1)) {
                }else if(status.equals(1)){
                    shippingInfo.setStatus("审核中");
                }
                shippingInfoMapper.updateById(shippingInfo);
            }
        }
        //销售审批成功之后添加生产数据
        if (approveProcess.getApproveType().equals(9)) {
            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
                    .eq(SalesLedgerProduct::getSalesLedgerId, approveProcess.getRecordId()));
            salesLedgerProducts.forEach(salesLedgerProductServiceImpl::addProductionData);
        }
        // ç»‘定附件
        if (!CollectionUtils.isEmpty(approveNode.getTempFileIds()) && approveNode.getApproveNodeStatus() == 1) {
        if(!CollectionUtils.isEmpty(approveNode.getTempFileIds()) && approveNode.getApproveNodeStatus() == 1){
            tempFileService.migrateTempFilesToFormal(approveNode.getId(), approveNode.getTempFileIds(), FileNameType.ApproveNode.getValue());
        }
    }
@@ -245,21 +239,21 @@
    @Override
    public void updateApproveNode(ApproveNode approveNode) throws IOException {
        // å®¡æ‰¹èŠ‚ç‚¹çŠ¶æ€:1同意,2拒绝,0尚未审核
        switch (approveNode.getApproveNodeStatus()) {
        switch (approveNode.getApproveNodeStatus()){
            case 1:
                updateApproveProcessStatus(approveNode, Boolean.TRUE.equals(approveNode.getIsLast()) ? 2 : 1);
                /*消息通知*/
                Integer nodeOrder = approveNode.getApproveNodeOrder();
                ApproveProcess approveProcess = approveProcessMapper.selectList(Wrappers.<ApproveProcess>lambdaQuery()
                        .eq(ApproveProcess::getApproveId, approveNode.getApproveProcessId())).get(0);
                if (approveProcess.getApproveUserIds().split(",").length > nodeOrder) {
                if (approveProcess.getApproveUserIds().split(",").length > nodeOrder){
                    String id = approveProcess.getApproveUserIds().split(",")[nodeOrder];
                    if (approveProcess.getApproveType() == 8) {
                    if (approveProcess.getApproveType()==8){
                        sysNoticeService.simpleNoticeByUser(approveProcessType(approveProcess.getApproveType()),
                                approveProcess.getApproveId() + "流程编号的审批需要您审核!!!!!",
                                Arrays.asList(Long.valueOf(id)),
                                "/safeProduction/safeWorkApproval?approveType=" + approveProcess.getApproveType() + "&approveId=" + approveProcess.getApproveId());
                    } else {
                    }else {
                        sysNoticeService.simpleNoticeByUser(approveProcessType(approveProcess.getApproveType()),
                                approveProcess.getApproveId() + "流程编号的审批需要您审核!!!!!",
                                Arrays.asList(Long.valueOf(id)),
@@ -292,8 +286,8 @@
    }
    //审批类型获取(与前端页面对应)
    private String approveProcessType(Integer approveType) {
        switch (approveType) {
    private String approveProcessType(Integer approveType){
        switch (approveType){
            case 1:
                return "公出管理";
            case 2:
@@ -310,8 +304,6 @@
                return "发货审批";
            case 8:
                return "危险作业审批";
            case 9:
                return "销售审批";
        }
        return null;
    }
@@ -328,12 +320,12 @@
        qualityInspect.setUnit(saleProduct.getUnit());
        qualityInspect.setQuantity(saleProduct.getQuantity());
        qualityInspectMapper.insert(qualityInspect);
        List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null);
        if (qualityTestStandard.size() > 0) {
        List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0,null);
        if (qualityTestStandard.size()>0){
            qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
            qualityInspectMapper.updateById(qualityInspect);
            qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
                            .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
                            .eq(QualityTestStandardParam::getTestStandardId,qualityTestStandard.get(0).getId()))
                    .forEach(qualityTestStandardParam -> {
                        QualityInspectParam param = new QualityInspectParam();
                        com.ruoyi.common.utils.bean.BeanUtils.copyProperties(qualityTestStandardParam, param);
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessConfigNodeServiceImpl.java
@@ -42,7 +42,9 @@
        //删除旧数据
        approveProcessConfigNodeMapper.delete(new QueryWrapper<ApproveProcessConfigNode>().lambda().eq(ApproveProcessConfigNode::getApproveType, approveProcessConfigNodes.get(0).getApproveType()));
        //新增 æ•°æ®
        approveProcessConfigNodes.forEach(approveProcessConfigNodeMapper::insert);
        for (ApproveProcessConfigNode node : approveProcessConfigNodes) {
            approveProcessConfigNodeMapper.insert(node);
        }
        return true;
    }
}
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -10,11 +10,9 @@
import com.ruoyi.approve.bean.vo.ApproveProcessConfigNodeVo;
import com.ruoyi.approve.bean.vo.ApproveProcessVO;
import com.ruoyi.approve.mapper.ApproveNodeMapper;
import com.ruoyi.approve.mapper.ApproveProcessConfigNodeMapper;
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveNode;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.pojo.ApproveProcessConfigNode;
import com.ruoyi.approve.service.ApproveProcessConfigNodeService;
import com.ruoyi.approve.service.IApproveNodeService;
import com.ruoyi.approve.service.IApproveProcessService;
@@ -65,19 +63,15 @@
    private final ShippingInfoMapper shippingInfoMapper;
    private final ApproveNodeMapper approveNodeMapper;
    private final ApproveProcessConfigNodeService approveProcessConfigNodeService;
    private final ApproveProcessConfigNodeMapper approveProcessConfigNodeMapper;
    @Override
    public void addApprove(ApproveProcessVO approveProcessVO) throws Exception {
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        SysDept sysDept = sysDeptMapper.selectDeptById(SecurityUtils.getLoginUser().getCurrentDeptId());
        List<ApproveProcessConfigNodeVo> list = approveProcessConfigNodeService.listNode(approveProcessVO.getApproveType());
        List<ApproveProcessConfigNodeVo> list = approveProcessConfigNodeService.listNode( approveProcessVO.getApproveType());
        List<Long> nodeIds = list.stream()
                .map(ApproveProcessConfigNodeVo::getApproverId)
                .collect(Collectors.toList());
        if (list.isEmpty()) {
            throw new RuntimeException("流程不存在");
        }
        List<SysUser> sysUsers = sysUserMapper.selectUserByIds(nodeIds);
        if (CollectionUtils.isEmpty(sysUsers)) throw new RuntimeException("审核用户不存在");
        if (sysDept == null) throw new RuntimeException("部门不存在");
@@ -89,7 +83,7 @@
//        String approveID = today + formattedCount;
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        ApproveProcess approveProcess = new ApproveProcess();
        String no = OrderUtils.countTodayByCreateTime(approveProcessMapper, "", "approve_id");
        String no = OrderUtils.countTodayByCreateTime(approveProcessMapper, "approve_id");
        approveProcess.setApproveId(no);
        approveProcess.setApproveUser(sysUser.getUserId());
        approveProcess.setApproveUserName(sysUser.getNickName());
@@ -97,10 +91,9 @@
        approveProcess.setApproveUserIds(nodeIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
        approveProcess.setApproveDeptName(sysDept.getDeptName());
        approveProcess.setApproveUserNames(sysUsers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
        approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? new Date() : dateFormat.parse(approveProcessVO.getApproveTime()));
        approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? new Date(): dateFormat.parse(approveProcessVO.getApproveTime()));
        approveProcess.setApproveReason(approveProcessVO.getApproveReason());
        approveProcess.setDeviceRepairId(approveProcessVO.getDeviceRepairId());
        approveProcess.setRecordId(approveProcessVO.getRecordId());
        approveProcess.setMaintenancePrice(approveProcessVO.getMaintenancePrice());
        approveProcess.setPrice(approveProcessVO.getPrice());
        approveProcess.setStartDate(approveProcessVO.getStartDate());
@@ -133,12 +126,12 @@
        tempFileService.migrateTempFilesToFormal(approveProcess.getId(), approveProcessVO.getTempFileIds(), FileNameType.ApproveProcess.getValue());
        /*消息通知*/
        Long id = nodeIds.get(0);
        if (approveProcess.getApproveType() == 8) {
        if (approveProcess.getApproveType()==8){
            sysNoticeService.simpleNoticeByUser(approveProcessType(approveProcess.getApproveType()),
                    approveProcess.getApproveId() + "流程编号的审批需要您审核!!!!!",
                    Collections.singletonList(id),
                    "/safeProduction/safeWorkApproval?approveType=" + approveProcess.getApproveType() + "&approveId=" + approveProcess.getApproveId());
        } else {
        }else {
            sysNoticeService.simpleNoticeByUser(approveProcessType(approveProcess.getApproveType()),
                    approveProcess.getApproveId() + "流程编号的审批需要您审核!!!!!",
                    Collections.singletonList(id),
@@ -155,6 +148,7 @@
        }
        return sysDeptList;
    }
    @Override
    public IPage<ApproveProcess> listAll(Page page, ApproveProcess approveProcess) {
@@ -275,9 +269,9 @@
            //  åˆ é™¤å¯¹åº”的消息通知
            sysNoticeService.remove(new LambdaQueryWrapper<SysNotice>()
                    .eq(SysNotice::getNoticeTitle, approveProcessType(latestProcess.getApproveType()))
                    .eq(SysNotice::getSenderId, latestProcess.getApproveUser())
                    .apply("CAST(notice_content AS CHAR) LIKE CONCAT('%', {0}, '%')", latestProcess.getApproveId()));
                            .eq(SysNotice::getNoticeTitle, approveProcessType(latestProcess.getApproveType()))
                            .eq(SysNotice::getSenderId, latestProcess.getApproveUser())
                            .apply("CAST(notice_content AS CHAR) LIKE CONCAT('%', {0}, '%')", latestProcess.getApproveId()));
        }
    }
@@ -285,8 +279,8 @@
    @Override
    public ApproveProcess getApproveById(String id) {
        ApproveProcess one = approveProcessMapper.selectList(Wrappers.<ApproveProcess>lambdaQuery()
                .eq(ApproveProcess::getApproveId, id)
                .eq(ApproveProcess::getApproveDelete, 0)).get(0);
                .eq(ApproveProcess::getApproveId,id)
                .eq(ApproveProcess::getApproveDelete,0)).get(0);
        one.setCommonFileList(commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
                .eq(CommonFile::getCommonId, one.getId())
                .eq(CommonFile::getType, FileNameType.ApproveProcess.getValue())));
@@ -301,20 +295,17 @@
                .eq(ApproveProcess::getApproveReason, approveGetAndUpdateVo.getApproveReason())
                .last("limit 1");
        ApproveProcess approveProcess = approveProcessMapper.selectOne(approveProcessLambdaQueryWrapper);
        if (approveProcess == null) throw new RuntimeException("请选择审批人");
        //查询审批配置
        List<ApproveProcessConfigNode> approveProcessConfig = approveProcessConfigNodeMapper.selectList(new LambdaQueryWrapper<ApproveProcessConfigNode>().eq(ApproveProcessConfigNode::getApproveType, approveGetAndUpdateVo.getApproveType()));
        List<Long> configNodeIds = approveProcessConfig.stream()
                .sorted(Comparator.comparing(ApproveProcessConfigNode::getNodeOrder))
                .map(ApproveProcessConfigNode::getApproverId)
                .collect(Collectors.toList());
        List<SysUser> sysUsers = sysUserMapper.selectUserByIds(configNodeIds);
        String[] split = approveGetAndUpdateVo.getApproveUserIds().split(",");
        if (split.length == 0) {
            throw new RuntimeException("请选择审批人");
        }
        List<SysUser> sysUsers = sysUserMapper.selectUserByIds(Arrays.asList(split).stream().map(Long::parseLong).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(sysUsers)) throw new RuntimeException("请选择审批人");
        //审核中不可以编辑审核人
        if (approveProcess.getApproveStatus() != 1) {
            approveProcess.setApproveUserCurrentId(configNodeIds.get(0));
            approveProcess.setApproveUserCurrentName(sysUsers.stream().filter(user -> user.getUserId().equals(configNodeIds.get(0))).collect(Collectors.toList()).get(0).getNickName());
            approveProcess.setApproveUserCurrentId(Long.parseLong(split[0]));
            approveProcess.setApproveUserCurrentName(sysUsers.stream().filter(user -> user.getUserId().equals(Long.parseLong(split[0]))).collect(Collectors.toList()).get(0).getNickName());
        }
        if (approveGetAndUpdateVo.getApproveStatus() != null) {
            approveProcess.setApproveStatus(approveGetAndUpdateVo.getApproveStatus());
@@ -326,24 +317,21 @@
        LambdaQueryWrapper<ApproveNode> approveNodeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        approveNodeLambdaQueryWrapper.eq(ApproveNode::getApproveProcessId, approveProcess.getApproveId())
                .eq(ApproveNode::getDeleteFlag, 0)
//                .eq(ApproveNode::getTenantId, SecurityUtils.getLoginUser().getTenantId())
                .orderByAsc(ApproveNode::getApproveNodeOrder);
        approveNodeMapper.delete(approveNodeLambdaQueryWrapper);
        //查询审批配置
        approveGetAndUpdateVo.setApproveUserIds(configNodeIds.stream()
                .map(String::valueOf)
                .collect(Collectors.joining(",")));
        approveNodeService.initApproveNodes(approveGetAndUpdateVo.getApproveUserIds(), approveProcess.getApproveId(), approveProcess.getTenantId());
        /*消息通知*/
        Long id = configNodeIds.get(0);
        if (approveProcess.getApproveType() == 8) {
        String id = approveProcess.getApproveUserIds().split(",")[0];
        if (approveProcess.getApproveType()==8){
            sysNoticeService.simpleNoticeByUser(approveProcessType(approveProcess.getApproveType()),
                    approveProcess.getApproveId() + "流程编号的审批需要您审核!!!!!",
                    Collections.singletonList(id),
                    Arrays.asList(Long.valueOf(id)),
                    "/safeProduction/safeWorkApproval?approveType=" + approveProcess.getApproveType() + "&approveId=" + approveProcess.getApproveId());
        } else {
        }else {
            sysNoticeService.simpleNoticeByUser(approveProcessType(approveProcess.getApproveType()),
                    approveProcess.getApproveId() + "流程编号的审批需要您审核!!!!!",
                    Collections.singletonList(id),
                    Arrays.asList(Long.valueOf(id)),
                    "/collaborativeApproval/approvalProcess?approveType=" + approveProcess.getApproveType() + "&approveId=" + approveProcess.getApproveId());
        }
    }
@@ -400,12 +388,12 @@
        tempFileService.migrateTempFilesToFormal(approve.getId(), approveGetAndUpdateVo.getTempFileIds(), FileNameType.ApproveProcess.getValue());
        /*消息通知*/
        String id = approve.getApproveUserIds().split(",")[0];
        if (approve.getApproveType() == 8) {
        if (approve.getApproveType()==8){
            sysNoticeService.simpleNoticeByUser(approveProcessType(approve.getApproveType()),
                    approve.getApproveId() + "流程编号的审批需要您审核!!!!!",
                    Arrays.asList(Long.valueOf(id)),
                    "/safeProduction/safeWorkApproval?approveType=" + approve.getApproveType() + "&approveId=" + approve.getApproveId());
        } else {
        }else {
            sysNoticeService.simpleNoticeByUser(approveProcessType(approve.getApproveType()),
                    approve.getApproveId() + "流程编号的审批需要您审核!!!!!",
                    Arrays.asList(Long.valueOf(id)),
@@ -434,8 +422,6 @@
                return "发货审批";
            case 8:
                return "危险作业审批";
            case 9:
                return "销售审批";
        }
        return null;
    }
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -4,64 +4,53 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.service.IApproveProcessService;
import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
import com.ruoyi.approve.bean.vo.ApproveGetAndUpdateVo;
import com.ruoyi.approve.bean.vo.ApproveProcessVO;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.sales.dto.QuotationRecordJSON;
import com.ruoyi.sales.dto.SalesQuotationDto;
import com.ruoyi.sales.mapper.QuotationRecordMapper;
import com.ruoyi.sales.mapper.SalesQuotationMapper;
import com.ruoyi.sales.mapper.SalesQuotationProductMapper;
import com.ruoyi.sales.pojo.SalesQuotation;
import com.ruoyi.sales.pojo.SalesQuotationProduct;
import com.ruoyi.sales.service.QuotationRecordService;
import com.ruoyi.sales.service.SalesQuotationProductService;
import com.ruoyi.sales.service.SalesQuotationService;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class SalesQuotationServiceImpl extends ServiceImpl<SalesQuotationMapper, SalesQuotation> implements SalesQuotationService {
    private final SalesQuotationMapper salesQuotationMapper;
    private final SalesQuotationProductMapper salesQuotationProductMapper;
    private final SalesQuotationProductService salesQuotationProductService;
    private final ApproveProcessServiceImpl approveProcessService;
    private final CustomerMapper customerMapper;
    private final SysUserMapper sysUserMapper;
    private final ProductModelMapper productModelMapper;
    private final QuotationRecordMapper quotationRecordMapper;
    private final QuotationRecordService quotationRecordsService;
    @Autowired
    private SalesQuotationMapper salesQuotationMapper;
    @Autowired
    private SalesQuotationProductMapper salesQuotationProductMapper;
    @Autowired
    private SalesQuotationProductService salesQuotationProductService;
    @Autowired
    private ApproveProcessServiceImpl approveProcessService;
    @Override
    public IPage<SalesQuotationDto> listPage(Page page, SalesQuotationDto salesQuotationDto) {
        IPage<SalesQuotationDto> salesQuotationDtoIPage = salesQuotationMapper.listPage(page, salesQuotationDto);
        if (CollectionUtils.isEmpty(salesQuotationDtoIPage.getRecords())) {
        if(CollectionUtils.isEmpty(salesQuotationDtoIPage.getRecords())){
            return salesQuotationDtoIPage;
        }
        salesQuotationDtoIPage.getRecords().forEach(record -> {
@@ -76,11 +65,11 @@
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SalesQuotation salesQuotation = new SalesQuotation();
        BeanUtils.copyProperties(salesQuotationDto, salesQuotation);
        String quotationNo = OrderUtils.countTodayByCreateTime(salesQuotationMapper, "QT", "quotation_no");
        String quotationNo = OrderUtils.countTodayByCreateTime(salesQuotationMapper, "QT","quotation_no");
        salesQuotation.setQuotationNo(quotationNo);
        salesQuotation.setStatus("待审批");
        salesQuotationMapper.insert(salesQuotation);
        if (CollectionUtils.isEmpty(salesQuotationDto.getProducts())) {
        if(CollectionUtils.isEmpty(salesQuotationDto.getProducts())){
            return true;
        }
        List<SalesQuotationProduct> products = salesQuotationDto.getProducts().stream().map(product -> {
@@ -101,38 +90,26 @@
        approveProcessVO.setPrice(salesQuotationDto.getTotalAmount());
        try {
            approveProcessService.addApprove(approveProcessVO);
        } catch (Exception e) {
        }catch (Exception e){
            log.error("SalesQuotationServiceImpl error:{}", e);
            throw new RuntimeException("审批失败");
        }
        return true;
    }
    @Override
    public boolean edit(SalesQuotationDto salesQuotationDto) {
        SalesQuotation salesQuotation = new SalesQuotation();
        BeanUtils.copyProperties(salesQuotationDto, salesQuotation);
//        if ("拒绝".equals(salesQuotationDto.getStatus())) {
//            vo.setApproveStatus(0);
//            salesQuotation.setStatus("待审批");
//        }
        //编辑将审批改为待审批
        salesQuotation.setStatus("待审批");
        //将之前未审批的结束
        LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>();
        approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveType, 6)
                .eq(ApproveProcess::getApproveReason, salesQuotationDto.getQuotationNo());
        List<ApproveProcess> approveProcesss = approveProcessService.list(approveProcessLambdaQueryWrapper);
        approveProcesss.forEach(approveProcess -> {
            approveProcess.setApproveStatus(4);
        });
        approveProcessService.updateBatchById(approveProcesss);
        if (salesQuotationMapper.updateById(salesQuotation) != 1) {
        ApproveGetAndUpdateVo vo = new ApproveGetAndUpdateVo();
        if("拒绝".equals(salesQuotationDto.getStatus())){
            vo.setApproveStatus(0);
            salesQuotation.setStatus("待审批");
        }
        if(salesQuotationMapper.updateById(salesQuotation)!=1){
            return false;
        }
        salesQuotationProductMapper.delete(new LambdaQueryWrapper<SalesQuotationProduct>().eq(SalesQuotationProduct::getSalesQuotationId, salesQuotationDto.getId()));
        if (CollectionUtils.isEmpty(salesQuotationDto.getProducts())) {
        if(CollectionUtils.isEmpty(salesQuotationDto.getProducts())){
            return true;
        }
        List<SalesQuotationProduct> products = salesQuotationDto.getProducts().stream().map(product -> {
@@ -144,220 +121,27 @@
        salesQuotationProductService.saveBatch(products);
        // ä¿®æ”¹æŠ¥ä»·å®¡æ‰¹
        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
        approveProcessVO.setApproveType(6);
        approveProcessVO.setApproveDeptId(SecurityUtils.getLoginUser().getCurrentDeptId());
        approveProcessVO.setApproveReason(salesQuotation.getQuotationNo());
        approveProcessVO.setApproveUserIds(salesQuotationDto.getApproveUserIds());
        approveProcessVO.setApproveUser(SecurityUtils.getUserId());
        approveProcessVO.setApproveTime(LocalDate.now().toString());
        approveProcessVO.setPrice(salesQuotationDto.getTotalAmount());
        try {
            approveProcessService.addApprove(approveProcessVO);
        }catch (Exception e){
            log.error("SalesQuotationServiceImpl error:{}", e);
        }
        vo.setApproveUserIds(salesQuotationDto.getApproveUserIds());
        vo.setApproveType(6);
        vo.setApproveReason(salesQuotationDto.getQuotationNo());
        approveProcessService.updateApproveUser(vo);
        return true;
    }
    @Override
    public boolean delete(Long id) {
        SalesQuotation salesQuotation = salesQuotationMapper.selectById(id);
        if (salesQuotation == null) return false;
        if(salesQuotation==null) return false;
        salesQuotationMapper.deleteById(id);
        salesQuotationProductMapper.delete(new LambdaQueryWrapper<SalesQuotationProduct>().eq(SalesQuotationProduct::getSalesQuotationId, id));
        // åˆ é™¤æŠ¥ä»·å®¡æ‰¹
        ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                .eq(ApproveProcess::getApproveType, 6)
                .eq(ApproveProcess::getApproveReason, salesQuotation.getQuotationNo()));
        if (one != null) {
        if(one != null){
            approveProcessService.delByIds(Collections.singletonList(one.getId()));
        }
        return true;
    }
    @Override
    public QuotationRecordJSON importData(MultipartFile file, String approveUserIdsJson) {
        try (InputStream inputStream = file.getInputStream();
             Workbook workbook = WorkbookFactory.create(inputStream)) {
            Sheet sheet = workbook.getNumberOfSheets() > 1 ? workbook.getSheetAt(1) : workbook.getSheetAt(0);
            DataFormatter dataFormatter = new DataFormatter();
            QuotationRecordJSON result = new QuotationRecordJSON();
            // æ¨¡æ¿ä¸­å®¢æˆ·ä¿¡æ¯å›ºå®šåœ¨ç¬¬2行(A2-F2),且只有一行
            Row customerRow = sheet.getRow(1);
            List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>()
                    .eq(Customer::getCustomerName, getStringCell(customerRow, 0, dataFormatter)));
            if (CollectionUtils.isEmpty(customers)) {
                throw new RuntimeException("客户不存在");
            }
            List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getNickName, getStringCell(customerRow, 1, dataFormatter)));
            if (CollectionUtils.isEmpty(sysUsers)) {
                throw new RuntimeException("业务员不存在");
            }
            if (customerRow != null) {
                result.setCustomer(getStringCell(customerRow, 0, dataFormatter));
                result.setSalesperson(getStringCell(customerRow, 1, dataFormatter));
                result.setQuotationDate(getStringCell(customerRow, 2, dataFormatter));
                result.setValidDate(getStringCell(customerRow, 3, dataFormatter));
                result.setPaymentMethod(getStringCell(customerRow, 4, dataFormatter));
                result.setRemark(getStringCell(customerRow, 5, dataFormatter));
            }
            // æ¨¡æ¿ä¸­äº§å“è¡¨å¤´åœ¨ç¬¬7行,数据从第8行开始
            List<QuotationRecordJSON.ProductJSON> products = new ArrayList<>();
            int startRow = 7;
            for (int i = startRow; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue;
                }
                String product = getStringCell(row, 0, dataFormatter);
                String specification = getStringCell(row, 1, dataFormatter);
                List<ProductModel> productModels = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>()
                        .eq(ProductModel::getModel, specification));
                if (CollectionUtils.isEmpty(productModels)) {
                    throw new RuntimeException("产品不存在");
                }
                ProductModel productModel = productModels.get(0);
                BigDecimal unitPrice = getDecimalCell(row, 2, dataFormatter);
                if (isBlank(product) && isBlank(specification) && unitPrice == null) {
                    continue;
                }
                QuotationRecordJSON.ProductJSON item = new QuotationRecordJSON.ProductJSON();
                item.setProduct(product);
                item.setSpecification(specification);
                item.setUnit(productModel.getUnit());
                item.setUnitPrice(unitPrice);
                products.add(item);
            }
            result.setProducts(products);
            // å¤„理报价单
            SalesQuotation salesQuotation = addOrUpdateApproveProcess(result, approveUserIdsJson);
            Integer insertResult = quotationRecordsService.add(salesQuotation.getId(), result);
            if (insertResult <= 0) {
                throw new RuntimeException("报价记录新增失败");
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("导入销售报价模板失败:" + e.getMessage(), e);
        }
    }
    private SalesQuotation addOrUpdateApproveProcess(QuotationRecordJSON quotationRecordJSON, String approveUserIdsJson) {
        List<SalesQuotation> salesQuotations = salesQuotationMapper.selectList(new LambdaQueryWrapper<SalesQuotation>()
                .eq(SalesQuotation::getCustomer, quotationRecordJSON.getCustomer())
                .eq(SalesQuotation::getStatus, "待审批"));
        if (CollectionUtils.isEmpty(salesQuotations)) {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            SalesQuotation salesQuotation = new SalesQuotation();
            String quotationNo = OrderUtils.countTodayByCreateTime(salesQuotationMapper, "QT", "quotation_no");
            salesQuotation.setQuotationNo(quotationNo);
            salesQuotation.setCustomer(quotationRecordJSON.getCustomer());
            salesQuotation.setSalesperson(quotationRecordJSON.getSalesperson());
            salesQuotation.setQuotationDate(LocalDate.parse(quotationRecordJSON.getQuotationDate()));
            salesQuotation.setValidDate(LocalDate.parse(quotationRecordJSON.getValidDate()));
            salesQuotation.setPaymentMethod(quotationRecordJSON.getPaymentMethod());
            salesQuotation.setStatus("待审批");
            BigDecimal totalAmount = quotationRecordJSON.getProducts().stream()
                    .map(QuotationRecordJSON.ProductJSON::getUnitPrice)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            salesQuotation.setTotalAmount(totalAmount);
            salesQuotationMapper.insert(salesQuotation);
            List<SalesQuotationProduct> products = quotationRecordJSON.getProducts().stream().map(product -> {
                SalesQuotationProduct salesQuotationProduct = new SalesQuotationProduct();
                salesQuotationProduct.setProduct(product.getProduct());
                salesQuotationProduct.setSpecification(product.getSpecification());
                salesQuotationProduct.setUnit(product.getUnit());
                salesQuotationProduct.setUnitPrice(product.getUnitPrice().doubleValue());
                salesQuotationProduct.setSalesQuotationId(salesQuotation.getId());
                return salesQuotationProduct;
            }).collect(Collectors.toList());
            salesQuotationProductService.saveBatch(products);
            // æŠ¥ä»·å®¡æ‰¹
            ApproveProcessVO approveProcessVO = new ApproveProcessVO();
            approveProcessVO.setApproveType(6);
            approveProcessVO.setApproveDeptId(loginUser.getCurrentDeptId());
            approveProcessVO.setApproveReason(quotationNo);
            approveProcessVO.setApproveUserIds(approveUserIdsJson);
            approveProcessVO.setApproveUser(loginUser.getUserId());
            approveProcessVO.setApproveTime(LocalDate.now().toString());
            approveProcessVO.setPrice(salesQuotation.getTotalAmount());
            try {
                approveProcessService.addApprove(approveProcessVO);
            } catch (Exception e) {
                log.error("SalesQuotationServiceImpl error:{}", e);
                throw new RuntimeException("审批失败");
            }
            return salesQuotation;
        } else {
            if (salesQuotations.size() > 1) {
                throw new RuntimeException("存在多个待审批的报价单");
            } else {
                SalesQuotation salesQuotation = salesQuotations.get(0);
                salesQuotation.setSalesperson(quotationRecordJSON.getSalesperson());
                salesQuotation.setQuotationDate(LocalDate.parse(quotationRecordJSON.getQuotationDate()));
                salesQuotation.setValidDate(LocalDate.parse(quotationRecordJSON.getValidDate()));
                salesQuotation.setPaymentMethod(quotationRecordJSON.getPaymentMethod());
                BigDecimal totalAmount = quotationRecordJSON.getProducts().stream()
                        .map(QuotationRecordJSON.ProductJSON::getUnitPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                salesQuotation.setTotalAmount(totalAmount);
                salesQuotationMapper.updateById(salesQuotation);
                // åˆ é™¤åŽŸæ¥çš„æŠ¥ä»·äº§å“
                salesQuotationProductMapper.delete(new LambdaQueryWrapper<SalesQuotationProduct>()
                        .eq(SalesQuotationProduct::getSalesQuotationId, salesQuotation.getId()));
                List<SalesQuotationProduct> products = quotationRecordJSON.getProducts().stream().map(product -> {
                    SalesQuotationProduct salesQuotationProduct = new SalesQuotationProduct();
                    salesQuotationProduct.setProduct(product.getProduct());
                    salesQuotationProduct.setSpecification(product.getSpecification());
                    salesQuotationProduct.setUnit(product.getUnit());
                    salesQuotationProduct.setUnitPrice(product.getUnitPrice().doubleValue());
                    salesQuotationProduct.setSalesQuotationId(salesQuotation.getId());
                    return salesQuotationProduct;
                }).collect(Collectors.toList());
                salesQuotationProductService.saveBatch(products);
                return salesQuotation;
            }
        }
    }
    private String getStringCell(Row row, int columnIndex, DataFormatter dataFormatter) {
        if (row == null) {
            return null;
        }
        Cell cell = row.getCell(columnIndex);
        if (cell == null) {
            return null;
        }
        if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) {
            return cell.getLocalDateTimeCellValue().toLocalDate().format(DateTimeFormatter.ISO_LOCAL_DATE);
        }
        String value = dataFormatter.formatCellValue(cell);
        return isBlank(value) ? null : value.trim();
    }
    private BigDecimal getDecimalCell(Row row, int columnIndex, DataFormatter dataFormatter) {
        String value = getStringCell(row, columnIndex, dataFormatter);
        if (isBlank(value)) {
            return null;
        }
        try {
            return new BigDecimal(value.replace(",", ""));
        } catch (Exception e) {
            return null;
        }
    }
    private boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }
}