Procházet zdrojové kódy

feat: crm 线索表完善 review 提到的问题

913752709@qq.com před 1 rokem
rodič
revize
e4eeaa1d69

+ 20 - 20
sql/mysql/crm.sql

@@ -41,23 +41,23 @@ CREATE TABLE `crm_contract`
 
 DROP TABLE IF EXISTS `crm_clue`;
 CREATE TABLE `crm_clue`  (
-     `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号,主键自增',
-     `transform_status` tinyint NOT NULL COMMENT '转化状态',
-     `follow_up_status` tinyint NOT NULL COMMENT '跟进状态',
-     `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '线索名称',
-     `customer_id` bigint NOT NULL COMMENT '客户id',
-     `contact_next_time` datetime NULL DEFAULT NULL COMMENT '下次联系时间',
-     `telephone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '电话',
-     `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '手机号',
-     `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '地址',
-     `owner_user_id` bigint NULL DEFAULT NULL COMMENT '负责人的用户编号',
-     `contact_last_time` datetime NULL DEFAULT NULL COMMENT '最后跟进时间',
-     `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
-     `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
-     `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-     `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
-     `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-     `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
-     `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
-     PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '线索表' ROW_FORMAT = Dynamic;
+    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号,主键自增',
+    `transform_status` tinyint DEFAULT NULL COMMENT '转化状态',
+    `follow_up_status` tinyint DEFAULT NULL COMMENT '跟进状态',
+    `name` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '线索名称',
+    `customer_id` bigint NOT NULL COMMENT '客户id',
+    `contact_next_time` datetime DEFAULT NULL COMMENT '下次联系时间',
+    `telephone` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电话',
+    `mobile` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号',
+    `address` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地址',
+    `owner_user_id` bigint NOT NULL COMMENT '负责人的用户编号',
+    `contact_last_time` datetime DEFAULT NULL COMMENT '最后跟进时间',
+    `remark` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
+    `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
+    `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
+    `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+    `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT = '线索表' ;

+ 28 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/Telephone.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.framework.common.validation;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+@Target({
+        ElementType.METHOD,
+        ElementType.FIELD,
+        ElementType.ANNOTATION_TYPE,
+        ElementType.CONSTRUCTOR,
+        ElementType.PARAMETER,
+        ElementType.TYPE_USE
+})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(
+        validatedBy = TelephoneValidator.class
+)
+public @interface Telephone {
+
+    String message() default "电话格式不正确";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+
+}

+ 25 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/TelephoneValidator.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.framework.common.validation;
+
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.PhoneUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class TelephoneValidator implements ConstraintValidator<Telephone, String> {
+
+    @Override
+    public void initialize(Telephone annotation) {
+    }
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext context) {
+        // 如果手机号为空,默认不校验,即校验通过
+        if (CharSequenceUtil.isEmpty(value)) {
+            return true;
+        }
+        // 校验手机
+        return PhoneUtil.isTel(value) || PhoneUtil.isPhone(value);
+    }
+
+}

+ 2 - 2
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java

@@ -12,7 +12,7 @@ public interface ErrorCodeConstants {
     // ========== 合同管理 1-020-000-000 ==========
     ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
 
-    // TODO @wanwan:要单独一个分段噢
-    ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_000_001, "线索不存在");
+    // ========== 线索管理 1-020-001-000 ==========
+    ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在");
 
 }

+ 8 - 19
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueBaseVO.java

@@ -1,10 +1,12 @@
 package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
 
 import cn.iocoder.yudao.framework.common.validation.Mobile;
+import cn.iocoder.yudao.framework.common.validation.Telephone;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
 
@@ -17,44 +19,31 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @Data
 public class CrmClueBaseVO {
 
-    // TODO @wanwan:转化状态,新增和修改的时候,应该不传递的哈;而是在未来的时候,才会更新到
-    @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
-    @NotNull(message = "转化状态不能为空")
-    private Boolean transformStatus;
-
-    // TODO @wanwan:同 transformStatus
-    @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
-    @NotNull(message = "跟进状态不能为空")
-    private Boolean followUpStatus;
-
     @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx")
-    @NotNull(message = "线索名称不能为空") // TODO @wanwan:应该是 NotEmpty 噢。空串都无法接受
+    @NotEmpty(message = "线索名称不能为空")
     private String name;
 
-    // TODO @wanwan:中英文之间,要有个空格;例如说,客户 id 不能为空
-    @Schema(description = "客户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "520")
-    @NotNull(message = "客户id不能为空")
+    @Schema(description = "客户 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "520")
+    @NotNull(message = "客户不能为空")
     private Long customerId;
 
     @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime contactNextTime;
 
-    // TODO @wanwan:@Schema 在 @Mobile 之前,要保持统一的顺序;2)可以加个 @Telephone 的校验格式;应该不是手机的格式哈
-    @Mobile(message = "电话格式不正确")
     @Schema(description = "电话", example = "18000000000")
+    @Telephone
     private String telephone;
 
-    // TODO @wanwan:@Schema 在 @Mobile 之前,要保持统一的顺序;2)类似 @Mobile 这个提示如果是默认的,就可以不写 message
-    @Mobile(message = "手机号格式不正确")
     @Schema(description = "手机号", example = "18000000000")
+    @Mobile
     private String mobile;
 
     @Schema(description = "地址", example = "北京市海淀区")
     private String address;
 
     @Schema(description = "负责人的用户编号", example = "27199")
-    // TODO @wanwan:这个是必填字段哈;
+    @NotNull(message = "负责人不能为空")
     private Long ownerUserId;
 
     @Schema(description = "最后跟进时间")

+ 5 - 4
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueExcelVO.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
 
+import cn.iocoder.yudao.module.infra.enums.DictTypeConstants;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.util.*;
@@ -12,7 +13,6 @@ import com.alibaba.excel.annotation.ExcelProperty;
 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
 
-
 /**
  * 线索 Excel VO
  *
@@ -21,20 +21,21 @@ import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
 @Data
 public class CrmClueExcelVO {
 
-    @ExcelProperty("编号,主键自增")
+    @ExcelProperty("编号")
     private Long id;
 
     @ExcelProperty(value = "转化状态", converter = DictConvert.class)
-    @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
+    @DictFormat(DictTypeConstants.BOOLEAN_STRING)
     private Boolean transformStatus;
 
     @ExcelProperty(value = "跟进状态", converter = DictConvert.class)
-    @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
+    @DictFormat(DictTypeConstants.BOOLEAN_STRING)
     private Boolean followUpStatus;
 
     @ExcelProperty("线索名称")
     private String name;
 
+    // TODO 这里需要导出成客户名称
     @ExcelProperty("客户id")
     private Long customerId;
 

+ 0 - 36
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java

@@ -5,54 +5,18 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 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 = "管理后台 - 线索分页 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
 public class CrmCluePageReqVO extends PageParam {
-
-    // TODO @wanwan:目前只要支持 name、mobile、telephone 的搜索即可;其它字段应该暂时不需要哈;
-
-    @Schema(description = "转化状态", example = "true")
-    private Boolean transformStatus;
-
-    @Schema(description = "跟进状态", example = "true")
-    private Boolean followUpStatus;
-
     @Schema(description = "线索名称", example = "线索xxx")
     private String name;
 
-    @Schema(description = "客户id", example = "520")
-    private Long customerId;
-
-    @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] contactNextTime;
-
     @Schema(description = "电话", example = "18000000000")
     private String telephone;
 
     @Schema(description = "手机号", example = "18000000000")
     private String mobile;
-
-    @Schema(description = "地址", example = "北京市海淀区")
-    private String address;
-
-    @Schema(description = "负责人的用户编号", example = "27199")
-    private Long ownerUserId;
-
-    @Schema(description = "最后跟进时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] contactLastTime;
-
-    @Schema(description = "创建时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
 }

+ 8 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java

@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
+
+import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
 
 @Schema(description = "管理后台 - 线索 Response VO")
@@ -16,4 +18,10 @@ public class CrmClueRespVO extends CrmClueBaseVO {
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime createTime;
 
+    @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private Boolean transformStatus;
+
+    @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private Boolean followUpStatus;
+
 }

+ 0 - 8
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java

@@ -19,17 +19,9 @@ public interface CrmClueMapper extends BaseMapperX<CrmClueDO> {
 
     default PageResult<CrmClueDO> selectPage(CrmCluePageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<CrmClueDO>()
-                .eqIfPresent(CrmClueDO::getTransformStatus, reqVO.getTransformStatus())
-                .eqIfPresent(CrmClueDO::getFollowUpStatus, reqVO.getFollowUpStatus())
                 .likeIfPresent(CrmClueDO::getName, reqVO.getName())
-                .eqIfPresent(CrmClueDO::getCustomerId, reqVO.getCustomerId())
-                .betweenIfPresent(CrmClueDO::getContactNextTime, reqVO.getContactNextTime())
                 .likeIfPresent(CrmClueDO::getTelephone, reqVO.getTelephone())
                 .likeIfPresent(CrmClueDO::getMobile, reqVO.getMobile())
-                .likeIfPresent(CrmClueDO::getAddress, reqVO.getAddress())
-                .eqIfPresent(CrmClueDO::getOwnerUserId, reqVO.getOwnerUserId())
-                .betweenIfPresent(CrmClueDO::getContactLastTime, reqVO.getContactLastTime())
-                .betweenIfPresent(CrmClueDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(CrmClueDO::getId));
     }