huminmin
8 天以前 52123c927f77f41f71461ef0d422525656bd7b6f
优化营销客户相关
已修改12个文件
已删除14个文件
1463 ■■■■ 文件已修改
src/main/java/com/ruoyi/basic/controller/CustomerController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerFollowUpController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerPrivateController.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerPrivatePoolController.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/dto/CustomerPrivateDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/dto/CustomerPrivatePoolDto.java 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/mapper/CustomerPrivateMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/mapper/CustomerPrivatePoolMapper.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/CustomerFollowUp.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/CustomerPrivate.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/CustomerPrivatePool.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/CustomerReturnVisit.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/CustomerPrivatePoolService.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/CustomerPrivateService.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/ICustomerService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerFollowUpServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivatePoolServiceImpl.java 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivateServiceImpl.java 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesQuotation.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 208 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerMapper.xml 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerPrivateMapper.xml 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerPrivatePoolMapper.xml 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerController.java
@@ -45,16 +45,9 @@
     */
    @Log(title = "客户档案", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, Customer customer) {
        Long[] ids = customer.getIds();
        List<Customer> list;
        if (ids != null && ids.length > 0) {
            list = customerService.selectCustomerListByIds(ids);
        } else {
            list = customerService.selectCustomerLists(customer);
        }
        ExcelUtil<Customer> util = new ExcelUtil<Customer>(Customer.class);
        util.exportExcel(response, list, "客户档案数据");
    public void export(HttpServletResponse response, CustomerDto customer) {
        ExcelUtil<CustomerVo> util = new ExcelUtil<CustomerVo>(CustomerVo.class);
        util.exportExcel(response, customerService.selectCustomerLists(customer), "客户档案数据");
    }
    @PostMapping("/downloadTemplate")
@@ -70,9 +63,9 @@
     */
    @Log(title = "客户档案", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file) throws Exception {
    public AjaxResult importData(MultipartFile file, Integer type) throws Exception {
        return customerService.importData(file);
        return customerService.importData(file, type);
    }
    /**
src/main/java/com/ruoyi/basic/controller/CustomerFollowUpController.java
@@ -44,7 +44,7 @@
    @Operation(summary = "查询客户跟进列表")
    public IPage<CustomerFollowUp> list(Page<CustomerFollowUp> page, CustomerFollowUp customerFollowUp) {
        LambdaQueryWrapper<CustomerFollowUp> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(customerFollowUp.getCustomerPrivatePoolId() != null, CustomerFollowUp::getCustomerPrivatePoolId, customerFollowUp.getCustomerPrivatePoolId())
        queryWrapper.eq(customerFollowUp.getCustomerId() != null, CustomerFollowUp::getCustomerId, customerFollowUp.getCustomerId())
                .like(customerFollowUp.getFollowerUserName() != null, CustomerFollowUp::getFollowerUserName, customerFollowUp.getFollowerUserName())
                .orderByDesc(CustomerFollowUp::getFollowUpTime);
        return customerFollowUpService.page(page, queryWrapper);
src/main/java/com/ruoyi/basic/controller/CustomerPrivateController.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/controller/CustomerPrivatePoolController.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/dto/CustomerPrivateDto.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/dto/CustomerPrivatePoolDto.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
@@ -69,4 +69,6 @@
    int deleteCustomerByIds(Long[] ids);
    IPage<CustomerVo> listPage(Page<CustomerDto> page, @Param("c") CustomerDto customer, @Param("loginUserId") Long loginUserId);
    List<CustomerVo> list(@Param("c") CustomerDto customer, @Param("loginUserId") Long loginUserId);
}
src/main/java/com/ruoyi/basic/mapper/CustomerPrivateMapper.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/mapper/CustomerPrivatePoolMapper.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/pojo/CustomerFollowUp.java
@@ -37,7 +37,7 @@
    /**
     * å…³è”的私海id
     */
    private Long customerPrivatePoolId;
//    private Long customerPrivatePoolId;
    private Long customerId;
src/main/java/com/ruoyi/basic/pojo/CustomerPrivate.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/pojo/CustomerPrivatePool.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/pojo/CustomerReturnVisit.java
@@ -36,7 +36,7 @@
    /**
     * å…³è”客户ID
     */
    private Integer customerPrivatePoolId;
//    private Integer customerPrivatePoolId;
    private Long customerId;
src/main/java/com/ruoyi/basic/service/CustomerPrivatePoolService.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/service/CustomerPrivateService.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/service/ICustomerService.java
@@ -75,9 +75,9 @@
     */
    List<Map<String, Object>> customerList(Customer customer);
    List<Customer> selectCustomerLists(Customer customer);
    List<CustomerVo> selectCustomerLists(CustomerDto customer);
    AjaxResult importData(MultipartFile file);
    AjaxResult importData(MultipartFile file, Integer type);
    IPage<CustomerVo> selectCustomerList(Page<CustomerDto> page, CustomerDto customer);
src/main/java/com/ruoyi/basic/service/impl/CustomerFollowUpServiceImpl.java
@@ -130,7 +130,7 @@
        }
        List<CustomerFollowUp> followUps = list(new LambdaQueryWrapper<CustomerFollowUp>()
                .eq(CustomerFollowUp::getCustomerPrivatePoolId, customerId));
                .eq(CustomerFollowUp::getCustomerId, customerId));
        if (followUps != null && !followUps.isEmpty()) {
            for (CustomerFollowUp followUp : followUps) {
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivatePoolServiceImpl.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivateServiceImpl.java
ÎļþÒÑɾ³ý
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -10,7 +10,6 @@
import com.ruoyi.basic.dto.CustomerDto;
import com.ruoyi.basic.dto.CustomerFollowUpDto;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
import com.ruoyi.basic.pojo.*;
import com.ruoyi.basic.service.CustomerFollowUpFileService;
import com.ruoyi.basic.service.CustomerFollowUpService;
@@ -20,22 +19,20 @@
import com.ruoyi.basic.vo.CustomerVo;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
@@ -48,16 +45,21 @@
 * @date 2025-05-07
 */
@Service
@RequiredArgsConstructor
@AllArgsConstructor
@Slf4j
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements ICustomerService {
    private final SalesLedgerMapper salesLedgerMapper;
    private final CustomerPrivatePoolMapper customerPrivatePoolMapper;
    private final CustomerMapper customerMapper;
    @Autowired
    private  SalesLedgerMapper salesLedgerMapper;
    @Autowired
    private CustomerMapper customerMapper;
    private final CustomerFollowUpService customerFollowUpService;
    private final CustomerReturnVisitService customerReturnVisitService;
    @Autowired
    private CustomerFollowUpService customerFollowUpService;
    @Autowired
    private CustomerFollowUpFileService customerFollowUpFileService;
    @Autowired
    private CustomerReturnVisitService customerReturnVisitService;
    @Autowired
    private CustomerUserService customerUserService;
    /**
@@ -165,13 +167,13 @@
    private Map<Long, CustomerFollowUp> getLatestFollowUpMap(List<Long> customerIds) {
        List<CustomerFollowUp> followUps = customerFollowUpService.list(
                new LambdaQueryWrapper<CustomerFollowUp>()
                        .in(CustomerFollowUp::getCustomerPrivatePoolId, customerIds)
                        .in(CustomerFollowUp::getCustomerId, customerIds)
                        .orderByDesc(CustomerFollowUp::getFollowUpTime)
        );
        return followUps.stream()
                .collect(Collectors.toMap(
                        CustomerFollowUp::getCustomerPrivatePoolId,
                        CustomerFollowUp::getCustomerId,
                        followUp -> followUp,
                        (existing, replacement) -> existing
                ));
@@ -229,13 +231,18 @@
        if (!assignedPools.isEmpty()) {
            throw new RuntimeException("客户档案下有已分配的公海客户,请先收回");
        }
        //  åˆ é™¤å®¢æˆ·çš„同时也需要删除对应的客户跟随、附件和回访提醒
        // åˆ é™¤å®¢æˆ·çš„同时也需要删除对应的客户跟随、附件和回访提醒
        for (Long id : ids) {
            customerFollowUpService.deleteByCustomerId(id);
            customerReturnVisitService.deleteByCustomerId(id);
            // åˆ é™¤å®¢æˆ·çš„共享关系
            customerUserService.remove(
                new QueryWrapper<CustomerUser>().lambda()
                    .eq(CustomerUser::getCustomerId, id)
            );
        }
        customerMapper.delete(new QueryWrapper<Customer>().lambda().in(Customer::getId, idList));
        // åˆ é™¤å®¢æˆ·ä¸»è¡¨æ•°æ®
        return customerMapper.deleteBatchIds(idList);
    }
@@ -247,17 +254,26 @@
    }
    @Override
    public List<Customer> selectCustomerLists(Customer customer) {
        return customerMapper.selectList(null);
    public List<CustomerVo> selectCustomerLists(CustomerDto customer) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long loginUserId = loginUser.getUserId();
        return customerMapper.list(customer, loginUserId);
    }
    @Override
    public AjaxResult importData(MultipartFile file) {
    public AjaxResult importData(MultipartFile file, Integer type) {
        try {
            ExcelUtil<Customer> util = new ExcelUtil<Customer>(Customer.class);
            List<Customer> userList = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(userList)) {
                return AjaxResult.warn("模板错误或导入数据为空");
            }
            // æ ¹æ® type å‚数设置客户类型(私海/公海)
            if (type != null) {
                userList.forEach(customer -> {
                    customer.setType(type);
                });
            }
            this.saveOrUpdateBatch(userList);
            return AjaxResult.success(true);
@@ -306,7 +322,7 @@
            customer.setUsageStatus(0L);
            customer.setUsageUser(0L);
            customerMapper.updateById(customer);
            // åˆ é™¤è¯¥å®¢æˆ·çš„æ‰€æœ‰å…±äº«å…³ç³»
            customerUserService.remove(
                new QueryWrapper<CustomerUser>().lambda()
@@ -376,4 +392,4 @@
        }
        return sb.toString();
    }
}
}
src/main/java/com/ruoyi/sales/pojo/SalesQuotation.java
@@ -3,7 +3,7 @@
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -16,55 +16,58 @@
public class SalesQuotation {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @Schema(description = "报价单编号")
    @ApiModelProperty(value = "报价单编号")
    @Excel(name = "报价单编号")
    private String quotationNo;
    @Schema(description = "客户名称")
    @ApiModelProperty(value = "客户名称")
    @Excel(name = "客户名称")
    private String customer;
    @Schema(description = "业务员")
    @ApiModelProperty(value = "客户id")
    private Long customerId;
    @ApiModelProperty(value = "业务员")
    @Excel(name = "业务员")
    private String salesperson;
    @Schema(description = "报价日期")
    @ApiModelProperty(value = "报价日期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "报价日期", width = 30, dateFormat = "yyyy-MM-dd")
    private LocalDate quotationDate;
    @Schema(description = "有效期至")
    @ApiModelProperty(value = "有效期至")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "有效期至", width = 30, dateFormat = "yyyy-MM-dd")
    private LocalDate validDate;
    @Schema(description = "付款方式")
    @ApiModelProperty(value = "付款方式")
    private String paymentMethod;
    @Schema(description = "交货周期天数")
    @ApiModelProperty(value = "交货周期天数")
    private String deliveryPeriod;
    @Schema(description = "状态")
    @ApiModelProperty(value = "状态")
    private String status;
    @Schema(description = "报价总金额")
    @ApiModelProperty(value = "报价总金额")
    @Excel(name = "报价金额")
    private BigDecimal totalAmount;
    @Schema(description = "备注")
    @ApiModelProperty(value = "备注")
    private String remark;
    @Schema(description = "创建时间")
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @Schema(description = "修改时间")
    @ApiModelProperty(value = "修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @Schema(description = "创建用户")
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @Schema(description = "修改用户")
    @ApiModelProperty(value = "修改用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @Schema(description = "租户ID")
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -9,15 +9,10 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.service.AccountIncomeService;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.dto.StorageBlobVO;
import com.ruoyi.basic.enums.ApplicationTypeEnum;
import com.ruoyi.basic.enums.RecordTypeEnum;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.utils.FileUtil;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.SaleEnum;
import com.ruoyi.common.exception.base.BaseException;
@@ -29,9 +24,8 @@
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.production.mapper.ProductionProductInputMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.service.ProductionProductMainService;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
@@ -44,11 +38,12 @@
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.*;
import com.ruoyi.sales.service.ISalesLedgerService;
import com.ruoyi.sales.vo.SalesLedgerVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
@@ -56,10 +51,15 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
@@ -82,26 +82,52 @@
    private static final String LOCK_PREFIX = "contract_no_lock:";
    private static final long LOCK_WAIT_TIMEOUT = 10; // é”ç­‰å¾…超时时间(秒)
    private static final long LOCK_EXPIRE_TIME = 30;  // é”è‡ªåŠ¨è¿‡æœŸæ—¶é—´ï¼ˆç§’ï¼‰
    private final AccountIncomeService accountIncomeService;
    private final SalesLedgerMapper salesLedgerMapper;
    private final CustomerMapper customerMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final SalesLedgerProductServiceImpl salesLedgerProductServiceImpl;
    private final CommonFileMapper commonFileMapper;
    private final TempFileMapper tempFileMapper;
    private final ReceiptPaymentMapper receiptPaymentMapper;
    private final ShippingInfoServiceImpl shippingInfoServiceImpl;
    private final CommonFileServiceImpl commonFileService;
    private final ShippingInfoMapper shippingInfoMapper;
    private final InvoiceLedgerMapper invoiceLedgerMapper;
    private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper;
    private final SalesLedgerWorkMapper salesLedgerWorkMapper;
    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    private final InvoiceRegistrationMapper invoiceRegistrationMapper;
    private final ProductModelMapper productModelMapper;
    private final ProductOrderMapper productOrderMapper;
    private final ProcessRouteMapper processRouteMapper;
    private final ProductProcessRouteMapper productProcessRouteMapper;
    private final ProcessRouteItemMapper processRouteItemMapper;
    private final ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private final ProductWorkOrderMapper productWorkOrderMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final ProductionProductInputMapper productionProductInputMapper;
    private final QualityInspectMapper qualityInspectMapper;
    private final RedisTemplate<String, String> redisTemplate;
    private final SysDeptMapper sysDeptMapper;
    private final ProductionProductMainService productionProductMainService;
    private final PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper;
    private final SysUserMapper sysUserMapper;
    private final CustomerPrivatePoolMapper customerPrivatePoolMapper;
    private final FileUtil fileUtil;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Value("${file.upload-dir}")
    private String uploadDir;
    @Autowired
    private ProductModelMapper productModelMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductStructureMapper productStructureMapper;
    @Autowired
    private ProductionProductMainService productionProductMainService;
    @Autowired
    private PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper;
    ;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Override
    public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) {
@@ -185,9 +211,6 @@
            resultDto.setProductData(products);
            resultDto.setSalesLedgerFiles(salesLedgerFiles);
        }
        // 5. æŸ¥è¯¢é™„ä»¶
        List<StorageBlobVO> StorageBlobVOs = fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.SALES_LEDGER, salesLedger.getId());
        resultDto.setStorageBlobVOs(StorageBlobVOs);
        return resultDto;
    }
@@ -311,7 +334,7 @@
    }
    @Override
    public IPage<SalesLedgerVo> selectSalesLedgerListPage(Page page, SalesLedgerDto salesLedgerDto) {
    public IPage<SalesLedger> selectSalesLedgerListPage(Page page, SalesLedgerDto salesLedgerDto) {
        return salesLedgerMapper.selectSalesLedgerListPage(page, salesLedgerDto);
    }
@@ -514,7 +537,7 @@
        List<Long> productIds = products.stream()
                .map(SalesLedgerProduct::getId)
                .collect(Collectors.toList());
        //删除生产计划
        //删除生产数据
        salesLedgerProductServiceImpl.deleteProductionData(productIds);
        // æ‰¹é‡åˆ é™¤äº§å“å­è¡¨
@@ -569,43 +592,122 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addOrUpdateSalesLedger(SalesLedgerDto salesLedgerDto) {
        // 1. æ ¡éªŒå®¢æˆ·ä¿¡æ¯
        CustomerPrivatePoolDto customer = customerPrivatePoolMapper.selectInfo(salesLedgerDto.getCustomerId());
        if (customer == null) {
            throw new BaseException("客户不存在");
        try {
            // 1. æ ¡éªŒå®¢æˆ·ä¿¡æ¯
            Customer customer = customerMapper.selectById(salesLedgerDto.getCustomerId());
            if (customer == null) {
                throw new BaseException("客户不存在");
            }
            // 2. DTO转Entity
            SalesLedger salesLedger = convertToEntity(salesLedgerDto);
            salesLedger.setCustomerName(customer.getCustomerName());
            salesLedger.setTenantId(customer.getTenantId());
            // 3. æ–°å¢žæˆ–更新主表
            if (salesLedger.getId() == null) {
                String contractNo = generateSalesContractNo();
                salesLedger.setSalesContractNo(contractNo);
                salesLedgerMapper.insert(salesLedger);
            } else {
                salesLedgerMapper.updateById(salesLedger);
            }
            // 4. å¤„理子表数据
            List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
            if (productList != null && !productList.isEmpty()) {
                handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
                updateMainContractAmount(
                        salesLedger.getId(),
                        productList,
                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
                        salesLedgerMapper,
                        SalesLedger.class
                );
            }
            // 5. è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
            if (salesLedgerDto.getTempFileIds() != null && !salesLedgerDto.getTempFileIds().isEmpty()) {
                migrateTempFilesToFormal(salesLedger.getId(), salesLedgerDto.getTempFileIds());
            }
            return 1;
        } catch (IOException e) {
            throw new BaseException("文件迁移失败: " + e.getMessage());
        }
    }
    /**
     * å°†ä¸´æ—¶æ–‡ä»¶è¿ç§»åˆ°æ­£å¼ç›®å½•
     *
     * @param businessId  ä¸šåŠ¡ID(销售台账ID)
     * @param tempFileIds ä¸´æ—¶æ–‡ä»¶ID列表
     * @throws IOException æ–‡ä»¶æ“ä½œå¼‚常
     */
    private void migrateTempFilesToFormal(Long businessId, List<String> tempFileIds) throws IOException {
        if (CollectionUtils.isEmpty(tempFileIds)) {
            return;
        }
        // 2. DTO转Entity
        SalesLedger salesLedger = convertToEntity(salesLedgerDto);
        salesLedger.setCustomerName(customer.getCustomerName());
        salesLedger.setTenantId(customer.getTenantId());
        // 3. æ–°å¢žæˆ–更新主表
        if (salesLedger.getId() == null) {
            String contractNo = generateSalesContractNo();
            salesLedger.setSalesContractNo(contractNo);
            salesLedgerMapper.insert(salesLedger);
        } else {
            salesLedgerMapper.updateById(salesLedger);
        // æž„建正式目录路径(按业务类型和日期分组)
        String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
        Path formalDirPath = Paths.get(formalDir);
        // ç¡®ä¿æ­£å¼ç›®å½•存在(递归创建)
        if (!Files.exists(formalDirPath)) {
            Files.createDirectories(formalDirPath);
        }
        // 4. å¤„理子表数据
        List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
        if (productList != null && !productList.isEmpty()) {
            handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
            updateMainContractAmount(
                    salesLedger.getId(),
                    productList,
                    SalesLedgerProduct::getTaxInclusiveTotalPrice,
                    salesLedgerMapper,
                    SalesLedger.class
            );
        }
        for (String tempFileId : tempFileIds) {
            // æŸ¥è¯¢ä¸´æ—¶æ–‡ä»¶è®°å½•
            TempFile tempFile = tempFileMapper.selectById(tempFileId);
            if (tempFile == null) {
                log.warn("临时文件不存在,跳过处理: {}", tempFileId);
                continue;
            }
        // 5. ä¿å­˜æ–‡ä»¶
        if (salesLedgerDto.getStorageBlobDTOs() != null && !salesLedgerDto.getStorageBlobDTOs().isEmpty()) {
            fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.SALES_LEDGER, salesLedger.getId(), salesLedgerDto.getStorageBlobDTOs());
            // æž„建正式文件名(包含业务ID和时间戳,避免冲突)
            String originalFilename = tempFile.getOriginalName();
            String fileExtension = FilenameUtils.getExtension(originalFilename);
            String formalFilename = businessId + "_" +
                    System.currentTimeMillis() + "_" +
                    UUID.randomUUID().toString().substring(0, 8) +
                    (StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
            Path formalFilePath = formalDirPath.resolve(formalFilename);
            try {
                // æ‰§è¡Œæ–‡ä»¶è¿ç§»ï¼ˆä½¿ç”¨åŽŸå­æ“ä½œç¡®ä¿å®‰å…¨æ€§ï¼‰
//                Files.move(
//                        Paths.get(tempFile.getTempPath()),
//                        formalFilePath,
//                        StandardCopyOption.REPLACE_EXISTING,
//                        StandardCopyOption.ATOMIC_MOVE
//                );
                // åŽŸå­ç§»åŠ¨å¤±è´¥ï¼Œä½¿ç”¨å¤åˆ¶+删除
                Files.copy(Paths.get(tempFile.getTempPath()), formalFilePath, StandardCopyOption.REPLACE_EXISTING);
                Files.deleteIfExists(Paths.get(tempFile.getTempPath()));
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
                // æ›´æ–°æ–‡ä»¶è®°å½•(关联到业务ID)
                CommonFile fileRecord = new CommonFile();
                fileRecord.setCommonId(businessId);
                fileRecord.setName(originalFilename);
                fileRecord.setUrl(formalFilePath.toString());
                fileRecord.setCreateTime(LocalDateTime.now());
                //销售
                fileRecord.setType(FileNameType.SALE.getValue());
                commonFileMapper.insert(fileRecord);
                // åˆ é™¤ä¸´æ—¶æ–‡ä»¶è®°å½•
                tempFileMapper.deleteById(tempFile);
                log.info("文件迁移成功: {} -> {}", tempFile.getTempPath(), formalFilePath);
            } catch (IOException e) {
                log.error("文件迁移失败: {}", tempFile.getTempPath(), e);
                // å¯é€‰æ‹©å›žæ»šäº‹åŠ¡æˆ–è®°å½•å¤±è´¥æ–‡ä»¶
                throw new IOException("文件迁移异常", e);
            }
        }
        return 1;
    }
    // æ–‡ä»¶è¿ç§»æ–¹æ³•
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -11,8 +11,6 @@
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.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;
src/main/resources/mapper/basic/CustomerMapper.xml
@@ -54,5 +54,57 @@
        </where>
    </select>
    <select id="list" resultType="com.ruoyi.basic.vo.CustomerVo">
        select
        c.*,
        u.user_name usage_user_name,
        (
        select group_concat(u2.user_name separator ', ')
        from customer_user cu
        left join sys_user u2 on cu.user_id = u2.user_id
        where cu.customer_id = c.id
        and cu.user_id != c.usage_user
        ) as together_user_names,
        (
        select group_concat(cu.user_id separator ',')
        from customer_user cu
        where cu.customer_id = c.id
        and cu.user_id != c.usage_user
        ) as user_ids_str
        from customer c
        left join sys_user u on c.usage_user = u.user_id
        <where>
            <if test="c.ids != null and c.ids.length > 0">
                and c.id in
                <foreach collection="c.ids" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
            <if test="c.customerName != null and c.customerName != ''">
                and customer_name like concat('%', #{c.customerName}, '%')
            </if>
            <if test="c.customerType != null and c.customerType != ''">
                and customer_type = #{c.customerType}
            </if>
            <!-- å…¬æµ·æŸ¥è¯¢ï¼štype = 1(公海客户)-->
            <if test="c.type != null and c.type == 1">
                and type = #{c.type}
            </if>
            <!-- ç§æµ·æŸ¥è¯¢ï¼štype = 0(私海客户)或者 type = 1(公海客户)且已被分配,并且是自己领用、自己创建或者共享给自己的客户 -->
            <if test="c.type != null and c.type == 0">
                and (
                    (type = #{c.type} or (type = 1 and is_assigned = 1))
                    and (
                        c.usage_user = #{loginUserId}
                        or c.create_user = #{loginUserId}
                        or exists (
                            select 1 from customer_user cu
                            where cu.customer_id = c.id
                            and cu.user_id = #{loginUserId}
                        )
                    )
                )
            </if>
        </where>
    </select>
</mapper>
src/main/resources/mapper/basic/CustomerPrivateMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/basic/CustomerPrivatePoolMapper.xml
ÎļþÒÑɾ³ý