liyong
2026-04-20 d697e4fa4468a803d97905164da5cbdded859858
Merge branch 'refs/heads/dev_New' into dev_西宁_湟水峡
已添加22个文件
已修改26个文件
1832 ■■■■■ 文件已修改
src/main/java/com/ruoyi/CodeGenerator.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerController.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerFollowUpController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerPrivateController.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/CustomerPrivatePoolController.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/dto/CustomerDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | 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 8 ●●●●● 补丁 | 查看 | 原始文档 | 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/Customer.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/CustomerFollowUp.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/CustomerPrivate.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/CustomerPrivatePool.java 68 ●●●●● 补丁 | 查看 | 原始文档 | 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 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerFollowUpServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivatePoolServiceImpl.java 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivateServiceImpl.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerReturnVisitServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/task/ReturnVisitReminderTask.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/config/IgnoreTableConfig.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProcessRouteItemController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductOrderController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductOrderMaterialController.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductOrderMaterialDto.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductOrderMaterialMapper.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductStructureMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductOrder.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductOrderMaterial.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcess.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductOrderMaterialService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductOrderMaterialServiceImpl.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerTemplateController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerMapper.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerPrivateMapper.xml 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/CustomerPrivatePoolMapper.xml 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProcessRouteItemMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMaterialMapper.xml 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessRouteItemMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/InvoiceLedgerMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/CodeGenerator.java
@@ -19,11 +19,11 @@
// æ¼”示例子,执行 main æ–¹æ³•控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {
    public static String database_url = "jdbc:mysql://1.15.17.182:9999/product-inventory-management-new";
    public static String database_url = "jdbc:mysql://localhost:3300/product-inventory-management-new";
    public static String database_username = "root";
    public static String database_password= "xd@123456..";
    public static String database_password= "root";
    public static String author = "芯导软件(江苏)有限公司";
    public static String model = "staff"; // æ¨¡å—
    public static String model = "basic"; // æ¨¡å—
    public static String setParent = "com.ruoyi."+ model; // åŒ…路径
    public static String tablePrefix = ""; // è®¾ç½®è¿‡æ»¤è¡¨å‰ç¼€
    public static void main(String[] args) {
src/main/java/com/ruoyi/basic/controller/CustomerController.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.CustomerDto;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.service.ICustomerService;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -9,6 +10,7 @@
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -32,8 +34,9 @@
     * æŸ¥è¯¢å®¢æˆ·æ¡£æ¡ˆåˆ—表
     */
    @GetMapping("/list")
    public IPage<Customer> list(Page<Customer> page, Customer customer) {
        return customerService.selectCustomerList(page, customer);
    public R list(Page<CustomerDto> page, CustomerDto customer) {
        IPage<CustomerDto> customerDtoIPage = customerService.selectCustomerList(page, customer);
        return R.ok(customerDtoIPage);
    }
    /**
@@ -116,4 +119,6 @@
    public List customerList(Customer customer) {
        return customerService.customerList(customer);
    }
}
src/main/java/com/ruoyi/basic/controller/CustomerFollowUpController.java
@@ -46,7 +46,7 @@
    @ApiOperation("查询客户跟进列表")
    public IPage<CustomerFollowUp> list(Page<CustomerFollowUp> page, CustomerFollowUp customerFollowUp) {
        LambdaQueryWrapper<CustomerFollowUp> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(customerFollowUp.getCustomerId() != null, CustomerFollowUp::getCustomerId, customerFollowUp.getCustomerId())
        queryWrapper.eq(customerFollowUp.getCustomerPrivatePoolId() != null, CustomerFollowUp::getCustomerPrivatePoolId, customerFollowUp.getCustomerPrivatePoolId())
                .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
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
package com.ruoyi.basic.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.CustomerDto;
import com.ruoyi.basic.dto.CustomerPrivateDto;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerPrivate;
import com.ruoyi.basic.service.CustomerPrivatePoolService;
import com.ruoyi.basic.service.CustomerPrivateService;
import com.ruoyi.basic.service.ICustomerService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import static com.ruoyi.framework.web.domain.AjaxResult.success;
/**
 * <p>
 * å®¢æˆ·æ¡£æ¡ˆ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-17 10:39:09
 */
@RestController
@RequestMapping("/customerPrivate")
public class CustomerPrivateController {
    @Autowired
    private CustomerPrivateService customerPrivateService;
    @Autowired
    private CustomerPrivatePoolService customerPrivatePoolService;
    @PostMapping("/add")
    public R add(@RequestBody CustomerPrivateDto customerPrivateDto) {
        return R.ok(customerPrivateService.add(customerPrivateDto));
    }
    @DeleteMapping("/delete")
    public R delete(@RequestBody List<Long> ids) {
        return R.ok(customerPrivateService.delete(ids));
    }
    /**
     * å¯¼å…¥å®¢æˆ·æ¡£æ¡ˆ
     */
    @Log(title = "客户档案", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public R importData(MultipartFile file) throws Exception {
        return customerPrivateService.importData(file);
    }
    /**
     * å¯¼å‡ºå®¢æˆ·æ¡£æ¡ˆåˆ—表
     */
    @Log(title = "客户档案", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, CustomerPrivatePoolDto customerPrivatePoolDto) {
        List<Long> ids = customerPrivatePoolDto.getIds();
        List<CustomerPrivatePoolDto> list;
        if (ids != null && ids.size() > 0) {
            list = customerPrivatePoolService.selectCustomerPrivatePoolDtoListByIds(ids);
        } else {
            list = customerPrivatePoolService.selectCustomerPrivatePoolDtoLists(customerPrivatePoolDto);
        }
        ExcelUtil<CustomerPrivatePoolDto> util = new ExcelUtil<CustomerPrivatePoolDto>(CustomerPrivatePoolDto.class);
        util.exportExcel(response, list, "客户档案数据");
    }
    @PostMapping("/downloadTemplate")
    @Log(title = "客户档案-下载模板", businessType = BusinessType.EXPORT)
    public void downloadTemplate(HttpServletResponse response) {
        ExcelUtil<CustomerPrivatePoolDto> util = new ExcelUtil<CustomerPrivatePoolDto>(CustomerPrivatePoolDto.class);
        util.importTemplateExcel(response, "客户档案模板");
    }
}
src/main/java/com/ruoyi/basic/controller/CustomerPrivatePoolController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
package com.ruoyi.basic.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerPrivatePool;
import com.ruoyi.basic.service.CustomerPrivatePoolService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
 *  å‰ç«¯æŽ§åˆ¶å™¨ å®¢æˆ·ï¼ˆç§æµ·ï¼‰
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-16 04:43:00
 */
@RestController
@Api(tags = "客户(私海)")
@RequestMapping("/customerPrivatePool")
public class CustomerPrivatePoolController {
    @Autowired
    private CustomerPrivatePoolService customerPrivatePoolService;
    @GetMapping("/listPage")
    @ApiOperation("客户(私海)列表")
    public R listPage(CustomerPrivatePoolDto customerPrivatePoolDto, Page<CustomerPrivatePoolDto> page){
        //查询当前用户的客户信息
        customerPrivatePoolDto.setBoundId(SecurityUtils.getUserId());
        IPage<CustomerPrivatePoolDto> listPage = customerPrivatePoolService.listPage(page, customerPrivatePoolDto);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @ApiOperation("分配客户(私海)")
    public R add(@RequestBody CustomerPrivatePoolDto customerPrivatePool){
        boolean result = customerPrivatePoolService.add(customerPrivatePool);
        return R.ok(result);
    }
    @PutMapping("/update")
    public R update(@RequestBody CustomerPrivatePoolDto customerPrivatePoolDto) {
        return R.ok(customerPrivatePoolService.updateCustomerPrivatePoolDto(customerPrivatePoolDto));
    }
    @DeleteMapping("/delete/{id}")
    @ApiOperation("删除客户(私海)")
    public R delete(@PathVariable Long id){
        boolean result = customerPrivatePoolService.deleteCustomerPrivatePool(id);
        return R.ok(result);
    }
    @PostMapping("/together")
    @ApiOperation("共享")
    public R together( @RequestBody CustomerPrivatePoolDto customerPrivatePool){
        boolean result = customerPrivatePoolService.together(customerPrivatePool);
        return R.ok(result);
    }
    @GetMapping("/info/{id}")
    @ApiOperation("详情")
    public R getInfo(@PathVariable Long id){
        CustomerPrivatePoolDto customerPrivatePool = customerPrivatePoolService.getInfo(id);
        return R.ok(customerPrivatePool);
    }
    @GetMapping("/getbyId/{id}")
    @ApiOperation("详情")
    public R getbyId(@PathVariable Long id){
        CustomerPrivatePoolDto customerPrivatePool = customerPrivatePoolService.getbyId(id);
        return R.ok(customerPrivatePool);
    }
}
src/main/java/com/ruoyi/basic/dto/CustomerDto.java
@@ -21,4 +21,8 @@
    private List<CustomerFollowUpDto> followUpList;
    private String usageUserName;
    private String togetherUserNames;
}
src/main/java/com/ruoyi/basic/dto/CustomerPrivateDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.ruoyi.basic.dto;
import com.ruoyi.basic.pojo.CustomerPrivate;
import lombok.Data;
import java.util.List;
@Data
public class CustomerPrivateDto extends CustomerPrivate {
    private List<CustomerFollowUpDto> followUpList;
}
src/main/java/com/ruoyi/basic/dto/CustomerPrivatePoolDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,124 @@
package com.ruoyi.basic.dto;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.basic.pojo.CustomerFollowUp;
import com.ruoyi.basic.pojo.CustomerPrivatePool;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
@Data
public class CustomerPrivatePoolDto extends CustomerPrivatePool {
    /**
     * å®¢æˆ·åç§°
     */
    @Excel(name = "客户名称")
    private String customerName;
    /** å®¢æˆ·åˆ†ç±»ï¼šé›¶å”®å®¢æˆ·ï¼Œè¿›é”€å•†å®¢æˆ· */
    @ApiModelProperty(value = "客户要id")
    private Long customerId;
    /**
     * è·Ÿè¿›ç¨‹åº¦
     */
//    @Excel(name = "跟进程度")
    @TableField(exist = false)
    private String followUpLevel;
    /**
     * è·Ÿè¿›æ—¶é—´
     */
//    @Excel(name = "跟进时间" , width = 30, dateFormat = "yyyy-MM-dd")
    @TableField(exist = false)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date followUpTime;
    @Excel(name = "客户分类")
    private String customerType;
    private  String addressPhone;
    /**
     * çº³ç¨Žäººè¯†åˆ«å·
     */
    @Excel(name = "纳税人识别号")
    private String taxpayerIdentificationNumber;
    /**
     * å…¬å¸åœ°å€
     */
    @Excel(name = "公司地址")
    private String companyAddress;
    /**
     * å…¬å¸ç”µè¯
     */
    @Excel(name = "公司电话")
    private String companyPhone;
    /**
     * è”系人
     */
    @Excel(name = "联系人")
    private String contactPerson;
    /**
     * è”系电话
     */
    @Excel(name = "联系电话",cellType = Excel.ColumnType.STRING)
    private String contactPhone;
    /**
     * ç»´æŠ¤äºº
     */
    @Excel(name = "维护人")
    private String maintainer;
    /**
     * ç»´æŠ¤æ—¶é—´
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "维护时间" , width = 30, dateFormat = "yyyy-MM-dd")
    private Date maintenanceTime;
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty(value = "银行基本户")
    @Excel(name = "银行基本户")
    private String basicBankAccount;
    @ApiModelProperty(value = "银行账号")
    @Excel(name = "银行账号")
    private String bankAccount;
    @ApiModelProperty(value = "开户行号")
    @Excel(name = "开户行号")
    private String bankCode;
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty(value = "跟进记录")
    private List<CustomerFollowUpDto> followUpList;
    @ApiModelProperty(value = "绑定人ids")
    private List< Long> boundIds;
    @Excel(isExport = false)
    private List<Long> ids;
}
src/main/java/com/ruoyi/basic/mapper/CustomerMapper.java
@@ -1,7 +1,12 @@
package com.ruoyi.basic.mapper;
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.basic.dto.CustomerDto;
import com.ruoyi.basic.pojo.Customer;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -11,6 +16,7 @@
 * @author ruoyi
 * @date 2025-05-07
 */
@Mapper
public interface CustomerMapper extends BaseMapper<Customer>
{
    /**
@@ -60,4 +66,6 @@
     * @return ç»“æžœ
     */
    int deleteCustomerByIds(Long[] ids);
    IPage<CustomerDto> listPage(Page<CustomerDto> page, @Param("c") CustomerDto customer);
}
src/main/java/com/ruoyi/basic/mapper/CustomerPrivateMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.basic.mapper;
import com.ruoyi.basic.pojo.CustomerPrivate;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * å®¢æˆ·æ¡£æ¡ˆ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-17 10:39:09
 */
@Mapper
public interface CustomerPrivateMapper extends BaseMapper<CustomerPrivate> {
}
src/main/java/com/ruoyi/basic/mapper/CustomerPrivatePoolMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.ruoyi.basic.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.pojo.CustomerPrivatePool;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
 *  Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-16 04:43:00
 */
@Mapper
public interface CustomerPrivatePoolMapper extends BaseMapper<CustomerPrivatePool> {
    IPage<CustomerPrivatePoolDto> listPage(IPage<CustomerPrivatePoolDto> page, @Param("c") CustomerPrivatePoolDto customerPrivatePoolDto);
    CustomerPrivatePoolDto selectInfo(Long id);
    List<CustomerPrivatePoolDto> selectInfos();
}
src/main/java/com/ruoyi/basic/pojo/Customer.java
@@ -10,6 +10,7 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import org.checkerframework.checker.units.qual.A;
/**
 * å®¢æˆ·æ¡£æ¡ˆå¯¹è±¡ customer
@@ -123,4 +124,9 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty(value = "使用用户")
    private Long usageUser;
    @ApiModelProperty(value = "使用状态")
    private Long usageStatus;
}
src/main/java/com/ruoyi/basic/pojo/CustomerFollowUp.java
@@ -8,6 +8,7 @@
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
@@ -34,9 +35,9 @@
    private Integer id;
    /**
     * å…³è”的客户ID
     * å…³è”的私海id
     */
    private Integer customerId;
    private Long customerPrivatePoolId;
    /**
     * è·Ÿè¿›æ–¹å¼
@@ -52,6 +53,7 @@
     * è·Ÿè¿›æ—¶é—´
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime followUpTime;
    /**
src/main/java/com/ruoyi/basic/pojo/CustomerPrivate.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,115 @@
package com.ruoyi.basic.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Date;
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.Getter;
import lombok.Setter;
/**
 * <p>
 * å®¢æˆ·æ¡£æ¡ˆ
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-17 10:39:09
 */
@Getter
@Setter
@TableName("customer_private")
@ApiModel(value = "CustomerPrivate对象", description = "客户档案")
public class CustomerPrivate implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("客户名称")
    @Excel(name = "客户名称")
    private String customerName;
    @ApiModelProperty("纳税人识别号")
    @Excel(name = "纳税人识别号")
    private String taxpayerIdentificationNumber;
    @ApiModelProperty("公司地址")
    @Excel(name = "公司地址")
    private String companyAddress;
    @ApiModelProperty("公司电话")
    @Excel(name = "公司电话")
    private String companyPhone;
    @ApiModelProperty("联系人")
    @Excel(name = "联系人")
    private String contactPerson;
    @ApiModelProperty("联系电话")
    @Excel(name = "联系电话", cellType = Excel.ColumnType.STRING)
    private String contactPhone;
    @ApiModelProperty("维护人")
    @Excel(name = "维护人")
    private String maintainer;
    @ApiModelProperty("维护时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "维护时间", width = 30, dateFormat = "yyyy-MM-dd")
    private Date maintenanceTime;
    @ApiModelProperty("租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty("银行基本户")
    @Excel(name = "银行基本户")
    private String basicBankAccount;
    @ApiModelProperty("银行账号")
    @Excel(name = "银行账号")
    private String bankAccount;
    @ApiModelProperty("开户行号")
    @Excel(name = "开户行号")
    private String bankCode;
    @ApiModelProperty("客户分类:零售客户,进销商客户")
    @Excel(name = "客户分类")
    private String customerType;
    @ApiModelProperty("创建人ID")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty("部门ID")
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty("跟进程度")
    @TableField(exist = false)
    private String followUpLevel;
    @ApiModelProperty("跟进时间")
    @TableField(exist = false)
    private Date followUpTime;
    @TableField(exist = false)
    private Long[] ids;
    @TableField(exist = false)
    private String addressPhone;
}
src/main/java/com/ruoyi/basic/pojo/CustomerPrivatePool.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package com.ruoyi.basic.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
 * <p>
 *
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-16 04:43:00
 */
@Data
@TableName("customer_private_pool")
@ApiModel(value = "CustomerPrivatePool对象", description = "")
public class CustomerPrivatePool implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("主键id")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("客户id")
    private Long customerId;
    @ApiModelProperty("绑定人id")
    private Long boundId;
    @ApiModelProperty("创建人")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty("更新人")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @ApiModelProperty("创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("类型区分公海客户和私海客户 é»˜è®¤æ˜¯ç§æµ·å®¢æˆ·0 å…¬æµ·1")
    private Long type;
    @ApiModelProperty("部门id")
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty("删除标识 é»˜è®¤0 1已经删除")
    private Integer DeleteFlag;
}
src/main/java/com/ruoyi/basic/pojo/CustomerReturnVisit.java
@@ -36,7 +36,7 @@
    /**
     * å…³è”客户ID
     */
    private Integer customerId;
    private Integer customerPrivatePoolId;
    /**
     * æé†’开关 (0:关闭, 1:开启)
src/main/java/com/ruoyi/basic/service/CustomerPrivatePoolService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
package com.ruoyi.basic.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerPrivatePool;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
 * <p>
 *  æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-16 04:43:00
 */
public interface CustomerPrivatePoolService extends IService<CustomerPrivatePool> {
    IPage<CustomerPrivatePoolDto> listPage(Page<CustomerPrivatePoolDto> page, CustomerPrivatePoolDto customerPrivatePoolDto);
    boolean deleteCustomerPrivatePool(Long id);
    boolean together(CustomerPrivatePoolDto customerPrivatePool);
    boolean add(CustomerPrivatePoolDto customerPrivatePool);
    CustomerPrivatePoolDto getInfo(Long id);
    Boolean updateCustomerPrivatePoolDto(CustomerPrivatePoolDto customerPrivatePoolDto);
    CustomerPrivatePoolDto getbyId(Long id);
    List<CustomerPrivatePoolDto> selectCustomerPrivatePoolDtoListByIds(List<Long> ids);
    List<CustomerPrivatePoolDto> selectCustomerPrivatePoolDtoLists(CustomerPrivatePoolDto customerPrivatePoolDto);
}
src/main/java/com/ruoyi/basic/service/CustomerPrivateService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package com.ruoyi.basic.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.CustomerPrivateDto;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerPrivate;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
 * <p>
 * å®¢æˆ·æ¡£æ¡ˆ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-17 10:39:09
 */
public interface CustomerPrivateService extends IService<CustomerPrivate> {
    Boolean add(CustomerPrivateDto customerPrivateDto);
    Integer delete(List<Long> id);
    R importData(MultipartFile file);
}
src/main/java/com/ruoyi/basic/service/ICustomerService.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.basic.dto.CustomerDto;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.framework.web.domain.AjaxResult;
import org.springframework.web.multipart.MultipartFile;
@@ -32,7 +33,7 @@
     * @param id å®¢æˆ·æ¡£æ¡ˆä¸»é”®
     * @return å®¢æˆ·è¯¦æƒ…DTO
     */
    CustomerDto selectCustomerDetailById(Long id);
    Customer selectCustomerDetailById(Long id);
    /**
     * æŸ¥è¯¢å®¢æˆ·æ¡£æ¡ˆåˆ—表
@@ -40,7 +41,6 @@
     * @param customer å®¢æˆ·æ¡£æ¡ˆ
     * @return å®¢æˆ·æ¡£æ¡ˆé›†åˆ
     */
    IPage<Customer> selectCustomerList(Page<Customer> page, Customer customer);
    /**
     * æ–°å¢žå®¢æˆ·æ¡£æ¡ˆ
@@ -78,4 +78,6 @@
    List<Customer> selectCustomerLists(Customer customer);
    AjaxResult importData(MultipartFile file);
    IPage<CustomerDto> selectCustomerList(Page<CustomerDto> page, CustomerDto customer);
}
src/main/java/com/ruoyi/basic/service/impl/CustomerFollowUpServiceImpl.java
@@ -132,7 +132,7 @@
        }
        List<CustomerFollowUp> followUps = list(new LambdaQueryWrapper<CustomerFollowUp>()
                .eq(CustomerFollowUp::getCustomerId, customerId));
                .eq(CustomerFollowUp::getCustomerPrivatePoolId, customerId));
        if (followUps != null && !followUps.isEmpty()) {
            for (CustomerFollowUp followUp : followUps) {
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivatePoolServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,234 @@
package com.ruoyi.basic.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.CustomerDto;
import com.ruoyi.basic.dto.CustomerFollowUpDto;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.mapper.CustomerPrivateMapper;
import com.ruoyi.basic.pojo.*;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
import com.ruoyi.basic.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
 * æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-16 04:43:00
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class CustomerPrivatePoolServiceImpl extends ServiceImpl<CustomerPrivatePoolMapper, CustomerPrivatePool> implements CustomerPrivatePoolService {
    @Autowired
    private CustomerPrivatePoolMapper customerPrivatePoolMapper;
    @Autowired
    private CustomerFollowUpService customerFollowUpService;
    @Autowired
    private CustomerReturnVisitService customerReturnVisitService;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private CustomerFollowUpFileService customerFollowUpFileService;
    @Autowired
    private CustomerPrivateMapper customerPrivateMapper;
    @Override
    public IPage<CustomerPrivatePoolDto> listPage(Page<CustomerPrivatePoolDto> page, CustomerPrivatePoolDto customerPrivatePoolDto) {
        IPage<CustomerPrivatePoolDto> customerPrivatePoolDtoIPage = customerPrivatePoolMapper.listPage(page, customerPrivatePoolDto);
        List<Long> customerIds = customerPrivatePoolDtoIPage.getRecords().stream()
                .map(CustomerPrivatePoolDto::getId )
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (!org.springframework.util.CollectionUtils.isEmpty(customerIds)) {
            Map<Long, CustomerFollowUp> latestFollowUpMap = getLatestFollowUpMap(customerIds);
            customerPrivatePoolDtoIPage.getRecords().forEach(c -> {
                String address = StringUtils.defaultString(c.getCompanyAddress(), "");
                String phone = StringUtils.defaultString(c.getCompanyPhone(), "");
                c.setAddressPhone(address + "(" + phone + ")");
                CustomerFollowUp followUp = latestFollowUpMap.get(c.getId());
                if (followUp != null) {
                    c.setFollowUpLevel(followUp.getFollowUpLevel());
                    c.setFollowUpTime(Date.from(
                            followUp.getFollowUpTime().atZone(ZoneId.systemDefault()).toInstant()
                    ));
                }
            });
        }
        return customerPrivatePoolDtoIPage;
    }
    private Map<Long, CustomerFollowUp> getLatestFollowUpMap(List<Long> customerIds) {
        List<CustomerFollowUp> followUps = customerFollowUpService.list(
                new LambdaQueryWrapper<CustomerFollowUp>()
                        .in(CustomerFollowUp::getCustomerPrivatePoolId, customerIds)
                        .orderByDesc(CustomerFollowUp::getFollowUpTime)
        );
        return followUps.stream()
                .collect(Collectors.toMap(
                        CustomerFollowUp::getCustomerPrivatePoolId,
                        followUp -> followUp,
                        (existing, replacement) -> existing
                ));
    }
    @Override
    public boolean deleteCustomerPrivatePool(Long id) {
        List<CustomerPrivatePool> list = this.list(new QueryWrapper<CustomerPrivatePool>().lambda().eq(CustomerPrivatePool::getCustomerId, id));
        for (CustomerPrivatePool customerPrivatePool : list) {
            customerFollowUpService.remove(new QueryWrapper<CustomerFollowUp>().lambda().eq(CustomerFollowUp::getCustomerPrivatePoolId, customerPrivatePool.getId()));
            customerReturnVisitService.remove(new QueryWrapper<CustomerReturnVisit>().lambda().eq(CustomerReturnVisit::getCustomerPrivatePoolId, customerPrivatePool.getId()));
        }
        Customer byId = customerService.getById(id);
        byId.setUsageStatus(0L);
        byId.setUsageUser(0L);
        customerService.updateById(byId);
        list.stream().forEach(customerPrivatePool -> {
            customerPrivatePool.setDeleteFlag(1);
            customerPrivatePoolMapper.updateById(customerPrivatePool);
        });
        return true;
    }
    @Override
    public boolean together(CustomerPrivatePoolDto customerPrivatePoolDto) {
        List<CustomerPrivatePool> existingPools = this.list(new QueryWrapper<CustomerPrivatePool>().lambda().eq(CustomerPrivatePool::getCustomerId, customerPrivatePoolDto.getCustomerId()));
        List<Long> existingBoundIds = existingPools.stream()
                .map(CustomerPrivatePool::getBoundId)
                .collect(Collectors.toList());
        List<Long> newBoundIds = customerPrivatePoolDto.getBoundIds().stream()
                .filter(boundId -> !existingBoundIds.contains(boundId))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(newBoundIds)) {
            return true;
        }
        for (Long id : customerPrivatePoolDto.getBoundIds()) {
            CustomerPrivatePool customerPrivatePool = new CustomerPrivatePool();
            customerPrivatePool.setCustomerId(customerPrivatePoolDto.getCustomerId());
            customerPrivatePool.setBoundId(id);
            customerPrivatePool.setType(1L);
            this.save(customerPrivatePool);
        }
        return true;
    }
    @Override
    public boolean add(CustomerPrivatePoolDto customerPrivatePool) {
        customerPrivatePool.setType(1L);
        this.save(customerPrivatePool);
        Customer byId = customerService.getById(customerPrivatePool.getCustomerId());
        if (byId != null) {
            byId.setUsageStatus(1L);
            byId.setUsageUser(customerPrivatePool.getBoundId());
            return customerService.updateById(byId);
        }
        throw new RuntimeException("客户不存在");
    }
    @Override
    public CustomerPrivatePoolDto getInfo(Long id) {
        CustomerPrivatePoolDto customerPrivatePool = customerPrivatePoolMapper.selectInfo(id);
        if (customerPrivatePool == null) {
            return null;
        }
        // æŸ¥è¯¢è·Ÿè¿›è®°å½•
        List<CustomerFollowUp> followUpList = customerFollowUpService.list(
                new LambdaQueryWrapper<CustomerFollowUp>()
                        .eq(CustomerFollowUp::getCustomerPrivatePoolId, id)
                        .orderByDesc(CustomerFollowUp::getFollowUpTime)
        );
        if (!CollectionUtils.isEmpty(followUpList)) {
            List<CustomerFollowUpDto> followUpDtoList = followUpList.stream().map(followUp -> {
                CustomerFollowUpDto followUpDto = new CustomerFollowUpDto();
                BeanUtils.copyProperties(followUp, followUpDto);
                // æŸ¥è¯¢é™„ä»¶
                List<CustomerFollowUpFile> fileList = customerFollowUpFileService.list(
                        new LambdaQueryWrapper<CustomerFollowUpFile>()
                                .eq(CustomerFollowUpFile::getFollowUpId, followUp.getId())
                );
                followUpDto.setFileList(fileList);
                return followUpDto;
            }).collect(Collectors.toList());
            customerPrivatePool.setFollowUpList(followUpDtoList);
        }
        return customerPrivatePool;
    }
    @Override
    public Boolean updateCustomerPrivatePoolDto(CustomerPrivatePoolDto customerPrivatePoolDto) {
        if (customerPrivatePoolDto.getType() == 0L) {
            CustomerPrivate byId = customerPrivateMapper.selectById(customerPrivatePoolDto.getCustomerId());
            BeanUtils.copyProperties(customerPrivatePoolDto, byId);
            byId.setId(customerPrivatePoolDto.getCustomerId());
            customerPrivateMapper.updateById(byId);
        } else if (customerPrivatePoolDto.getType() == 1L) {
            Customer customer = customerService.getById(customerPrivatePoolDto.getCustomerId());
            BeanUtils.copyProperties(customerPrivatePoolDto, customer);
            customer.setId(customerPrivatePoolDto.getCustomerId());
            customerService.updateById(customer);
        }
        return true;
    }
    @Override
    public CustomerPrivatePoolDto getbyId(Long id) {
        CustomerPrivatePoolDto customerPrivatePool = customerPrivatePoolMapper.selectInfo(id);
        return customerPrivatePool;
    }
    @Override
    public List<CustomerPrivatePoolDto> selectCustomerPrivatePoolDtoListByIds(List<Long> ids) {
        ArrayList<CustomerPrivatePoolDto> customerPrivatePoolDtos = new ArrayList<>();
        for (Long id : ids) {
            CustomerPrivatePoolDto customerPrivatePoolDto = customerPrivatePoolMapper.selectInfo(id);
            customerPrivatePoolDtos.add(customerPrivatePoolDto);
        }
        return customerPrivatePoolDtos;
    }
    @Override
    public List<CustomerPrivatePoolDto> selectCustomerPrivatePoolDtoLists(CustomerPrivatePoolDto customerPrivatePoolDto) {
        return customerPrivatePoolMapper.selectInfos();
    }
}
src/main/java/com/ruoyi/basic/service/impl/CustomerPrivateServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
package com.ruoyi.basic.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.CustomerPrivateDto;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
import com.ruoyi.basic.pojo.*;
import com.ruoyi.basic.mapper.CustomerPrivateMapper;
import com.ruoyi.basic.service.CustomerFollowUpService;
import com.ruoyi.basic.service.CustomerPrivateService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.service.CustomerReturnVisitService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.pojo.SalesLedger;
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.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
 * å®¢æˆ·æ¡£æ¡ˆ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-17 10:39:09
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class CustomerPrivateServiceImpl extends ServiceImpl<CustomerPrivateMapper, CustomerPrivate> implements CustomerPrivateService {
    @Autowired
    private CustomerPrivatePoolMapper customerPrivatePoolMapper;
    @Autowired
    private CustomerFollowUpService customerFollowUpService;
    @Autowired
    private CustomerReturnVisitService customerReturnVisitService;
    @Autowired
    private SalesLedgerMapper salesLedgerMapper;
    @Autowired
    private  CustomerPrivateMapper customerPrivateMapper;
    @Autowired
    private CustomerPrivateService customerPrivateService;
    @Override
    public Boolean add(CustomerPrivateDto customerPrivateDto) {
        //新增私海 å®¢æˆ·
        this.save(customerPrivateDto);
        //新增私海记录
        CustomerPrivatePool customerPrivatePool = new CustomerPrivatePool();
        customerPrivatePool.setCustomerId(customerPrivateDto.getId());
        customerPrivatePool.setType(0L);
        customerPrivatePool.setBoundId(SecurityUtils.getLoginUser().getUserId());
        customerPrivatePoolMapper.insert(customerPrivatePool);
        return true;
    }
    @Override
    public Integer delete(List<Long> ids) {
        List<CustomerPrivatePool> customerPrivatePools = customerPrivatePoolMapper.selectList(new QueryWrapper<CustomerPrivatePool>().lambda().in(CustomerPrivatePool::getId, ids));
        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(new QueryWrapper<SalesLedger>().lambda().in(SalesLedger::getCustomerId, customerPrivatePools.stream().map(CustomerPrivatePool::getCustomerId).collect(Collectors.toList())));
        if (!CollectionUtils.isEmpty(salesLedgers)) {
            throw new RuntimeException("客户有销售合同,请先删除销售合同");
        }
        if (CollectionUtils.isEmpty(customerPrivatePools)) {
            throw new RuntimeException("客户不存在");
        }
        customerFollowUpService.remove(new QueryWrapper<CustomerFollowUp>().lambda().in(CustomerFollowUp::getCustomerPrivatePoolId, customerPrivatePools.stream().map(CustomerPrivatePool::getCustomerId).collect(Collectors.toList())));
        customerReturnVisitService.remove(new QueryWrapper<CustomerReturnVisit>().lambda().in(CustomerReturnVisit::getCustomerPrivatePoolId, customerPrivatePools.stream().map(CustomerPrivatePool::getCustomerId).collect(Collectors.toList())));
        customerPrivatePools.stream().forEach(customerPrivatePool -> {
            customerPrivatePool.setDeleteFlag(1);
            customerPrivatePoolMapper.updateById(customerPrivatePool);
        });
        return 1;
    }
    @Override
    public R importData(MultipartFile file) {
        try {
            List<CustomerPrivate> existingList = customerPrivateService.list();
            java.util.Set<String> existingCustomerNames = existingList.stream()
                    .map(CustomerPrivate::getCustomerName)
                    .collect(Collectors.toSet());
            ExcelUtil<CustomerPrivate> util = new ExcelUtil<CustomerPrivate>(CustomerPrivate.class);
            List<CustomerPrivate> userList = util.importExcel(file.getInputStream());
            if (CollectionUtils.isEmpty(userList)) {
                return R.fail("模板错误或导入数据为空");
            }
            int successCount = 0;
            int skipCount = 0;
            for (CustomerPrivate user : userList) {
                if (existingCustomerNames.contains(user.getCustomerName())) {
                    skipCount++;
                    continue;
                }
                CustomerPrivateDto customerPrivateDto = new CustomerPrivateDto();
                BeanUtils.copyProperties(user, customerPrivateDto);
                this.add(customerPrivateDto);
                existingCustomerNames.add(user.getCustomerName());
                successCount++;
            }
            return R.ok("导入完成,成功" + successCount + "条,跳过重复" + skipCount + "条");
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("导入失败:" + e.getMessage());
        }
    }
}
src/main/java/com/ruoyi/basic/service/impl/CustomerReturnVisitServiceImpl.java
@@ -75,7 +75,7 @@
            throw new ServiceException("客户ID不能为空");
        }
        LambdaQueryWrapper<CustomerReturnVisit> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CustomerReturnVisit::getCustomerId, customerId);
        queryWrapper.eq(CustomerReturnVisit::getCustomerPrivatePoolId, customerId);
        CustomerReturnVisit returnVisit = baseMapper.selectOne(queryWrapper);
        if (returnVisit == null) {
@@ -94,7 +94,7 @@
            throw new ServiceException("客户ID不能为空");
        }
        LambdaQueryWrapper<CustomerReturnVisit> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CustomerReturnVisit::getCustomerId, customerId);
        queryWrapper.eq(CustomerReturnVisit::getCustomerPrivatePoolId, customerId);
        List<CustomerReturnVisit> returnVisits = baseMapper.selectList(queryWrapper);
        for (CustomerReturnVisit returnVisit : returnVisits) {
@@ -124,7 +124,7 @@
        if (returnVisit == null) {
            throw new ServiceException("回访提醒数据不能为空");
        }
        if (returnVisit.getCustomerId() == null) {
        if (returnVisit.getCustomerPrivatePoolId() == null) {
            throw new ServiceException("客户ID不能为空");
        }
        if (returnVisit.getReminderTime() == null) {
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -1,8 +1,6 @@
package com.ruoyi.basic.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -11,10 +9,13 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.dto.CustomerDto;
import com.ruoyi.basic.dto.CustomerFollowUpDto;
import com.ruoyi.basic.dto.CustomerPrivatePoolDto;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.CustomerPrivatePoolMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerFollowUp;
import com.ruoyi.basic.pojo.CustomerFollowUpFile;
import com.ruoyi.basic.pojo.CustomerPrivatePool;
import com.ruoyi.basic.service.CustomerFollowUpFileService;
import com.ruoyi.basic.service.CustomerFollowUpService;
import com.ruoyi.basic.service.CustomerReturnVisitService;
@@ -30,6 +31,7 @@
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;
@@ -51,13 +53,18 @@
@AllArgsConstructor
@Slf4j
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements ICustomerService {
    private final SalesLedgerMapper salesLedgerMapper;
    @Autowired
    private  SalesLedgerMapper salesLedgerMapper;
    @Autowired
    private CustomerPrivatePoolMapper customerPrivatePoolMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private CustomerFollowUpService customerFollowUpService;
    @Autowired
    private CustomerFollowUpFileService customerFollowUpFileService;
    @Autowired
    private CustomerReturnVisitService customerReturnVisitService;
    /**
@@ -78,41 +85,8 @@
     * @return å®¢æˆ·è¯¦æƒ…DTO
     */
    @Override
    public CustomerDto selectCustomerDetailById(Long id) {
        Customer customer = customerMapper.selectById(id);
        if (customer == null) {
            return null;
        }
        CustomerDto dto = new CustomerDto();
        BeanUtils.copyProperties(customer, dto);
        // æŸ¥è¯¢è·Ÿè¿›è®°å½•
        List<CustomerFollowUp> followUpList = customerFollowUpService.list(
                new LambdaQueryWrapper<CustomerFollowUp>()
                        .eq(CustomerFollowUp::getCustomerId, id)
                        .orderByDesc(CustomerFollowUp::getFollowUpTime)
        );
        if (!CollectionUtils.isEmpty(followUpList)) {
            List<CustomerFollowUpDto> followUpDtoList = followUpList.stream().map(followUp -> {
                CustomerFollowUpDto followUpDto = new CustomerFollowUpDto();
                BeanUtils.copyProperties(followUp, followUpDto);
                // æŸ¥è¯¢é™„ä»¶
                List<CustomerFollowUpFile> fileList = customerFollowUpFileService.list(
                        new LambdaQueryWrapper<CustomerFollowUpFile>()
                                .eq(CustomerFollowUpFile::getFollowUpId, followUp.getId())
                );
                followUpDto.setFileList(fileList);
                return followUpDto;
            }).collect(Collectors.toList());
            dto.setFollowUpList(followUpDtoList);
        }
        return dto;
    public Customer selectCustomerDetailById(Long id) {
        return this.getById( id);
    }
    /**
@@ -122,62 +96,53 @@
     * @return å®¢æˆ·æ¡£æ¡ˆ
     */
    @Override
    public IPage<Customer> selectCustomerList(Page<Customer> page, Customer customer) {
        // 1. å¤„理空值场景(参数校验)
        if (page == null) {
            page = Page.of(1, 10); // é»˜è®¤ç¬¬1页,每页10条数据
        }
        if (customer == null) {
            customer = new Customer(); // é¿å…ç©ºå¯¹è±¡å¯¼è‡´çš„NPE
    public IPage<CustomerDto> selectCustomerList(Page<CustomerDto> page, CustomerDto customer) {
        IPage<CustomerDto> customerPage = customerMapper.listPage(page, customer);
        List<CustomerDto> records = customerPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return customerPage;
        }
        // 2. æž„建查询条件(增强空值安全)
        LambdaQueryWrapper<Customer> queryWrapper = new LambdaQueryWrapper<>();
        String customerName = customer.getCustomerName();
        String customerType = customer.getCustomerType();
        if (StringUtils.isNotBlank(customerName)) {
            queryWrapper.like(Customer::getCustomerName, customerName);
        }
        if (StringUtils.isNotBlank(customerType)) {
            queryWrapper.like(Customer::getCustomerType, customerType);
        }
        // 3. æ‰§è¡Œåˆ†é¡µæŸ¥è¯¢ï¼ˆä¿ç•™åˆ†é¡µå…ƒæ•°æ®ï¼‰
        IPage<Customer> customerPage = customerMapper.selectPage(page, queryWrapper);
        // 4. æ•°æ®å¤„理(增强空值安全 & ä»£ç å¯è¯»æ€§ï¼‰
        List<Customer> processedList = customerPage.getRecords().stream()
                .filter(Objects::nonNull) // è¿‡æ»¤ç©ºå¯¹è±¡ï¼ˆé¿å…åŽç»­æ“ä½œNPE)
                .peek(c -> {
                    // å®‰å…¨èŽ·å–å­—æ®µï¼Œé¿å…null值拼接
                    String address = StringUtils.defaultString(c.getCompanyAddress(), "");
                    String phone = StringUtils.defaultString(c.getCompanyPhone(), "");
                    c.setAddressPhone(address + "(" + phone + ")");
                    // æŸ¥è¯¢æœ€æ–°çš„跟进记录
                    CustomerFollowUp followUp = customerFollowUpService.getOne(
                            new LambdaQueryWrapper<CustomerFollowUp>()
                                    .eq(CustomerFollowUp::getCustomerId, c.getId())
                                    .orderByDesc(CustomerFollowUp::getFollowUpTime)
                                    .last("LIMIT 1")
                    );
                    if (followUp != null) {
                        c.setFollowUpLevel(followUp.getFollowUpLevel());
                        c.setFollowUpTime(
                                Date.from(
                                        followUp.getFollowUpTime().atZone(ZoneId.systemDefault()).toInstant()
                                )
                        );
                    }
                })
        List<Long> customerIds = records.stream()
                .map(CustomerDto::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        // 5. æ›´æ–°åˆ†é¡µç»“果中的数据(保持分页信息完整)
        IPage<Customer> resultPage = new Page<>(customerPage.getCurrent(), customerPage.getSize(), customerPage.getTotal());
        resultPage.setRecords(processedList);
        if (!CollectionUtils.isEmpty(customerIds)) {
            Map<Long, CustomerFollowUp> latestFollowUpMap = getLatestFollowUpMap(customerIds);
        return customerPage; // è¿”回包含分页信息的IPage对象
            records.forEach(c -> {
                String address = StringUtils.defaultString(c.getCompanyAddress(), "");
                String phone = StringUtils.defaultString(c.getCompanyPhone(), "");
                c.setAddressPhone(address + "(" + phone + ")");
                CustomerFollowUp followUp = latestFollowUpMap.get(c.getId());
                if (followUp != null) {
                    c.setFollowUpLevel(followUp.getFollowUpLevel());
                    c.setFollowUpTime(Date.from(
                            followUp.getFollowUpTime().atZone(ZoneId.systemDefault()).toInstant()
                    ));
                }
            });
        }
        return customerPage;
    }
    private Map<Long, CustomerFollowUp> getLatestFollowUpMap(List<Long> customerIds) {
        List<CustomerFollowUp> followUps = customerFollowUpService.list(
                new LambdaQueryWrapper<CustomerFollowUp>()
                        .in(CustomerFollowUp::getCustomerPrivatePoolId, customerIds)
                        .orderByDesc(CustomerFollowUp::getFollowUpTime)
        );
        return followUps.stream()
                .collect(Collectors.toMap(
                        CustomerFollowUp::getCustomerPrivatePoolId,
                        followUp -> followUp,
                        (existing, replacement) -> existing
                ));
    }
    /**
@@ -222,6 +187,10 @@
        if (!salesLedgers.isEmpty()) {
            throw new RuntimeException("客户档案下有销售合同,请先删除销售合同");
        }
        List<CustomerPrivatePool> customerPrivatePools = customerPrivatePoolMapper.selectList(new QueryWrapper<CustomerPrivatePool>().lambda().in(CustomerPrivatePool::getCustomerId, idList));
        if (!customerPrivatePools.isEmpty()) {
            throw new RuntimeException("客户档案下有客户私海,请先收回私海数据");
        }
        //  åˆ é™¤å®¢æˆ·çš„同时也需要删除对应的客户跟随、附件和回访提醒
        for (Long id : ids) {
            customerFollowUpService.deleteByCustomerId(id);
src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -2,6 +2,7 @@
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.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.dto.ProductDto;
@@ -89,6 +90,9 @@
    @Override
    public int addOrEditProduct(ProductDto productDto) {
        if (ObjectUtils.isEmpty(productDto.getParentId())) {
            throw new IllegalArgumentException("请选择父节点");
        }
        if (productDto.getId() == null) {
            // æ–°å¢žäº§å“é€»è¾‘
            if (productDto.getParentId() == null) {
src/main/java/com/ruoyi/basic/task/ReturnVisitReminderTask.java
@@ -76,7 +76,7 @@
        }
        try {
            unipushService.sendReturnVisitReminder(returnVisitId, client.getCid(), returnVisit.getContent(), returnVisit.getCustomerId());
            unipushService.sendReturnVisitReminder(returnVisitId, client.getCid(), returnVisit.getContent(), returnVisit.getCustomerPrivatePoolId());
            CustomerReturnVisit updateObj = new CustomerReturnVisit();
            updateObj.setId(returnVisitId);
            updateObj.setIsCompleted(1);
src/main/java/com/ruoyi/common/config/IgnoreTableConfig.java
@@ -36,6 +36,8 @@
        IGNORE_TABLES.add("gen_table");
        IGNORE_TABLES.add("sys_notice");
        IGNORE_TABLES.add("sys_user_client");
        IGNORE_TABLES.add("gen_table_column");
        IGNORE_TABLES.add("product_model");
        IGNORE_TABLES.add("product");
    }
}
src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java
@@ -7,8 +7,6 @@
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.ruoyi.common.handler.CustomTenantLineHandler;
import com.ruoyi.common.interceptor.DataScopeSqlInterceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
@@ -23,9 +21,7 @@
import java.sql.SQLException;
/**
 * Mybatis Plus é…ç½®
 *
 * @author ruoyi
 * MyBatis Plus config.
 */
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
@@ -35,66 +31,47 @@
    private DataScopeSqlInterceptor dataScopeSqlInterceptor;
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor()
    {
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // ç§Ÿæˆ·æ’ä»¶
//        TenantLineInnerInterceptor tenantLineInnerInterceptor = new TenantLineInnerInterceptor(new CustomTenantLineHandler());
//        interceptor.addInnerInterceptor(tenantLineInnerInterceptor);
        // åˆ†é¡µæ’ä»¶
        interceptor.addInnerInterceptor(paginationInnerInterceptor());
        // ä¹è§‚锁插件
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
        // é˜»æ–­æ’ä»¶
        interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
        // æ•°æ®æƒé™æ’ä»¶
        // Rewrite the original SQL before pagination generates the count query.
        interceptor.addInnerInterceptor(dataScopeSqlInterceptor);
        interceptor.addInnerInterceptor(paginationInnerInterceptor());
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
        interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
        return interceptor;
    }
    /**
     * åˆ†é¡µæ’件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html
     * Pagination interceptor.
     */
//    public PaginationInnerInterceptor paginationInnerInterceptor()
//    {
//        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
//        // è®¾ç½®æ•°æ®åº“类型为mysql
//        paginationInnerInterceptor.setDbType(DbType.MYSQL);
//        // è®¾ç½®æœ€å¤§å•页限制数量,默认 500 æ¡ï¼Œ-1 ä¸å—限制
//        paginationInnerInterceptor.setMaxLimit(-1L);
//        return paginationInnerInterceptor;
//    }
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        PaginationInnerInterceptor interceptor = new PaginationInnerInterceptor(DbType.MYSQL) {
            @Override
            public void beforeQuery(Executor executor, MappedStatement ms, Object parameter,
                                    RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
                                    RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
                    throws SQLException {
                IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);
                if (page != null && page.getSize() <= 0) {
                    // å½“size<=0时,不进行分页
                    return;
                }
                super.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            }
        };
        interceptor.setMaxLimit(1000L); // å»ºè®®è®¾ç½®åˆç†çš„æœ€å¤§å€¼
        interceptor.setMaxLimit(1000L);
        return interceptor;
    }
    /**
     * ä¹è§‚锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html
     * Optimistic lock interceptor.
     */
    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor()
    {
    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
        return new OptimisticLockerInnerInterceptor();
    }
    /**
     * å¦‚果是对全表的删除或更新操作,就会终止该操作 https://baomidou.com/guide/interceptor-block-attack.html
     * Block full-table update and delete.
     */
    public BlockAttackInnerInterceptor blockAttackInnerInterceptor()
    {
    public BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
        return new BlockAttackInnerInterceptor();
    }
}
}
src/main/java/com/ruoyi/production/controller/ProcessRouteItemController.java
@@ -1,27 +1,19 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProcessRouteItemDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProcessRouteItem;
import com.ruoyi.production.service.ProcessRouteItemService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("processRouteItem")
@RequestMapping("/processRouteItem")
@Api(tags = "工艺路线明细")
public class ProcessRouteItemController {
    @Autowired
src/main/java/com/ruoyi/production/controller/ProductOrderController.java
@@ -1,13 +1,11 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.service.ProductOrderService;
import io.swagger.annotations.Api;
@@ -16,7 +14,6 @@
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
@RequestMapping("productOrder")
src/main/java/com/ruoyi/production/controller/ProductOrderMaterialController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductOrderMaterialDto;
import com.ruoyi.production.pojo.ProductOrderMaterial;
import com.ruoyi.production.service.ProductOrderMaterialService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@AllArgsConstructor
@RequestMapping("/productOrderMaterial")
@Api(value = "ProductOrderMaterial", tags = "生产订单物料表")
public class ProductOrderMaterialController {
    private ProductOrderMaterialService productOrderMaterialservice;
    @GetMapping("/detailList")
    @ApiOperation("分页查询所有生产订单物料表")
    public R listPage(Page<ProductOrderMaterial> page, ProductOrderMaterial productOrderMaterial) {
        IPage<ProductOrderMaterial> listPage = productOrderMaterialservice.listPage(page, productOrderMaterial);
        return R.ok(listPage);
    }
    @PostMapping("/add")
    @ApiOperation("新增生产订单物料表")
    public R add(@RequestBody ProductOrderMaterial productOrderMaterial) {
        return R.ok(productOrderMaterialservice.save(productOrderMaterial));
    }
    @PostMapping("/update")
    @ApiOperation("修改生产订单物料表")
    public R update(@RequestBody ProductOrderMaterial productOrderMaterial) {
        return R.ok(productOrderMaterialservice.updateById(productOrderMaterial));
    }
    @GetMapping("/list")
    @ApiOperation("领料台账列表")
    public R list(ProductOrderMaterialDto productOrderMaterialDto) {
        List<ProductOrderMaterialDto> productOrderMaterialDtos = productOrderMaterialservice.pickMaterial(productOrderMaterialDto);
        return R.ok(productOrderMaterialDtos);
    }
}
src/main/java/com/ruoyi/production/dto/ProductOrderMaterialDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package com.ruoyi.production.dto;
import com.ruoyi.production.pojo.ProductOrderMaterial;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class ProductOrderMaterialDto extends ProductOrderMaterial {
}
src/main/java/com/ruoyi/production/mapper/ProductOrderMaterialMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.production.dto.ProductOrderMaterialDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProductOrderMaterial;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface ProductOrderMaterialMapper extends BaseMapper<ProductOrderMaterial> {
    IPage<ProductOrderMaterial> pickMaterial(@Param("id") Long ProductOrderId);
    List<ProductStructureDto> selectLeafNode(@Param("bomId") Long bomId);
    List<ProductOrderMaterialDto> selectByProductModelIds(@Param("ids") List<Long> productModelIds);
}
src/main/java/com/ruoyi/production/mapper/ProductStructureMapper.java
@@ -1,8 +1,6 @@
package com.ruoyi.production.mapper;
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.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProductStructure;
import org.apache.ibatis.annotations.Mapper;
@@ -16,4 +14,6 @@
    List<ProductStructureDto> listBybomId(@Param("bomId") Integer bomId);
    List<ProductStructureDto> listBybomAndProcess(@Param("bomId") Integer bomId, @Param("processId") Long processId);
    List<ProductStructureDto> selectLeafNode(@Param("bomId") Integer bomId);
}
src/main/java/com/ruoyi/production/pojo/ProductOrder.java
@@ -3,7 +3,6 @@
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
src/main/java/com/ruoyi/production/pojo/ProductOrderMaterial.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("product_order_material")
@ApiModel(description="生产订单物料表")
public class ProductOrderMaterial implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
    * ä¸»é”®ID
    */
    @ApiModelProperty(value="主键ID")
    private Long id;
    /**
    * ç”Ÿäº§è®¢å•ID
    */
    @ApiModelProperty(value="生产订单ID")
    private Long productOrderId;
    /**
    * å·¥åºåç§°
    */
    @ApiModelProperty(value="工序名称")
    private String processName;
    /**
    * åŽŸæ–™åç§°
    */
    @ApiModelProperty(value="原料名称")
    private String materialName;
    /**
    * åŽŸæ–™åž‹å·
    */
    @ApiModelProperty(value="原料型号")
    private String materialModel;
    /**
    * éœ€æ±‚数量
    */
    @ApiModelProperty(value="需求数量")
    private BigDecimal requiredQty;
    /**
    * è®¡é‡å•位
    */
    @ApiModelProperty(value="计量单位")
    private String unit;
    /**
    * é¢†ç”¨æ•°é‡
    */
    @ApiModelProperty(value="领用数量")
    private BigDecimal pickQty;
    /**
    * è¡¥æ–™æ•°é‡
    */
    @ApiModelProperty(value="补料数量")
    private BigDecimal supplementQty;
    /**
    * é€€æ–™æ•°é‡
    */
    @ApiModelProperty(value="退料数量")
    private BigDecimal returnQty;
    /**
    * å®žé™…数量
    */
    @ApiModelProperty(value="实际数量")
    private BigDecimal actualQty;
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty(value = "修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "修改用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
}
src/main/java/com/ruoyi/production/pojo/ProductProcess.java
@@ -86,4 +86,12 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty(value ="是否入库")
    @TableField("is_inbound")
    private Boolean inbound;
    @ApiModelProperty(value ="是否报工")
    @TableField("is_report_work")
    private Boolean reportWork;
}
src/main/java/com/ruoyi/production/service/ProductOrderMaterialService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package com.ruoyi.production.service;
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.production.dto.ProductOrderMaterialDto;
import com.ruoyi.production.pojo.ProductOrderMaterial;
import java.util.List;
public interface ProductOrderMaterialService extends IService<ProductOrderMaterial> {
    IPage<ProductOrderMaterial> listPage(Page<ProductOrderMaterial> page, ProductOrderMaterial productOrderMaterial);
    List<ProductOrderMaterialDto> pickMaterial(ProductOrderMaterialDto productOrderMaterialDto);
}
src/main/java/com/ruoyi/production/service/impl/ProductOrderMaterialServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.dto.ProductOrderMaterialDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.ProcessRouteMapper;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.mapper.ProductOrderMaterialMapper;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.pojo.ProductOrderMaterial;
import com.ruoyi.production.service.ProductOrderMaterialService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProductOrderMaterialServiceImpl extends ServiceImpl<ProductOrderMaterialMapper, ProductOrderMaterial> implements ProductOrderMaterialService {
    private final ProductOrderMaterialMapper productOrderMaterialmapper;
    private final ProductOrderMapper productOrderMapper;
    private final ProcessRouteMapper processRouteMapper;
    @Override
    public IPage<ProductOrderMaterial> listPage(Page<ProductOrderMaterial> page, ProductOrderMaterial productOrderMaterial) {
        return productOrderMaterialmapper.selectPage(page, null);
    }
    @Override
    public List<ProductOrderMaterialDto> pickMaterial(ProductOrderMaterialDto productOrderMaterialDto) {
        Long productOrderId = productOrderMaterialDto.getProductOrderId();
        ProductOrder productOrder = productOrderMapper.selectById(productOrderId);
        BigDecimal quantity = productOrder.getQuantity();
        ProcessRoute processRoute = processRouteMapper.selectById(productOrder.getRouteId());
        //查询叶子节点
        List<ProductStructureDto> productStructureDtoList = productOrderMaterialmapper.selectLeafNode(Long.valueOf(processRoute.getBomId()));
        List<Long> productModelIds = productStructureDtoList.stream()
                .map(ProductStructureDto::getProductModelId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (!productModelIds.isEmpty()) {
            List<ProductOrderMaterialDto> productOrderMaterialDtos = productOrderMaterialmapper.selectByProductModelIds(productModelIds);
            if (!productOrderMaterialDtos.isEmpty()) {
                return productOrderMaterialDtos;
            }else {
                throw new RuntimeException("库存没有对应产品");
            }
        }else {
            throw new RuntimeException("请先维护BOM");
        }
    }
}
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerTemplateController.java
@@ -102,6 +102,7 @@
                SalesLedgerProductTemplate salesLedgerProductTemplate = new SalesLedgerProductTemplate();
                BeanUtils.copyProperties(product, salesLedgerProductTemplate);
                salesLedgerProductTemplate.setSalesLedgerId(purchaseLedgerTemplate.getId());
                salesLedgerProductTemplate.setType(2);
                salesLedgerProductTemplateMapper.insert(salesLedgerProductTemplate);
            });
        }
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -9,10 +9,13 @@
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.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.pojo.CustomerPrivatePool;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.SaleEnum;
import com.ruoyi.common.exception.base.BaseException;
@@ -128,6 +131,8 @@
    ;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private CustomerPrivatePoolMapper customerPrivatePoolMapper;
    @Override
    public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) {
@@ -594,7 +599,7 @@
    public int addOrUpdateSalesLedger(SalesLedgerDto salesLedgerDto) {
        try {
            // 1. æ ¡éªŒå®¢æˆ·ä¿¡æ¯
            Customer customer = customerMapper.selectById(salesLedgerDto.getCustomerId());
            CustomerPrivatePoolDto customer = customerPrivatePoolMapper.selectInfo(salesLedgerDto.getCustomerId());
            if (customer == null) {
                throw new BaseException("客户不存在");
            }
src/main/resources/mapper/basic/CustomerMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.basic.mapper.CustomerMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.basic.pojo.Customer">
        <id column="id" property="id" />
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.basic.dto.CustomerDto">
        select
        c.*,
        u.user_name usage_user_name,
        (
        select group_concat(u2.user_name separator ', ')
        from customer_private_pool cpp2
        left join sys_user u2 on cpp2.bound_id = u2.user_id
        where cpp2.customer_id = c.id and cpp2.delete_flag = 0
        and cpp2.bound_id != c.usage_user
        ) as together_user_names
        from customer c
        left join sys_user u on c.usage_user = u.user_id
        <where>
            <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>
        </where>
    </select>
</mapper>
src/main/resources/mapper/basic/CustomerPrivateMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.basic.mapper.CustomerPrivateMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.basic.pojo.CustomerPrivate">
        <id column="id" property="id" />
        <result column="customer_name" property="customerName" />
        <result column="taxpayer_identification_number" property="taxpayerIdentificationNumber" />
        <result column="company_address" property="companyAddress" />
        <result column="company_phone" property="companyPhone" />
        <result column="contact_person" property="contactPerson" />
        <result column="contact_phone" property="contactPhone" />
        <result column="maintainer" property="maintainer" />
        <result column="maintenance_time" property="maintenanceTime" />
        <result column="tenant_id" property="tenantId" />
        <result column="basic_bank_account" property="basicBankAccount" />
        <result column="bank_account" property="bankAccount" />
        <result column="bank_code" property="bankCode" />
        <result column="customer_type" property="customerType" />
        <result column="create_user" property="createUser" />
        <result column="dept_id" property="deptId" />
    </resultMap>
</mapper>
src/main/resources/mapper/basic/CustomerPrivatePoolMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.basic.mapper.CustomerPrivatePoolMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.basic.pojo.CustomerPrivatePool">
        <id column="id" property="id" />
        <result column="customer_id" property="customerId" />
        <result column="bound_id" property="boundId" />
        <result column="create_user" property="createUser" />
        <result column="update_user" property="updateUser" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.basic.dto.CustomerPrivatePoolDto">
        select cpp.id,
        cpp.bound_id,
        cpp.type,
        coalesce(c.id, cp.id) as customer_id,
        coalesce(c.customer_name, cp.customer_name) as customer_name,
        coalesce(c.customer_type, cp.customer_type) as customer_type,
        coalesce(c.taxpayer_identification_number, cp.taxpayer_identification_number) as taxpayer_identification_number,
        coalesce(c.company_address, cp.company_address) as company_address,
        coalesce(c.company_phone, cp.company_phone) as company_phone,
        coalesce(c.contact_person, cp.contact_person) as contact_person,
        coalesce(c.contact_phone, cp.contact_phone) as contact_phone,
        coalesce(c.maintainer, cp.maintainer) as maintainer,
        coalesce(c.maintenance_time, cp.maintenance_time) as maintenance_time,
        coalesce(c.tenant_id, cp.tenant_id) as tenant_id,
        coalesce(c.basic_bank_account, cp.basic_bank_account) as basic_bank_account,
        coalesce(c.bank_account, cp.bank_account) as bank_account,
        coalesce(c.bank_code, cp.bank_code) as bank_code
        from customer_private_pool cpp
        left join customer c on c.id = cpp.customer_id and cpp.type = 1
        left join customer_private cp on cp.id = cpp.customer_id and cpp.type = 0
        <where>
            cpp.delete_flag = 0
            <if test="c.customerName != null and c.customerName != ''">
                and (c.customer_name like concat('%', #{c.customerName}, '%') or cp.customer_name like concat('%', #{c.customerName}, '%'))
            </if>
            <if test="c.customerType != null">
                and c.customer_type = #{c.customerType}
            </if>
            <if test="c.boundId != null">
                and cpp.boundId = #{c.boundId}
            </if>
        </where>
        order by cpp.id desc
    </select>
    <select id="selectInfo" resultType="com.ruoyi.basic.dto.CustomerPrivatePoolDto">
        select cpp.id,
               cpp.bound_id,
               cpp.type,
               coalesce(c.id, cp.id) as customer_id,
               coalesce(c.customer_name, cp.customer_name) as customer_name,
               coalesce(c.customer_type, cp.customer_type) as customer_type,
               coalesce(c.taxpayer_identification_number, cp.taxpayer_identification_number) as taxpayer_identification_number,
               coalesce(c.company_address, cp.company_address) as company_address,
               coalesce(c.company_phone, cp.company_phone) as company_phone,
               coalesce(c.contact_person, cp.contact_person) as contact_person,
               coalesce(c.contact_phone, cp.contact_phone) as contact_phone,
               coalesce(c.maintainer, cp.maintainer) as maintainer,
               coalesce(c.maintenance_time, cp.maintenance_time) as maintenance_time,
               coalesce(c.tenant_id, cp.tenant_id) as tenant_id,
               coalesce(c.basic_bank_account, cp.basic_bank_account) as basic_bank_account,
               coalesce(c.bank_account, cp.bank_account) as bank_account,
               coalesce(c.bank_code, cp.bank_code) as bank_code
        from customer_private_pool cpp
                 left join customer c on c.id = cpp.customer_id and cpp.type = 1
                 left join customer_private cp on cp.id = cpp.customer_id and cpp.type = 0
        <where>
            <if test="id != null">
                and cpp.id = #{id}
            </if>
        </where>
    </select>
    <select id="selectInfos" resultType="com.ruoyi.basic.dto.CustomerPrivatePoolDto">
        select cpp.id,
               cpp.bound_id,
               cpp.type,
               coalesce(c.id, cp.id) as customer_id,
               coalesce(c.customer_name, cp.customer_name) as customer_name,
               coalesce(c.customer_type, cp.customer_type) as customer_type,
               coalesce(c.taxpayer_identification_number, cp.taxpayer_identification_number) as taxpayer_identification_number,
               coalesce(c.company_address, cp.company_address) as company_address,
               coalesce(c.company_phone, cp.company_phone) as company_phone,
               coalesce(c.contact_person, cp.contact_person) as contact_person,
               coalesce(c.contact_phone, cp.contact_phone) as contact_phone,
               coalesce(c.maintainer, cp.maintainer) as maintainer,
               coalesce(c.maintenance_time, cp.maintenance_time) as maintenance_time,
               coalesce(c.tenant_id, cp.tenant_id) as tenant_id,
               coalesce(c.basic_bank_account, cp.basic_bank_account) as basic_bank_account,
               coalesce(c.bank_account, cp.bank_account) as bank_account,
               coalesce(c.bank_code, cp.bank_code) as bank_code
        from customer_private_pool cpp
                 left join customer c on c.id = cpp.customer_id and cpp.type = 1
                 left join customer_private cp on cp.id = cpp.customer_id and cpp.type = 0
    </select>
</mapper>
src/main/resources/mapper/production/ProcessRouteItemMapper.xml
@@ -17,6 +17,8 @@
        select pri.*,
               pr.description ,
               pp.name as process_name,
               pp.is_inbound as inbound,
               pp.is_report_work as reportWork,
               pm.speculative_trading_name,
               pm.product_id,
               pm.model,
src/main/resources/mapper/production/ProductOrderMaterialMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.production.mapper.ProductOrderMaterialMapper">
    <resultMap id="BaseResultMap" type="com.ruoyi.production.pojo.ProductOrderMaterial">
        <id column="id" property="id" />
                <result column="tenant_id" property="tenantId" />
                <result column="process_name" property="processName" />
                <result column="material_name" property="materialName" />
                <result column="material_model" property="materialModel" />
                <result column="required_qty" property="requiredQty" />
                <result column="unit" property="unit" />
                <result column="pick_qty" property="pickQty" />
                <result column="supplement_qty" property="supplementQty" />
                <result column="return_qty" property="returnQty" />
                <result column="actual_qty" property="actualQty" />
                <result column="create_time" property="createTime" />
                <result column="update_time" property="updateTime" />
                <result column="create_user" property="createUser" />
                <result column="update_user" property="updateUser" />
    </resultMap>
        <select id="pickMaterial" resultType="com.ruoyi.production.pojo.ProductOrderMaterial">
            SELECT
            si.id,
            si.qualitity,
            COALESCE(si.locked_quantity, 0) AS locked_quantity,
            si.product_model_id,
            si.create_time,
            si.update_time,
            COALESCE(si.warn_num, 0) AS warn_num,
            si.version,
            (si.qualitity - COALESCE(si.locked_quantity, 0)) AS un_locked_quantity,
            pm.model,
            si.remark,
            pm.unit,
            pm.uid_no AS uidNo,
            p.product_name,
            p1.product_name AS parentName,
            si.batch_no,
            si.customer
            FROM
            stock_inventory si
            LEFT JOIN product_model pm ON si.product_model_id = pm.id
            LEFT JOIN product p ON pm.product_id = p.id
            LEFT JOIN product p1 ON p1.id = p.parent_id
        </select>
    <select id="selectLeafNode" resultType="com.ruoyi.production.dto.ProductStructureDto">
        SELECT
            ps.*,
            p.product_name,
            pp.NAME AS process_name,
            pm.product_id,
            pm.model
        FROM
            product_structure ps
                LEFT JOIN product_model pm ON ps.product_model_id = pm.id
                LEFT JOIN product p ON pm.product_id = p.id
                LEFT JOIN product_process pp ON ps.process_id = pp.id
        WHERE
            ps.bom_id = #{bomId}
          AND NOT EXISTS (SELECT 1 FROM product_structure ps_child WHERE ps_child.parent_id = ps.id AND ps_child.bom_id = 30)
        ORDER BY
            ps.id
    </select>
    <select id="selectByProductModelIds" resultType="com.ruoyi.production.dto.ProductOrderMaterialDto">
        SELECT
            si.id,
            si.qualitity,
            COALESCE(si.locked_quantity, 0) AS locked_quantity,
            si.product_model_id,
            si.create_time,
            si.update_time,
            COALESCE(si.warn_num, 0) AS warn_num,
            si.version,
            (si.qualitity - COALESCE(si.locked_quantity, 0)) AS un_locked_quantity,
            pm.model as materialModel,
            si.remark,
            pm.unit,
            pm.uid_no AS uidNo,
            p.product_name as materialName,
            p1.product_name AS parentName,
            leaf.process_name,
            leaf.id AS structure_id
            FROM stock_inventory si
            LEFT JOIN product_model pm ON si.product_model_id = pm.id
            LEFT JOIN product p ON pm.product_id = p.id
            LEFT JOIN product p1 ON p1.id = p.parent_id
            INNER JOIN (
            SELECT
            ps.product_model_id,
            pp.name AS process_name,
            ps.id
        FROM product_structure ps
        LEFT JOIN product_process pp ON ps.process_id = pp.id
        WHERE ps.product_model_id IN
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
        AND ps.id NOT IN (
        SELECT DISTINCT parent_id
        FROM product_structure
        WHERE parent_id IS NOT NULL
        AND parent_id != 0
        AND product_model_id IN
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
        ))
        leaf ON leaf.product_model_id = si.product_model_id
        ORDER BY si.id
    </select>
</mapper>
src/main/resources/mapper/production/ProductProcessRouteItemMapper.xml
@@ -13,6 +13,8 @@
    <select id="listItem" resultType="com.ruoyi.production.dto.ProductProcessRouteItemDto">
        select ppri.*,
               pp.name as process_name,
               pp.is_inbound as inbound,
               pp.is_report_work as reportWork,
               pm.model,
               pm.unit,
               p.product_name,
src/main/resources/mapper/sales/InvoiceLedgerMapper.xml
@@ -123,7 +123,7 @@
                T1.customer_name LIKE CONCAT ('%',#{invoiceLedgerDto.searchText},'%')
            </if>
        </where>
        GROUP BY T1.customer_name
        GROUP BY T1.customer_name,t1.customer_id
    </select>
    <select id="invoiceLedgerProductInfo" resultType="com.ruoyi.sales.dto.InvoiceRegistrationProductDto">