| | |
| | | import com.ruoyi.basic.pojo.Customer; |
| | | import com.ruoyi.basic.pojo.CustomerFollowUp; |
| | | import com.ruoyi.basic.pojo.CustomerFollowUpFile; |
| | | import com.ruoyi.basic.service.CustomerFollowUpFileService; |
| | | import com.ruoyi.basic.service.CustomerFollowUpService; |
| | | import com.ruoyi.basic.service.CustomerReturnVisitService; |
| | | import com.ruoyi.basic.service.ICustomerService; |
| | | import com.ruoyi.basic.pojo.CustomerUser; |
| | | import com.ruoyi.basic.service.*; |
| | | import com.ruoyi.basic.vo.CustomerVo; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.framework.security.LoginUser; |
| | | import com.ruoyi.framework.web.domain.AjaxResult; |
| | | import com.ruoyi.project.system.domain.SysUser; |
| | | import com.ruoyi.framework.web.domain.R; |
| | | import com.ruoyi.sales.mapper.SalesLedgerMapper; |
| | | import com.ruoyi.sales.pojo.SalesLedger; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.time.ZoneId; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | |
| | |
| | | @AllArgsConstructor |
| | | @Slf4j |
| | | public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements ICustomerService { |
| | | private final SalesLedgerMapper salesLedgerMapper; |
| | | @Autowired |
| | | private SalesLedgerMapper salesLedgerMapper; |
| | | @Autowired |
| | | private CustomerMapper customerMapper; |
| | | |
| | | @Autowired |
| | | private CustomerFollowUpService customerFollowUpService; |
| | | |
| | | @Autowired |
| | | private CustomerFollowUpFileService customerFollowUpFileService; |
| | | |
| | | @Autowired |
| | | private CustomerReturnVisitService customerReturnVisitService; |
| | | @Autowired |
| | | private CustomerUserService customerUserService; |
| | | |
| | | /** |
| | | * 查询客户档案 |
| | |
| | | * @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); |
| | | public CustomerVo selectCustomerDetailById(Long id) { |
| | | CustomerVo customerVo = new CustomerVo(); |
| | | BeanUtils.copyProperties(this.getById(id), customerVo); |
| | | |
| | | // 查询跟进记录 |
| | | List<CustomerFollowUp> followUpList = customerFollowUpService.list( |
| | |
| | | .eq(CustomerFollowUp::getCustomerId, id) |
| | | .orderByDesc(CustomerFollowUp::getFollowUpTime) |
| | | ); |
| | | |
| | | if (!CollectionUtils.isEmpty(followUpList)) { |
| | | if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(followUpList)) { |
| | | List<CustomerFollowUpDto> followUpDtoList = followUpList.stream().map(followUp -> { |
| | | CustomerFollowUpDto followUpDto = new CustomerFollowUpDto(); |
| | | BeanUtils.copyProperties(followUp, followUpDto); |
| | |
| | | return followUpDto; |
| | | }).collect(Collectors.toList()); |
| | | |
| | | dto.setFollowUpList(followUpDtoList); |
| | | customerVo.setFollowUpList(followUpDtoList); |
| | | } |
| | | |
| | | return dto; |
| | | return customerVo; |
| | | } |
| | | |
| | | /** |
| | |
| | | * @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<CustomerVo> selectCustomerList(Page<CustomerDto> page, CustomerDto customer) { |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | Long loginUserId = loginUser.getUserId(); |
| | | IPage<CustomerVo> customerPage = customerMapper.listPage(page, customer, loginUserId); |
| | | |
| | | List<CustomerVo> 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(followUp.getFollowUpTime()); |
| | | } |
| | | }) |
| | | List<Long> customerIds = records.stream() |
| | | .map(CustomerVo::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() |
| | | )); |
| | | } |
| | | |
| | | // 转换共享用户ID字符串为List<Long> |
| | | String userIdsStr = c.getUserIdsStr(); |
| | | if (StringUtils.isNotEmpty(userIdsStr)) { |
| | | List<Long> userIds = Arrays.stream(userIdsStr.split(",")) |
| | | .map(String::trim) |
| | | .map(Long::parseLong) |
| | | .collect(Collectors.toList()); |
| | | c.setUserIds(userIds); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | return customerPage; |
| | | } |
| | | |
| | | private Map<Long, CustomerFollowUp> getLatestFollowUpMap(List<Long> customerIds) { |
| | | List<CustomerFollowUp> followUps = customerFollowUpService.list( |
| | | new LambdaQueryWrapper<CustomerFollowUp>() |
| | | .in(CustomerFollowUp::getCustomerId, customerIds) |
| | | .orderByDesc(CustomerFollowUp::getFollowUpTime) |
| | | ); |
| | | |
| | | return followUps.stream() |
| | | .collect(Collectors.toMap( |
| | | CustomerFollowUp::getCustomerId, |
| | | followUp -> followUp, |
| | | (existing, replacement) -> existing |
| | | )); |
| | | } |
| | | |
| | | /** |
| | |
| | | if (!salesLedgers.isEmpty()) { |
| | | throw new RuntimeException("客户档案下有销售合同,请先删除销售合同"); |
| | | } |
| | | // 删除客户的同时也需要删除对应的客户跟随、附件和回访提醒 |
| | | // 查询是否有已分配的公海客户 |
| | | List<Customer> assignedPools = customerMapper.selectList( |
| | | new QueryWrapper<Customer>().lambda() |
| | | .in(Customer::getId, idList) |
| | | .eq(Customer::getType, 1). |
| | | eq(Customer::getIsAssigned, 1) // 公海客户 |
| | | ); |
| | | if (!assignedPools.isEmpty()) { |
| | | throw new RuntimeException("客户档案下有已分配的公海客户,请先收回"); |
| | | } |
| | | // 删除客户的同时也需要删除对应的客户跟随、附件和回访提醒 |
| | | for (Long id : ids) { |
| | | customerFollowUpService.deleteByCustomerId(id); |
| | | customerReturnVisitService.deleteByCustomerId(id); |
| | | // 删除客户的共享关系 |
| | | customerUserService.remove( |
| | | new QueryWrapper<CustomerUser>().lambda() |
| | | .eq(CustomerUser::getCustomerId, id) |
| | | ); |
| | | } |
| | | |
| | | // 删除客户主表数据 |
| | | return customerMapper.deleteBatchIds(idList); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<Customer> selectCustomerLists(Customer customer) { |
| | | return customerMapper.selectList(null); |
| | | public List<CustomerVo> selectCustomerLists(CustomerDto customer) { |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | Long loginUserId = loginUser.getUserId(); |
| | | return customerMapper.list(customer, loginUserId); |
| | | } |
| | | |
| | | @Override |
| | | public AjaxResult importData(MultipartFile file) { |
| | | public R importData(MultipartFile file, Integer type) { |
| | | try { |
| | | ExcelUtil<Customer> util = new ExcelUtil<Customer>(Customer.class); |
| | | List<Customer> userList = util.importExcel(file.getInputStream()); |
| | | if (CollectionUtils.isEmpty(userList)) { |
| | | return AjaxResult.warn("模板错误或导入数据为空"); |
| | | return R.fail("模板错误或导入数据为空"); |
| | | } |
| | | |
| | | // 根据 type 参数设置客户类型(私海/公海) |
| | | if (type != null) { |
| | | userList.forEach(customer -> { |
| | | customer.setType(type); |
| | | }); |
| | | } |
| | | this.saveOrUpdateBatch(userList); |
| | | return AjaxResult.success(true); |
| | | return R.ok(true); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return AjaxResult.error("导入失败"); |
| | | return R.fail("导入失败"); |
| | | } |
| | | |
| | | } |
| | |
| | | ).collect(Collectors.toList()); |
| | | } |
| | | |
| | | // 分配公海客户给私海 |
| | | @Override |
| | | public void assignCustomer(CustomerDto customerDto) { |
| | | Customer customer = customerMapper.selectById(customerDto.getId()); |
| | | if (customer.getType() == 1 && customer.getIsAssigned() == 0) { // 公海且可分配 |
| | | customer.setIsAssigned(1); |
| | | customer.setUsageStatus(1L); |
| | | customer.setUsageUser(customerDto.getUsageUser()); |
| | | customerMapper.updateById(customer); |
| | | } |
| | | } |
| | | |
| | | // 回收私海客户到公海 |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void recycleCustomer(CustomerDto customerDto) { |
| | | Customer customer = customerMapper.selectById(customerDto.getId()); |
| | | if (customer.getType() == 1 && customer.getIsAssigned() == 1) { // 公海且已分配 |
| | | customer.setIsAssigned(0); |
| | | customer.setUsageStatus(0L); |
| | | customer.setUsageUser(0L); |
| | | customerMapper.updateById(customer); |
| | | |
| | | // 删除该客户的所有共享关系 |
| | | customerUserService.remove( |
| | | new QueryWrapper<CustomerUser>().lambda() |
| | | .eq(CustomerUser::getCustomerId, customerDto.getId()) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | // 客户共享 |
| | | @Override |
| | | public void together(CustomerDto customerDto) { |
| | | // 查询现有的共享记录 |
| | | List<CustomerUser> existingUsers = customerUserService.list( |
| | | new QueryWrapper<CustomerUser>().lambda().eq(CustomerUser::getCustomerId, customerDto.getId()) |
| | | ); |
| | | |
| | | // 获取已存在的用户ID列表 |
| | | List<Long> existingUserIds = existingUsers.stream() |
| | | .map(CustomerUser::getUserId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 过滤掉已存在的用户,只保留新用户 |
| | | List<Long> newUserIds = customerDto.getUserIds().stream() |
| | | .filter(userId -> !existingUserIds.contains(userId)) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (CollectionUtils.isEmpty(newUserIds)) { |
| | | return; |
| | | } |
| | | |
| | | // 获取当前租户ID |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | Long tenantId = loginUser.getTenantId(); |
| | | |
| | | // 批量保存新的共享记录 |
| | | List<CustomerUser> customerUsers = newUserIds.stream() |
| | | .map(userId -> { |
| | | CustomerUser customerUser = new CustomerUser(); |
| | | customerUser.setCustomerId(customerDto.getId()); |
| | | customerUser.setUserId(userId); |
| | | customerUser.setTenantId(tenantId); |
| | | return customerUser; |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | |
| | | customerUserService.saveBatch(customerUsers); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean back(Long id) { |
| | | //将客户的type改为1 且直接分配给当前用户 |
| | | Customer customer = customerMapper.selectById(id); |
| | | customer.setType(1); |
| | | customer.setIsAssigned(1); |
| | | return this.updateById(customer); |
| | | } |
| | | |
| | | /** |
| | | * 下划线命名转驼峰命名 |
| | | */ |