Commit 49bc70ed82eac0281d13f45017f45bd0b97fe194

Authored by YunaiV
1 parent 1bfb4060

📖 CRM:线索 clue 列表的完善

yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java
1 package cn.iocoder.yudao.module.crm.controller.admin.clue; 1 package cn.iocoder.yudao.module.crm.controller.admin.clue;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  7 +import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; 9 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
7 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 10 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
8 import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*; 11 import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
9 import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; 12 import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
  13 +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
10 import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; 14 import cn.iocoder.yudao.module.crm.service.clue.CrmClueService;
  15 +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
  16 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  17 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  18 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  19 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
11 import io.swagger.v3.oas.annotations.Operation; 20 import io.swagger.v3.oas.annotations.Operation;
12 import io.swagger.v3.oas.annotations.Parameter; 21 import io.swagger.v3.oas.annotations.Parameter;
13 import io.swagger.v3.oas.annotations.tags.Tag; 22 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -19,10 +28,15 @@ import org.springframework.validation.annotation.Validated; @@ -19,10 +28,15 @@ import org.springframework.validation.annotation.Validated;
19 import org.springframework.web.bind.annotation.*; 28 import org.springframework.web.bind.annotation.*;
20 29
21 import java.io.IOException; 30 import java.io.IOException;
  31 +import java.util.Collections;
22 import java.util.List; 32 import java.util.List;
  33 +import java.util.Map;
  34 +import java.util.stream.Stream;
23 35
24 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 36 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
25 import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; 37 import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
  38 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
  39 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
26 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; 40 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
27 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 41 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
28 42
@@ -34,6 +48,13 @@ public class CrmClueController { @@ -34,6 +48,13 @@ public class CrmClueController {
34 48
35 @Resource 49 @Resource
36 private CrmClueService clueService; 50 private CrmClueService clueService;
  51 + @Resource
  52 + private CrmCustomerService customerService;
  53 +
  54 + @Resource
  55 + private AdminUserApi adminUserApi;
  56 + @Resource
  57 + private DeptApi deptApi;
37 58
38 @PostMapping("/create") 59 @PostMapping("/create")
39 @Operation(summary = "创建线索") 60 @Operation(summary = "创建线索")
@@ -73,7 +94,7 @@ public class CrmClueController { @@ -73,7 +94,7 @@ public class CrmClueController {
73 @PreAuthorize("@ss.hasPermission('crm:clue:query')") 94 @PreAuthorize("@ss.hasPermission('crm:clue:query')")
74 public CommonResult<PageResult<CrmClueRespVO>> getCluePage(@Valid CrmCluePageReqVO pageVO) { 95 public CommonResult<PageResult<CrmClueRespVO>> getCluePage(@Valid CrmCluePageReqVO pageVO) {
75 PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO, getLoginUserId()); 96 PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO, getLoginUserId());
76 - return success(BeanUtils.toBean(pageResult, CrmClueRespVO.class)); 97 + return success(new PageResult<>(buildClueDetailList(pageResult.getList()), pageResult.getTotal()));
77 } 98 }
78 99
79 @GetMapping("/export-excel") 100 @GetMapping("/export-excel")
@@ -84,8 +105,32 @@ public class CrmClueController { @@ -84,8 +105,32 @@ public class CrmClueController {
84 pageReqVO.setPageSize(PAGE_SIZE_NONE); 105 pageReqVO.setPageSize(PAGE_SIZE_NONE);
85 List<CrmClueDO> list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList(); 106 List<CrmClueDO> list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList();
86 // 导出 Excel 107 // 导出 Excel
87 - List<CrmClueRespVO> datas = BeanUtils.toBean(list, CrmClueRespVO.class);  
88 - ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, datas); 108 + ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, buildClueDetailList(list));
  109 + }
  110 +
  111 + private List<CrmClueRespVO> buildClueDetailList(List<CrmClueDO> list) {
  112 + if (CollUtil.isEmpty(list)) {
  113 + return Collections.emptyList();
  114 + }
  115 + // 1.1 获取客户列表
  116 + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
  117 + convertSet(list, CrmClueDO::getCustomerId));
  118 + // 1.2 获取创建人、负责人列表
  119 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(list,
  120 + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
  121 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  122 + // 2. 转换成 VO
  123 + return BeanUtils.toBean(list, CrmClueRespVO.class, clueVO -> {
  124 + // 2.1 设置客户名称
  125 + MapUtils.findAndThen(customerMap, clueVO.getCustomerId(), customer -> clueVO.setCustomerName(customer.getName()));
  126 + // 2.2 设置创建人、负责人名称
  127 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(clueVO.getCreator()),
  128 + user -> clueVO.setCreatorName(user.getNickname()));
  129 + MapUtils.findAndThen(userMap, clueVO.getOwnerUserId(), user -> {
  130 + clueVO.setOwnerUserName(user.getNickname());
  131 + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> clueVO.setOwnerUserDeptName(dept.getName()));
  132 + });
  133 + });
89 } 134 }
90 135
91 @PutMapping("/transfer") 136 @PutMapping("/transfer")
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java
@@ -8,12 +8,9 @@ import com.alibaba.excel.annotation.ExcelProperty; @@ -8,12 +8,9 @@ import com.alibaba.excel.annotation.ExcelProperty;
8 import io.swagger.v3.oas.annotations.media.Schema; 8 import io.swagger.v3.oas.annotations.media.Schema;
9 import lombok.Data; 9 import lombok.Data;
10 import lombok.ToString; 10 import lombok.ToString;
11 -import org.springframework.format.annotation.DateTimeFormat;  
12 11
13 import java.time.LocalDateTime; 12 import java.time.LocalDateTime;
14 13
15 -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;  
16 -  
17 @Schema(description = "管理后台 - 线索 Response VO") 14 @Schema(description = "管理后台 - 线索 Response VO")
18 @Data 15 @Data
19 @ToString(callSuper = true) 16 @ToString(callSuper = true)
@@ -34,19 +31,25 @@ public class CrmClueRespVO { @@ -34,19 +31,25 @@ public class CrmClueRespVO {
34 private Boolean followUpStatus; 31 private Boolean followUpStatus;
35 32
36 @Schema(description = "最后跟进时间") 33 @Schema(description = "最后跟进时间")
37 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
38 @ExcelProperty("最后跟进时间") 34 @ExcelProperty("最后跟进时间")
39 private LocalDateTime contactLastTime; 35 private LocalDateTime contactLastTime;
40 36
  37 + @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗")
  38 + @ExcelProperty("最后跟进内容")
  39 + private String contactLastContent;
  40 +
41 @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") 41 @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
42 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
43 @ExcelProperty("下次联系时间") 42 @ExcelProperty("下次联系时间")
44 private LocalDateTime contactNextTime; 43 private LocalDateTime contactNextTime;
45 44
46 @Schema(description = "负责人编号") 45 @Schema(description = "负责人编号")
47 - @ExcelProperty("负责人的用户编号")  
48 - // TODO 这里需要导出成负责人的名字  
49 private Long ownerUserId; 46 private Long ownerUserId;
  47 + @Schema(description = "负责人名字", example = "25682")
  48 + @ExcelProperty("负责人名字")
  49 + private String ownerUserName;
  50 + @Schema(description = "负责人部门")
  51 + @ExcelProperty("负责人部门")
  52 + private String ownerUserDeptName;
50 53
51 @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") 54 @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
52 @ExcelProperty(value = "转化状态", converter = DictConvert.class) 55 @ExcelProperty(value = "转化状态", converter = DictConvert.class)
@@ -54,9 +57,10 @@ public class CrmClueRespVO { @@ -54,9 +57,10 @@ public class CrmClueRespVO {
54 private Boolean transformStatus; 57 private Boolean transformStatus;
55 58
56 @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "520") 59 @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "520")
57 - // TODO 这里需要导出成客户名称  
58 - @ExcelProperty("客户编号")  
59 private Long customerId; 60 private Long customerId;
  61 + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "客户名称")
  62 + @ExcelProperty("客户名称")
  63 + private String customerName;
60 64
61 @Schema(description = "手机号", example = "18000000000") 65 @Schema(description = "手机号", example = "18000000000")
62 @ExcelProperty("手机号") 66 @ExcelProperty("手机号")
@@ -109,8 +113,19 @@ public class CrmClueRespVO { @@ -109,8 +113,19 @@ public class CrmClueRespVO {
109 @ExcelProperty("备注") 113 @ExcelProperty("备注")
110 private String remark; 114 private String remark;
111 115
  116 + @Schema(description = "创建人", example = "1024")
  117 + @ExcelProperty("创建人")
  118 + private String creator;
  119 + @Schema(description = "创建人名字", example = "芋道源码")
  120 + @ExcelProperty("创建人名字")
  121 + private String creatorName;
  122 +
112 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 123 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
113 @ExcelProperty("创建时间") 124 @ExcelProperty("创建时间")
114 private LocalDateTime createTime; 125 private LocalDateTime createTime;
115 126
  127 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  128 + @ExcelProperty("更新时间")
  129 + private LocalDateTime updateTime;
  130 +
116 } 131 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
@@ -56,6 +56,7 @@ public class CrmCustomerController { @@ -56,6 +56,7 @@ public class CrmCustomerController {
56 private CrmCustomerService customerService; 56 private CrmCustomerService customerService;
57 @Resource 57 @Resource
58 private CrmCustomerPoolConfigService customerPoolConfigService; 58 private CrmCustomerPoolConfigService customerPoolConfigService;
  59 +
59 @Resource 60 @Resource
60 private DeptApi deptApi; 61 private DeptApi deptApi;
61 @Resource 62 @Resource
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java
@@ -40,10 +40,14 @@ public class CrmClueDO extends BaseDO { @@ -40,10 +40,14 @@ public class CrmClueDO extends BaseDO {
40 */ 40 */
41 private Boolean followUpStatus; 41 private Boolean followUpStatus;
42 /** 42 /**
43 - * 最后跟进时间 TODO 添加跟进记录时更新该值 43 + * 最后跟进时间
44 */ 44 */
45 private LocalDateTime contactLastTime; 45 private LocalDateTime contactLastTime;
46 /** 46 /**
  47 + * 最后跟进内容
  48 + */
  49 + private String contactLastContent;
  50 + /**
47 * 下次联系时间 51 * 下次联系时间
48 */ 52 */
49 private LocalDateTime contactNextTime; 53 private LocalDateTime contactNextTime;
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java
@@ -35,6 +35,7 @@ import org.springframework.stereotype.Service; @@ -35,6 +35,7 @@ import org.springframework.stereotype.Service;
35 import org.springframework.transaction.annotation.Transactional; 35 import org.springframework.transaction.annotation.Transactional;
36 import org.springframework.validation.annotation.Validated; 36 import org.springframework.validation.annotation.Validated;
37 37
  38 +import java.time.LocalDateTime;
38 import java.util.*; 39 import java.util.*;
39 40
40 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 41 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -81,7 +82,8 @@ public class CrmClueServiceImpl implements CrmClueService { @@ -81,7 +82,8 @@ public class CrmClueServiceImpl implements CrmClueService {
81 } 82 }
82 83
83 // 2. 插入 84 // 2. 插入
84 - CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class).setId(null); 85 + CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class)
  86 + .setContactLastTime(LocalDateTime.now());
85 clueMapper.insert(clue); 87 clueMapper.insert(clue);
86 88
87 // 3. 创建数据权限 89 // 3. 创建数据权限
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR
6 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO; 6 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
7 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
8 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; 8 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
  9 +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
9 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; 10 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
10 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO; 11 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
11 import jakarta.validation.Valid; 12 import jakarta.validation.Valid;
@@ -127,13 +128,20 @@ public interface CrmContractService { @@ -127,13 +128,20 @@ public interface CrmContractService {
127 Long getContractCountByCustomerId(Long customerId); 128 Long getContractCountByCustomerId(Long customerId);
128 129
129 /** 130 /**
130 - * 根据商机ID获取关联客户的合同数量 131 + * 根据商机编号,获取关联客户的合同数量
131 * 132 *
132 * @param businessId 商机编号 133 * @param businessId 商机编号
133 * @return 数量 134 * @return 数量
134 */ 135 */
135 Long getContractCountByBusinessId(Long businessId); 136 Long getContractCountByBusinessId(Long businessId);
136 137
  138 + /**
  139 + * 根据合同编号,获得合同的产品列表
  140 + *
  141 + * @param contactId 合同编号
  142 + * @return 产品列表
  143 + */
  144 + List<CrmContractProductDO> getContractProductListByContractId(Long contactId);
137 145
138 /** 146 /**
139 * 获得待审核合同数量 147 * 获得待审核合同数量
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java
@@ -10,6 +10,9 @@ import jakarta.validation.Valid; @@ -10,6 +10,9 @@ import jakarta.validation.Valid;
10 10
11 import java.util.Collection; 11 import java.util.Collection;
12 import java.util.List; 12 import java.util.List;
  13 +import java.util.Map;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
13 16
14 /** 17 /**
15 * 客户 Service 接口 18 * 客户 Service 接口
@@ -59,6 +62,16 @@ public interface CrmCustomerService { @@ -59,6 +62,16 @@ public interface CrmCustomerService {
59 List<CrmCustomerDO> getCustomerList(Collection<Long> ids); 62 List<CrmCustomerDO> getCustomerList(Collection<Long> ids);
60 63
61 /** 64 /**
  65 + * 获得客户 Map
  66 + *
  67 + * @param ids 客户编号数组
  68 + * @return 客户 Map
  69 + */
  70 + default Map<Long, CrmCustomerDO> getCustomerMap(Collection<Long> ids) {
  71 + return convertMap(getCustomerList(ids), CrmCustomerDO::getId);
  72 + }
  73 +
  74 + /**
62 * 获得客户分页 75 * 获得客户分页
63 * 76 *
64 * @param pageReqVO 分页查询 77 * @param pageReqVO 分页查询