Browse Source

📖 CRM:线索 clue 列表的完善

YunaiV 1 year ago
parent
commit
49bc70ed82

+ 48 - 3
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java

@@ -1,13 +1,22 @@
 package cn.iocoder.yudao.module.crm.controller.admin.clue;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
 import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
 import cn.iocoder.yudao.module.crm.service.clue.CrmClueService;
+import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -19,10 +28,15 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
@@ -34,6 +48,13 @@ public class CrmClueController {
 
     @Resource
     private CrmClueService clueService;
+    @Resource
+    private CrmCustomerService customerService;
+
+    @Resource
+    private AdminUserApi adminUserApi;
+    @Resource
+    private DeptApi deptApi;
 
     @PostMapping("/create")
     @Operation(summary = "创建线索")
@@ -73,7 +94,7 @@ public class CrmClueController {
     @PreAuthorize("@ss.hasPermission('crm:clue:query')")
     public CommonResult<PageResult<CrmClueRespVO>> getCluePage(@Valid CrmCluePageReqVO pageVO) {
         PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO, getLoginUserId());
-        return success(BeanUtils.toBean(pageResult, CrmClueRespVO.class));
+        return success(new PageResult<>(buildClueDetailList(pageResult.getList()), pageResult.getTotal()));
     }
 
     @GetMapping("/export-excel")
@@ -84,8 +105,32 @@ public class CrmClueController {
         pageReqVO.setPageSize(PAGE_SIZE_NONE);
         List<CrmClueDO> list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList();
         // 导出 Excel
-        List<CrmClueRespVO> datas = BeanUtils.toBean(list, CrmClueRespVO.class);
-        ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, datas);
+        ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, buildClueDetailList(list));
+    }
+
+    private List<CrmClueRespVO> buildClueDetailList(List<CrmClueDO> list) {
+        if (CollUtil.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        // 1.1 获取客户列表
+        Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
+                convertSet(list, CrmClueDO::getCustomerId));
+        // 1.2 获取创建人、负责人列表
+        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(list,
+                contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
+        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
+        // 2. 转换成 VO
+        return BeanUtils.toBean(list, CrmClueRespVO.class, clueVO -> {
+            // 2.1 设置客户名称
+            MapUtils.findAndThen(customerMap, clueVO.getCustomerId(), customer -> clueVO.setCustomerName(customer.getName()));
+            // 2.2 设置创建人、负责人名称
+            MapUtils.findAndThen(userMap, NumberUtils.parseLong(clueVO.getCreator()),
+                    user -> clueVO.setCreatorName(user.getNickname()));
+            MapUtils.findAndThen(userMap, clueVO.getOwnerUserId(), user -> {
+                clueVO.setOwnerUserName(user.getNickname());
+                MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> clueVO.setOwnerUserDeptName(dept.getName()));
+            });
+        });
     }
 
     @PutMapping("/transfer")

+ 24 - 9
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;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
 
 import java.time.LocalDateTime;
 
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
 @Schema(description = "管理后台 - 线索 Response VO")
 @Data
 @ToString(callSuper = true)
@@ -34,19 +31,25 @@ public class CrmClueRespVO {
     private Boolean followUpStatus;
 
     @Schema(description = "最后跟进时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     @ExcelProperty("最后跟进时间")
     private LocalDateTime contactLastTime;
 
+    @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗")
+    @ExcelProperty("最后跟进内容")
+    private String contactLastContent;
+
     @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     @ExcelProperty("下次联系时间")
     private LocalDateTime contactNextTime;
 
     @Schema(description = "负责人编号")
-    @ExcelProperty("负责人的用户编号")
-    // TODO 这里需要导出成负责人的名字
     private Long ownerUserId;
+    @Schema(description = "负责人名字", example = "25682")
+    @ExcelProperty("负责人名字")
+    private String ownerUserName;
+    @Schema(description = "负责人部门")
+    @ExcelProperty("负责人部门")
+    private String ownerUserDeptName;
 
     @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
     @ExcelProperty(value = "转化状态", converter = DictConvert.class)
@@ -54,9 +57,10 @@ public class CrmClueRespVO {
     private Boolean transformStatus;
 
     @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "520")
-    // TODO 这里需要导出成客户名称
-    @ExcelProperty("客户编号")
     private Long customerId;
+    @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "客户名称")
+    @ExcelProperty("客户名称")
+    private String customerName;
 
     @Schema(description = "手机号", example = "18000000000")
     @ExcelProperty("手机号")
@@ -109,8 +113,19 @@ public class CrmClueRespVO {
     @ExcelProperty("备注")
     private String remark;
 
+    @Schema(description = "创建人", example = "1024")
+    @ExcelProperty("创建人")
+    private String creator;
+    @Schema(description = "创建人名字", example = "芋道源码")
+    @ExcelProperty("创建人名字")
+    private String creatorName;
+
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;
 
+    @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("更新时间")
+    private LocalDateTime updateTime;
+
 }

+ 1 - 0
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 {
     private CrmCustomerService customerService;
     @Resource
     private CrmCustomerPoolConfigService customerPoolConfigService;
+
     @Resource
     private DeptApi deptApi;
     @Resource

+ 5 - 1
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java

@@ -40,9 +40,13 @@ public class CrmClueDO extends BaseDO {
      */
     private Boolean followUpStatus;
     /**
-     * 最后跟进时间 TODO 添加跟进记录时更新该值
+     * 最后跟进时间
      */
     private LocalDateTime contactLastTime;
+    /**
+     * 最后跟进内容
+     */
+    private String contactLastContent;
     /**
      * 下次联系时间
      */

+ 3 - 1
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;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.time.LocalDateTime;
 import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -81,7 +82,8 @@ public class CrmClueServiceImpl implements CrmClueService {
         }
 
         // 2. 插入
-        CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class).setId(null);
+        CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class)
+                .setContactLastTime(LocalDateTime.now());
         clueMapper.insert(clue);
 
         // 3. 创建数据权限

+ 9 - 1
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
 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
 import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
 import jakarta.validation.Valid;
@@ -127,13 +128,20 @@ public interface CrmContractService {
     Long getContractCountByCustomerId(Long customerId);
 
     /**
-     * 根据商机ID获取关联客户的合同数量
+     * 根据商机编号,获取关联客户的合同数量
      *
      * @param businessId 商机编号
      * @return 数量
      */
     Long getContractCountByBusinessId(Long businessId);
 
+    /**
+     * 根据合同编号,获得合同的产品列表
+     *
+     * @param contactId 合同编号
+     * @return 产品列表
+     */
+    List<CrmContractProductDO> getContractProductListByContractId(Long contactId);
 
     /**
      * 获得待审核合同数量

+ 13 - 0
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;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 
 /**
  * 客户 Service 接口
@@ -58,6 +61,16 @@ public interface CrmCustomerService {
      */
     List<CrmCustomerDO> getCustomerList(Collection<Long> ids);
 
+    /**
+     * 获得客户 Map
+     *
+     * @param ids 客户编号数组
+     * @return 客户 Map
+     */
+    default Map<Long, CrmCustomerDO> getCustomerMap(Collection<Long> ids) {
+        return convertMap(getCustomerList(ids), CrmCustomerDO::getId);
+    }
+
     /**
      * 获得客户分页
      *