Commit a09ee495b674411d312dce4e18b29360b6ec7e38

Authored by 913752709@qq.com
1 parent b133acd8

feat: CRM 线索表 crud

Showing 20 changed files with 1065 additions and 3 deletions
sql/mysql/crm.sql
... ... @@ -37,3 +37,27 @@ CREATE TABLE `crm_contract`
37 37 ) ENGINE = InnoDB
38 38 CHARACTER SET = utf8mb4
39 39 COLLATE = utf8mb4_unicode_ci COMMENT ='合同表';
  40 +
  41 +
  42 +DROP TABLE IF EXISTS `crm_clue`;
  43 +CREATE TABLE `crm_clue` (
  44 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号,主键自增',
  45 + `transform_status` tinyint NOT NULL COMMENT '转化状态',
  46 + `follow_up_status` tinyint NOT NULL COMMENT '跟进状态',
  47 + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '线索名称',
  48 + `customer_id` bigint NOT NULL COMMENT '客户id',
  49 + `contact_next_time` datetime NULL DEFAULT NULL COMMENT '下次联系时间',
  50 + `telephone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '电话',
  51 + `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '手机号',
  52 + `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '地址',
  53 + `owner_user_id` bigint NULL DEFAULT NULL COMMENT '负责人的用户编号',
  54 + `contact_last_time` datetime NULL DEFAULT NULL COMMENT '最后跟进时间',
  55 + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
  56 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  57 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  58 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  59 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  60 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  61 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  62 + PRIMARY KEY (`id`) USING BTREE
  63 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '线索表' ROW_FORMAT = Dynamic;
40 64 \ No newline at end of file
... ...
sql/mysql/crm_menu.sql
... ... @@ -59,5 +59,61 @@ VALUES (
59 59 );
60 60  
61 61 -- ----------------------------
62   --- ...菜单
63   --- ----------------------------
64 62 \ No newline at end of file
  63 +-- 线索菜单
  64 +-- ----------------------------
  65 +
  66 +-- 菜单 SQL
  67 +INSERT INTO system_menu(
  68 + name, permission, type, sort, parent_id,
  69 + path, icon, component, status, component_name
  70 +)
  71 +VALUES (
  72 + '线索管理', '', 2, 0, 2375,
  73 + 'clue', '', 'crm/clue/index', 0, 'CrmClue'
  74 +);
  75 +
  76 +-- 按钮父菜单ID
  77 +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
  78 +SELECT @parentId := LAST_INSERT_ID();
  79 +
  80 +-- 按钮 SQL
  81 +INSERT INTO system_menu(
  82 + name, permission, type, sort, parent_id,
  83 + path, icon, component, status
  84 +)
  85 +VALUES (
  86 + '线索查询', 'crm:clue:query', 3, 1, @parentId,
  87 + '', '', '', 0
  88 +);
  89 +INSERT INTO system_menu(
  90 + name, permission, type, sort, parent_id,
  91 + path, icon, component, status
  92 +)
  93 +VALUES (
  94 + '线索创建', 'crm:clue:create', 3, 2, @parentId,
  95 + '', '', '', 0
  96 +);
  97 +INSERT INTO system_menu(
  98 + name, permission, type, sort, parent_id,
  99 + path, icon, component, status
  100 +)
  101 +VALUES (
  102 + '线索更新', 'crm:clue:update', 3, 3, @parentId,
  103 + '', '', '', 0
  104 +);
  105 +INSERT INTO system_menu(
  106 + name, permission, type, sort, parent_id,
  107 + path, icon, component, status
  108 +)
  109 +VALUES (
  110 + '线索删除', 'crm:clue:delete', 3, 4, @parentId,
  111 + '', '', '', 0
  112 +);
  113 +INSERT INTO system_menu(
  114 + name, permission, type, sort, parent_id,
  115 + path, icon, component, status
  116 +)
  117 +VALUES (
  118 + '线索导出', 'crm:clue:export', 3, 5, @parentId,
  119 + '', '', '', 0
  120 +);
... ...
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
... ... @@ -12,4 +12,6 @@ public interface ErrorCodeConstants {
12 12 // ========== 合同管理 1-020-000-000 ==========
13 13 ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
14 14  
  15 + ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_000_001, "线索不存在");
  16 +
15 17 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.security.access.prepost.PreAuthorize;
  7 +import io.swagger.v3.oas.annotations.tags.Tag;
  8 +import io.swagger.v3.oas.annotations.Parameter;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +
  11 +import javax.validation.constraints.*;
  12 +import javax.validation.*;
  13 +import javax.servlet.http.*;
  14 +import java.util.*;
  15 +import java.io.IOException;
  16 +
  17 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  18 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +
  21 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  22 +
  23 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  24 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  25 +
  26 +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
  27 +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
  28 +import cn.iocoder.yudao.module.crm.convert.clue.CrmClueConvert;
  29 +import cn.iocoder.yudao.module.crm.service.clue.CrmClueService;
  30 +
  31 +@Tag(name = "管理后台 - 线索")
  32 +@RestController
  33 +@RequestMapping("/crm/clue")
  34 +@Validated
  35 +public class CrmClueController {
  36 +
  37 + @Resource
  38 + private CrmClueService clueService;
  39 +
  40 + @PostMapping("/create")
  41 + @Operation(summary = "创建线索")
  42 + @PreAuthorize("@ss.hasPermission('crm:clue:create')")
  43 + public CommonResult<Long> createClue(@Valid @RequestBody CrmClueCreateReqVO createReqVO) {
  44 + return success(clueService.createClue(createReqVO));
  45 + }
  46 +
  47 + @PutMapping("/update")
  48 + @Operation(summary = "更新线索")
  49 + @PreAuthorize("@ss.hasPermission('crm:clue:update')")
  50 + public CommonResult<Boolean> updateClue(@Valid @RequestBody CrmClueUpdateReqVO updateReqVO) {
  51 + clueService.updateClue(updateReqVO);
  52 + return success(true);
  53 + }
  54 +
  55 + @DeleteMapping("/delete")
  56 + @Operation(summary = "删除线索")
  57 + @Parameter(name = "id", description = "编号", required = true)
  58 + @PreAuthorize("@ss.hasPermission('crm:clue:delete')")
  59 + public CommonResult<Boolean> deleteClue(@RequestParam("id") Long id) {
  60 + clueService.deleteClue(id);
  61 + return success(true);
  62 + }
  63 +
  64 + @GetMapping("/get")
  65 + @Operation(summary = "获得线索")
  66 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  67 + @PreAuthorize("@ss.hasPermission('crm:clue:query')")
  68 + public CommonResult<CrmClueRespVO> getClue(@RequestParam("id") Long id) {
  69 + CrmClueDO clue = clueService.getClue(id);
  70 + return success(CrmClueConvert.INSTANCE.convert(clue));
  71 + }
  72 +
  73 + @GetMapping("/list")
  74 + @Operation(summary = "获得线索列表")
  75 + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
  76 + @PreAuthorize("@ss.hasPermission('crm:clue:query')")
  77 + public CommonResult<List<CrmClueRespVO>> getClueList(@RequestParam("ids") Collection<Long> ids) {
  78 + List<CrmClueDO> list = clueService.getClueList(ids);
  79 + return success(CrmClueConvert.INSTANCE.convertList(list));
  80 + }
  81 +
  82 + @GetMapping("/page")
  83 + @Operation(summary = "获得线索分页")
  84 + @PreAuthorize("@ss.hasPermission('crm:clue:query')")
  85 + public CommonResult<PageResult<CrmClueRespVO>> getCluePage(@Valid CrmCluePageReqVO pageVO) {
  86 + PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO);
  87 + return success(CrmClueConvert.INSTANCE.convertPage(pageResult));
  88 + }
  89 +
  90 + @GetMapping("/export-excel")
  91 + @Operation(summary = "导出线索 Excel")
  92 + @PreAuthorize("@ss.hasPermission('crm:clue:export')")
  93 + @OperateLog(type = EXPORT)
  94 + public void exportClueExcel(@Valid CrmClueExportReqVO exportReqVO,
  95 + HttpServletResponse response) throws IOException {
  96 + List<CrmClueDO> list = clueService.getClueList(exportReqVO);
  97 + // 导出 Excel
  98 + List<CrmClueExcelVO> datas = CrmClueConvert.INSTANCE.convertList02(list);
  99 + ExcelUtils.write(response, "线索.xls", "数据", CrmClueExcelVO.class, datas);
  100 + }
  101 +
  102 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueBaseVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.Mobile;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.*;
  6 +import java.util.*;
  7 +import java.time.LocalDateTime;
  8 +import java.time.LocalDateTime;
  9 +import java.time.LocalDateTime;
  10 +import java.time.LocalDateTime;
  11 +import javax.validation.constraints.*;
  12 +import org.springframework.format.annotation.DateTimeFormat;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  15 +
  16 +/**
  17 + * 线索 Base VO,提供给添加、修改、详细的子 VO 使用
  18 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  19 + */
  20 +@Data
  21 +public class CrmClueBaseVO {
  22 +
  23 + @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  24 + @NotNull(message = "转化状态不能为空")
  25 + private Boolean transformStatus;
  26 +
  27 + @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  28 + @NotNull(message = "跟进状态不能为空")
  29 + private Boolean followUpStatus;
  30 +
  31 + @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx")
  32 + @NotNull(message = "线索名称不能为空")
  33 + private String name;
  34 +
  35 + @Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "520")
  36 + @NotNull(message = "客户id不能为空")
  37 + private Long customerId;
  38 +
  39 + @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
  40 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  41 + private LocalDateTime contactNextTime;
  42 +
  43 + @Mobile(message = "电话格式不正确")
  44 + @Schema(description = "电话", example = "18000000000")
  45 + private String telephone;
  46 +
  47 + @Mobile(message = "手机号格式不正确")
  48 + @Schema(description = "手机号", example = "18000000000")
  49 + private String mobile;
  50 +
  51 + @Schema(description = "地址", example = "北京市海淀区")
  52 + private String address;
  53 +
  54 + @Schema(description = "负责人的用户编号", example = "27199")
  55 + private Long ownerUserId;
  56 +
  57 + @Schema(description = "最后跟进时间")
  58 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  59 + private LocalDateTime contactLastTime;
  60 +
  61 + @Schema(description = "备注", example = "随便")
  62 + private String remark;
  63 +
  64 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import javax.validation.constraints.*;
  7 +
  8 +@Schema(description = "管理后台 - 线索创建 Request VO")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +public class CrmClueCreateReqVO extends CrmClueBaseVO {
  13 +
  14 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueExcelVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import java.time.LocalDateTime;
  7 +import java.time.LocalDateTime;
  8 +import java.time.LocalDateTime;
  9 +import java.time.LocalDateTime;
  10 +
  11 +import com.alibaba.excel.annotation.ExcelProperty;
  12 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  13 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  14 +
  15 +
  16 +/**
  17 + * 线索 Excel VO
  18 + *
  19 + * @author Wanwan
  20 + */
  21 +@Data
  22 +public class CrmClueExcelVO {
  23 +
  24 + @ExcelProperty("编号,主键自增")
  25 + private Long id;
  26 +
  27 + @ExcelProperty(value = "转化状态", converter = DictConvert.class)
  28 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
  29 + private Boolean transformStatus;
  30 +
  31 + @ExcelProperty(value = "跟进状态", converter = DictConvert.class)
  32 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
  33 + private Boolean followUpStatus;
  34 +
  35 + @ExcelProperty("线索名称")
  36 + private String name;
  37 +
  38 + @ExcelProperty("客户id")
  39 + private Long customerId;
  40 +
  41 + @ExcelProperty("下次联系时间")
  42 + private LocalDateTime contactNextTime;
  43 +
  44 + @ExcelProperty("电话")
  45 + private String telephone;
  46 +
  47 + @ExcelProperty("手机号")
  48 + private String mobile;
  49 +
  50 + @ExcelProperty("地址")
  51 + private String address;
  52 +
  53 + @ExcelProperty("负责人的用户编号")
  54 + private Long ownerUserId;
  55 +
  56 + @ExcelProperty("最后跟进时间")
  57 + private LocalDateTime contactLastTime;
  58 +
  59 + @ExcelProperty("备注")
  60 + private String remark;
  61 +
  62 + @ExcelProperty("创建时间")
  63 + private LocalDateTime createTime;
  64 +
  65 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueExportReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import java.time.LocalDateTime;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 线索 Excel 导出 Request VO,参数和 CrmCluePageReqVO 是一致的")
  13 +@Data
  14 +public class CrmClueExportReqVO {
  15 +
  16 + @Schema(description = "转化状态", example = "true")
  17 + private Boolean transformStatus;
  18 +
  19 + @Schema(description = "跟进状态", example = "true")
  20 + private Boolean followUpStatus;
  21 +
  22 + @Schema(description = "线索名称", example = "线索xxx")
  23 + private String name;
  24 +
  25 + @Schema(description = "客户id", example = "520")
  26 + private Long customerId;
  27 +
  28 + @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private LocalDateTime[] contactNextTime;
  31 +
  32 + @Schema(description = "电话", example = "18000000000")
  33 + private String telephone;
  34 +
  35 + @Schema(description = "手机号", example = "18000000000")
  36 + private String mobile;
  37 +
  38 + @Schema(description = "地址", example = "北京市海淀区")
  39 + private String address;
  40 +
  41 + @Schema(description = "负责人的用户编号", example = "27199")
  42 + private Long ownerUserId;
  43 +
  44 + @Schema(description = "最后跟进时间")
  45 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  46 + private LocalDateTime[] contactLastTime;
  47 +
  48 + @Schema(description = "创建时间")
  49 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  50 + private LocalDateTime[] createTime;
  51 +
  52 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 线索分页 Request VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class CrmCluePageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "转化状态", example = "true")
  19 + private Boolean transformStatus;
  20 +
  21 + @Schema(description = "跟进状态", example = "true")
  22 + private Boolean followUpStatus;
  23 +
  24 + @Schema(description = "线索名称", example = "线索xxx")
  25 + private String name;
  26 +
  27 + @Schema(description = "客户id", example = "520")
  28 + private Long customerId;
  29 +
  30 + @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + private LocalDateTime[] contactNextTime;
  33 +
  34 + @Schema(description = "电话", example = "18000000000")
  35 + private String telephone;
  36 +
  37 + @Schema(description = "手机号", example = "18000000000")
  38 + private String mobile;
  39 +
  40 + @Schema(description = "地址", example = "北京市海淀区")
  41 + private String address;
  42 +
  43 + @Schema(description = "负责人的用户编号", example = "27199")
  44 + private Long ownerUserId;
  45 +
  46 + @Schema(description = "最后跟进时间")
  47 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  48 + private LocalDateTime[] contactLastTime;
  49 +
  50 + @Schema(description = "创建时间")
  51 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  52 + private LocalDateTime[] createTime;
  53 +
  54 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.time.LocalDateTime;
  6 +
  7 +@Schema(description = "管理后台 - 线索 Response VO")
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@ToString(callSuper = true)
  11 +public class CrmClueRespVO extends CrmClueBaseVO {
  12 +
  13 + @Schema(description = "编号,主键自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "10969")
  14 + private Long id;
  15 +
  16 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  17 + private LocalDateTime createTime;
  18 +
  19 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +
  8 +@Schema(description = "管理后台 - 线索更新 Request VO")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +public class CrmClueUpdateReqVO extends CrmClueBaseVO {
  13 +
  14 + @Schema(description = "编号,主键自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "10969")
  15 + @NotNull(message = "编号,主键自增不能为空")
  16 + private Long id;
  17 +
  18 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/clue/CrmClueConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.convert.clue;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +
  7 +import org.mapstruct.Mapper;
  8 +import org.mapstruct.factory.Mappers;
  9 +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
  10 +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
  11 +
  12 +/**
  13 + * 线索 Convert
  14 + *
  15 + * @author Wanwan
  16 + */
  17 +@Mapper
  18 +public interface CrmClueConvert {
  19 +
  20 + CrmClueConvert INSTANCE = Mappers.getMapper(CrmClueConvert.class);
  21 +
  22 + CrmClueDO convert(CrmClueCreateReqVO bean);
  23 +
  24 + CrmClueDO convert(CrmClueUpdateReqVO bean);
  25 +
  26 + CrmClueRespVO convert(CrmClueDO bean);
  27 +
  28 + List<CrmClueRespVO> convertList(List<CrmClueDO> list);
  29 +
  30 + PageResult<CrmClueRespVO> convertPage(PageResult<CrmClueDO> page);
  31 +
  32 + List<CrmClueExcelVO> convertList02(List<CrmClueDO> list);
  33 +
  34 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.dal.dataobject.clue;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import java.time.LocalDateTime;
  8 +import java.time.LocalDateTime;
  9 +import com.baomidou.mybatisplus.annotation.*;
  10 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  11 +
  12 +/**
  13 + * 线索 DO
  14 + *
  15 + * @author Wanwan
  16 + */
  17 +@TableName("crm_clue")
  18 +@KeySequence("crm_clue_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  19 +@Data
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +@Builder
  23 +@NoArgsConstructor
  24 +@AllArgsConstructor
  25 +public class CrmClueDO extends BaseDO {
  26 +
  27 + /**
  28 + * 编号,主键自增
  29 + */
  30 + @TableId
  31 + private Long id;
  32 + /**
  33 + * 转化状态
  34 + *
  35 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  36 + */
  37 + private Boolean transformStatus;
  38 + /**
  39 + * 跟进状态
  40 + *
  41 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  42 + */
  43 + private Boolean followUpStatus;
  44 + /**
  45 + * 线索名称
  46 + */
  47 + private String name;
  48 + /**
  49 + * 客户id
  50 + */
  51 + private Long customerId;
  52 + /**
  53 + * 下次联系时间
  54 + */
  55 + private LocalDateTime contactNextTime;
  56 + /**
  57 + * 电话
  58 + */
  59 + private String telephone;
  60 + /**
  61 + * 手机号
  62 + */
  63 + private String mobile;
  64 + /**
  65 + * 地址
  66 + */
  67 + private String address;
  68 + /**
  69 + * 负责人的用户编号
  70 + */
  71 + private Long ownerUserId;
  72 + /**
  73 + * 最后跟进时间
  74 + */
  75 + private LocalDateTime contactLastTime;
  76 + /**
  77 + * 备注
  78 + */
  79 + private String remark;
  80 +
  81 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.dal.mysql.clue;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
  11 +
  12 +/**
  13 + * 线索 Mapper
  14 + *
  15 + * @author Wanwan
  16 + */
  17 +@Mapper
  18 +public interface CrmClueMapper extends BaseMapperX<CrmClueDO> {
  19 +
  20 + default PageResult<CrmClueDO> selectPage(CrmCluePageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<CrmClueDO>()
  22 + .eqIfPresent(CrmClueDO::getTransformStatus, reqVO.getTransformStatus())
  23 + .eqIfPresent(CrmClueDO::getFollowUpStatus, reqVO.getFollowUpStatus())
  24 + .likeIfPresent(CrmClueDO::getName, reqVO.getName())
  25 + .eqIfPresent(CrmClueDO::getCustomerId, reqVO.getCustomerId())
  26 + .betweenIfPresent(CrmClueDO::getContactNextTime, reqVO.getContactNextTime())
  27 + .likeIfPresent(CrmClueDO::getTelephone, reqVO.getTelephone())
  28 + .likeIfPresent(CrmClueDO::getMobile, reqVO.getMobile())
  29 + .likeIfPresent(CrmClueDO::getAddress, reqVO.getAddress())
  30 + .eqIfPresent(CrmClueDO::getOwnerUserId, reqVO.getOwnerUserId())
  31 + .betweenIfPresent(CrmClueDO::getContactLastTime, reqVO.getContactLastTime())
  32 + .betweenIfPresent(CrmClueDO::getCreateTime, reqVO.getCreateTime())
  33 + .orderByDesc(CrmClueDO::getId));
  34 + }
  35 +
  36 + default List<CrmClueDO> selectList(CrmClueExportReqVO reqVO) {
  37 + return selectList(new LambdaQueryWrapperX<CrmClueDO>()
  38 + .eqIfPresent(CrmClueDO::getTransformStatus, reqVO.getTransformStatus())
  39 + .eqIfPresent(CrmClueDO::getFollowUpStatus, reqVO.getFollowUpStatus())
  40 + .likeIfPresent(CrmClueDO::getName, reqVO.getName())
  41 + .eqIfPresent(CrmClueDO::getCustomerId, reqVO.getCustomerId())
  42 + .betweenIfPresent(CrmClueDO::getContactNextTime, reqVO.getContactNextTime())
  43 + .likeIfPresent(CrmClueDO::getTelephone, reqVO.getTelephone())
  44 + .likeIfPresent(CrmClueDO::getMobile, reqVO.getMobile())
  45 + .likeIfPresent(CrmClueDO::getAddress, reqVO.getAddress())
  46 + .eqIfPresent(CrmClueDO::getOwnerUserId, reqVO.getOwnerUserId())
  47 + .betweenIfPresent(CrmClueDO::getContactLastTime, reqVO.getContactLastTime())
  48 + .betweenIfPresent(CrmClueDO::getCreateTime, reqVO.getCreateTime())
  49 + .orderByDesc(CrmClueDO::getId));
  50 + }
  51 +
  52 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.clue;
  2 +
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
  6 +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +
  9 +/**
  10 + * 线索 Service 接口
  11 + *
  12 + * @author Wanwan
  13 + */
  14 +public interface CrmClueService {
  15 +
  16 + /**
  17 + * 创建线索
  18 + *
  19 + * @param createReqVO 创建信息
  20 + * @return 编号
  21 + */
  22 + Long createClue(@Valid CrmClueCreateReqVO createReqVO);
  23 +
  24 + /**
  25 + * 更新线索
  26 + *
  27 + * @param updateReqVO 更新信息
  28 + */
  29 + void updateClue(@Valid CrmClueUpdateReqVO updateReqVO);
  30 +
  31 + /**
  32 + * 删除线索
  33 + *
  34 + * @param id 编号
  35 + */
  36 + void deleteClue(Long id);
  37 +
  38 + /**
  39 + * 获得线索
  40 + *
  41 + * @param id 编号
  42 + * @return 线索
  43 + */
  44 + CrmClueDO getClue(Long id);
  45 +
  46 + /**
  47 + * 获得线索列表
  48 + *
  49 + * @param ids 编号
  50 + * @return 线索列表
  51 + */
  52 + List<CrmClueDO> getClueList(Collection<Long> ids);
  53 +
  54 + /**
  55 + * 获得线索分页
  56 + *
  57 + * @param pageReqVO 分页查询
  58 + * @return 线索分页
  59 + */
  60 + PageResult<CrmClueDO> getCluePage(CrmCluePageReqVO pageReqVO);
  61 +
  62 + /**
  63 + * 获得线索列表, 用于 Excel 导出
  64 + *
  65 + * @param exportReqVO 查询条件
  66 + * @return 线索列表
  67 + */
  68 + List<CrmClueDO> getClueList(CrmClueExportReqVO exportReqVO);
  69 +
  70 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.clue;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +
  7 +import java.util.*;
  8 +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
  9 +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
  10 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  11 +
  12 +import cn.iocoder.yudao.module.crm.convert.clue.CrmClueConvert;
  13 +import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
  17 +
  18 +import cn.hutool.core.collection.CollUtil;
  19 +import cn.hutool.core.collection.ListUtil;
  20 +
  21 +/**
  22 + * 线索 Service 实现类
  23 + *
  24 + * @author Wanwan
  25 + */
  26 +@Service
  27 +@Validated
  28 +public class CrmClueServiceImpl implements CrmClueService {
  29 +
  30 + @Resource
  31 + private CrmClueMapper clueMapper;
  32 +
  33 + @Override
  34 + public Long createClue(CrmClueCreateReqVO createReqVO) {
  35 + // 插入
  36 + CrmClueDO clue = CrmClueConvert.INSTANCE.convert(createReqVO);
  37 + clueMapper.insert(clue);
  38 + // 返回
  39 + return clue.getId();
  40 + }
  41 +
  42 + @Override
  43 + public void updateClue(CrmClueUpdateReqVO updateReqVO) {
  44 + // 校验存在
  45 + validateClueExists(updateReqVO.getId());
  46 + // 更新
  47 + CrmClueDO updateObj = CrmClueConvert.INSTANCE.convert(updateReqVO);
  48 + clueMapper.updateById(updateObj);
  49 + }
  50 +
  51 + @Override
  52 + public void deleteClue(Long id) {
  53 + // 校验存在
  54 + validateClueExists(id);
  55 + // 删除
  56 + clueMapper.deleteById(id);
  57 + }
  58 +
  59 + private void validateClueExists(Long id) {
  60 + if (clueMapper.selectById(id) == null) {
  61 + throw exception(CLUE_NOT_EXISTS);
  62 + }
  63 + }
  64 +
  65 + @Override
  66 + public CrmClueDO getClue(Long id) {
  67 + return clueMapper.selectById(id);
  68 + }
  69 +
  70 + @Override
  71 + public List<CrmClueDO> getClueList(Collection<Long> ids) {
  72 + if (CollUtil.isEmpty(ids)) {
  73 + return ListUtil.empty();
  74 + }
  75 + return clueMapper.selectBatchIds(ids);
  76 + }
  77 +
  78 + @Override
  79 + public PageResult<CrmClueDO> getCluePage(CrmCluePageReqVO pageReqVO) {
  80 + return clueMapper.selectPage(pageReqVO);
  81 + }
  82 +
  83 + @Override
  84 + public List<CrmClueDO> getClueList(CrmClueExportReqVO exportReqVO) {
  85 + return clueMapper.selectList(exportReqVO);
  86 + }
  87 +
  88 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/clue/CrmClueMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
... ...
yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.clue;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.boot.test.mock.mockito.MockBean;
  6 +
  7 +import javax.annotation.Resource;
  8 +
  9 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  10 +
  11 +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*;
  12 +import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO;
  13 +import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  15 +
  16 +import javax.annotation.Resource;
  17 +import org.springframework.context.annotation.Import;
  18 +import java.util.*;
  19 +import java.time.LocalDateTime;
  20 +
  21 +import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  27 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  28 +import static org.junit.jupiter.api.Assertions.*;
  29 +import static org.mockito.Mockito.*;
  30 +
  31 +/**
  32 + * {@link CrmClueServiceImpl} 的单元测试类
  33 + *
  34 + * @author Wanwan
  35 + */
  36 +@Import(CrmClueServiceImpl.class)
  37 +public class CrmClueServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private CrmClueServiceImpl clueService;
  41 +
  42 + @Resource
  43 + private CrmClueMapper clueMapper;
  44 +
  45 + @Test
  46 + public void testCreateClue_success() {
  47 + // 准备参数
  48 + CrmClueCreateReqVO reqVO = randomPojo(CrmClueCreateReqVO.class);
  49 +
  50 + // 调用
  51 + Long clueId = clueService.createClue(reqVO);
  52 + // 断言
  53 + assertNotNull(clueId);
  54 + // 校验记录的属性是否正确
  55 + CrmClueDO clue = clueMapper.selectById(clueId);
  56 + assertPojoEquals(reqVO, clue);
  57 + }
  58 +
  59 + @Test
  60 + public void testUpdateClue_success() {
  61 + // mock 数据
  62 + CrmClueDO dbClue = randomPojo(CrmClueDO.class);
  63 + clueMapper.insert(dbClue);// @Sql: 先插入出一条存在的数据
  64 + // 准备参数
  65 + CrmClueUpdateReqVO reqVO = randomPojo(CrmClueUpdateReqVO.class, o -> {
  66 + o.setId(dbClue.getId()); // 设置更新的 ID
  67 + });
  68 +
  69 + // 调用
  70 + clueService.updateClue(reqVO);
  71 + // 校验是否更新正确
  72 + CrmClueDO clue = clueMapper.selectById(reqVO.getId()); // 获取最新的
  73 + assertPojoEquals(reqVO, clue);
  74 + }
  75 +
  76 + @Test
  77 + public void testUpdateClue_notExists() {
  78 + // 准备参数
  79 + CrmClueUpdateReqVO reqVO = randomPojo(CrmClueUpdateReqVO.class);
  80 +
  81 + // 调用, 并断言异常
  82 + assertServiceException(() -> clueService.updateClue(reqVO), CLUE_NOT_EXISTS);
  83 + }
  84 +
  85 + @Test
  86 + public void testDeleteClue_success() {
  87 + // mock 数据
  88 + CrmClueDO dbClue = randomPojo(CrmClueDO.class);
  89 + clueMapper.insert(dbClue);// @Sql: 先插入出一条存在的数据
  90 + // 准备参数
  91 + Long id = dbClue.getId();
  92 +
  93 + // 调用
  94 + clueService.deleteClue(id);
  95 + // 校验数据不存在了
  96 + assertNull(clueMapper.selectById(id));
  97 + }
  98 +
  99 + @Test
  100 + public void testDeleteClue_notExists() {
  101 + // 准备参数
  102 + Long id = randomLongId();
  103 +
  104 + // 调用, 并断言异常
  105 + assertServiceException(() -> clueService.deleteClue(id), CLUE_NOT_EXISTS);
  106 + }
  107 +
  108 + @Test
  109 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  110 + public void testGetCluePage() {
  111 + // mock 数据
  112 + CrmClueDO dbClue = randomPojo(CrmClueDO.class, o -> { // 等会查询到
  113 + o.setTransformStatus(null);
  114 + o.setFollowUpStatus(null);
  115 + o.setName(null);
  116 + o.setCustomerId(null);
  117 + o.setContactNextTime(null);
  118 + o.setTelephone(null);
  119 + o.setMobile(null);
  120 + o.setAddress(null);
  121 + o.setOwnerUserId(null);
  122 + o.setContactLastTime(null);
  123 + o.setCreateTime(null);
  124 + });
  125 + clueMapper.insert(dbClue);
  126 + // 测试 transformStatus 不匹配
  127 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setTransformStatus(null)));
  128 + // 测试 followUpStatus 不匹配
  129 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setFollowUpStatus(null)));
  130 + // 测试 name 不匹配
  131 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setName(null)));
  132 + // 测试 customerId 不匹配
  133 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setCustomerId(null)));
  134 + // 测试 contactNextTime 不匹配
  135 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setContactNextTime(null)));
  136 + // 测试 telephone 不匹配
  137 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setTelephone(null)));
  138 + // 测试 mobile 不匹配
  139 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setMobile(null)));
  140 + // 测试 address 不匹配
  141 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setAddress(null)));
  142 + // 测试 ownerUserId 不匹配
  143 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setOwnerUserId(null)));
  144 + // 测试 contactLastTime 不匹配
  145 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setContactLastTime(null)));
  146 + // 测试 createTime 不匹配
  147 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setCreateTime(null)));
  148 + // 准备参数
  149 + CrmCluePageReqVO reqVO = new CrmCluePageReqVO();
  150 + reqVO.setTransformStatus(null);
  151 + reqVO.setFollowUpStatus(null);
  152 + reqVO.setName(null);
  153 + reqVO.setCustomerId(null);
  154 + reqVO.setContactNextTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  155 + reqVO.setTelephone(null);
  156 + reqVO.setMobile(null);
  157 + reqVO.setAddress(null);
  158 + reqVO.setOwnerUserId(null);
  159 + reqVO.setContactLastTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  160 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  161 +
  162 + // 调用
  163 + PageResult<CrmClueDO> pageResult = clueService.getCluePage(reqVO);
  164 + // 断言
  165 + assertEquals(1, pageResult.getTotal());
  166 + assertEquals(1, pageResult.getList().size());
  167 + assertPojoEquals(dbClue, pageResult.getList().get(0));
  168 + }
  169 +
  170 + @Test
  171 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  172 + public void testGetClueList() {
  173 + // mock 数据
  174 + CrmClueDO dbClue = randomPojo(CrmClueDO.class, o -> { // 等会查询到
  175 + o.setTransformStatus(null);
  176 + o.setFollowUpStatus(null);
  177 + o.setName(null);
  178 + o.setCustomerId(null);
  179 + o.setContactNextTime(null);
  180 + o.setTelephone(null);
  181 + o.setMobile(null);
  182 + o.setAddress(null);
  183 + o.setOwnerUserId(null);
  184 + o.setContactLastTime(null);
  185 + o.setCreateTime(null);
  186 + });
  187 + clueMapper.insert(dbClue);
  188 + // 测试 transformStatus 不匹配
  189 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setTransformStatus(null)));
  190 + // 测试 followUpStatus 不匹配
  191 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setFollowUpStatus(null)));
  192 + // 测试 name 不匹配
  193 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setName(null)));
  194 + // 测试 customerId 不匹配
  195 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setCustomerId(null)));
  196 + // 测试 contactNextTime 不匹配
  197 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setContactNextTime(null)));
  198 + // 测试 telephone 不匹配
  199 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setTelephone(null)));
  200 + // 测试 mobile 不匹配
  201 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setMobile(null)));
  202 + // 测试 address 不匹配
  203 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setAddress(null)));
  204 + // 测试 ownerUserId 不匹配
  205 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setOwnerUserId(null)));
  206 + // 测试 contactLastTime 不匹配
  207 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setContactLastTime(null)));
  208 + // 测试 createTime 不匹配
  209 + clueMapper.insert(cloneIgnoreId(dbClue, o -> o.setCreateTime(null)));
  210 + // 准备参数
  211 + CrmClueExportReqVO reqVO = new CrmClueExportReqVO();
  212 + reqVO.setTransformStatus(null);
  213 + reqVO.setFollowUpStatus(null);
  214 + reqVO.setName(null);
  215 + reqVO.setCustomerId(null);
  216 + reqVO.setContactNextTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  217 + reqVO.setTelephone(null);
  218 + reqVO.setMobile(null);
  219 + reqVO.setAddress(null);
  220 + reqVO.setOwnerUserId(null);
  221 + reqVO.setContactLastTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  222 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  223 +
  224 + // 调用
  225 + List<CrmClueDO> list = clueService.getClueList(reqVO);
  226 + // 断言
  227 + assertEquals(1, list.size());
  228 + assertPojoEquals(dbClue, list.get(0));
  229 + }
  230 +
  231 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/test/resources/sql/clean.sql
1 1 DELETE FROM "crm_contract";
  2 +
  3 +DELETE FROM "crm_clue";
2 4 \ No newline at end of file
... ...
yudao-module-crm/yudao-module-crm-biz/src/test/resources/sql/create_tables.sql
... ... @@ -24,4 +24,26 @@ CREATE TABLE IF NOT EXISTS &quot;crm_contract&quot; (
24 24 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
25 25 "deleted" bit NOT NULL DEFAULT FALSE,
26 26 PRIMARY KEY ("id")
27   - ) COMMENT '合同表';
28 27 \ No newline at end of file
  28 +) COMMENT '合同表';
  29 +
  30 +CREATE TABLE IF NOT EXISTS "crm_clue" (
  31 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  32 + "transform_status" bit NOT NULL,
  33 + "follow_up_status" bit NOT NULL,
  34 + "name" varchar NOT NULL,
  35 + "customer_id" bigint NOT NULL,
  36 + "contact_next_time" varchar,
  37 + "telephone" varchar,
  38 + "mobile" varchar,
  39 + "address" varchar,
  40 + "owner_user_id" bigint,
  41 + "contact_last_time" varchar,
  42 + "remark" varchar,
  43 + "creator" varchar DEFAULT '',
  44 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  45 + "updater" varchar DEFAULT '',
  46 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  47 + "deleted" bit NOT NULL DEFAULT FALSE,
  48 + "tenant_id" bigint NOT NULL,
  49 + PRIMARY KEY ("id")
  50 +) COMMENT '线索表';
29 51 \ No newline at end of file
... ...