diff --git a/sql/mysql/crm.sql b/sql/mysql/crm.sql index e3e2ca0a0..a33204a1e 100644 --- a/sql/mysql/crm.sql +++ b/sql/mysql/crm.sql @@ -1 +1,30 @@ SET NAMES utf8mb4; +-- `ruoyi-vue-pro`.crm_contact definition + +CREATE TABLE `crm_contact` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '联系人名称', + `next_time` datetime DEFAULT NULL COMMENT '下次联系时间', + `mobile` varchar(16) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号', + `telephone` varchar(16) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电话', + `email` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电子邮箱', + `post` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '职务', + `customer_id` bigint(20) DEFAULT NULL COMMENT '客户编号', + `address` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地址', + `remark` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注', + `creator` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建人', + `owner_user_id` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '负责人用户编号', + `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间', + `last_time` timestamp NULL DEFAULT NULL COMMENT '最后跟进时间', + `updater` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '更新人', + `deleted` bit(1) NOT NULL DEFAULT b'0', + `tenant_id` bigint(20) DEFAULT NULL, + `parent_id` bigint(20) DEFAULT NULL COMMENT '直系上属', + `qq` int(11) DEFAULT NULL, + `wechat` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `sex` int(11) DEFAULT NULL COMMENT '性别', + `master` bit(1) DEFAULT NULL COMMENT '是否关键决策人', + `area_id` bigint(20) DEFAULT NULL COMMENT '地区', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 联系人'; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/contact/ContactConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/contact/ContactConstants.java new file mode 100644 index 000000000..a0a246f34 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/contact/ContactConstants.java @@ -0,0 +1,5 @@ +package cn.iocoder.yudao.module.crm.enums.contact; + +public class ContactConstants { + public static final String MULTIPLE_SPLIT = ","; +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/ContactController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/ContactController.java index 933e46901..3031f92ef 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/ContactController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/ContactController.java @@ -7,10 +7,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.contact.vo.*; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; import cn.iocoder.yudao.module.crm.convert.contact.ContactConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.contact.ContactDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; +import cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.crm.service.contact.ContactService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -19,6 +19,7 @@ import com.google.common.collect.Lists; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -27,13 +28,14 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -42,6 +44,7 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti @RestController @RequestMapping("/crm/contact") @Validated +@Slf4j public class ContactController { @Resource @@ -83,23 +86,25 @@ public class ContactController { @PreAuthorize("@ss.hasPermission('crm:contact:query')") public CommonResult getContact(@RequestParam("id") Long id) { ContactDO contact = contactService.getContact(id); - // TODO @zyna:需要考虑 null 的情况; - ContactRespVO contactRespVO = ContactConvert.INSTANCE.convert(contact); - // TODO @zyna:可以把数据读完后,convert 统一交给 ContactConvert,让 controller 更简洁;而 convert 专门去做一些转换逻辑 + if(contact == null){ + throw exception(ErrorCodeConstants.CONTACT_NOT_EXISTS); + } + //1.获取用户名 Map userMap = adminUserApi.getUserMap(CollUtil.removeNull(Lists.newArrayList( - NumberUtil.parseLong(contact.getCreator())))); - contactRespVO.setCreatorName(Optional.ofNullable(userMap.get(NumberUtil.parseLong(contact.getCreator()))).map(AdminUserRespDTO::getNickname).orElse(null)); - contactRespVO.setCustomerName(Optional.ofNullable(crmCustomerService.getCustomer(contact.getCustomerId())).map(CrmCustomerDO::getName).orElse(null)); + NumberUtil.parseLong(contact.getCreator()),contact.getOwnerUserId()))); + //2.获取客户信息 + List crmCustomerDOList = crmCustomerService.getCustomerList(Collections.singletonList(contact.getCustomerId())); + //3.直属上级 + List contactList = contactService.getContactList(Collections.singletonList(contact.getParentId())); + ContactRespVO contactRespVO = ContactConvert.INSTANCE.convert(contact,userMap,crmCustomerDOList,contactList); return success(contactRespVO); } - - // TODO @zyna:url 使用中划线噢;然后,单词的拼写也要注意呀,AllList 是不是更好呀; - @GetMapping("/simpleAlllist") + @GetMapping("/simple-all-list") @Operation(summary = "获得联系人列表") @PreAuthorize("@ss.hasPermission('crm:contact:query')") public CommonResult> simpleAlllist() { // TODO @zyna:方法名改成,getContactList;方法命名,要动名词,get 动词;all 可以去掉,因为没条件,自然是全部 - List list = contactService.allContactList(); + List list = contactService.getContactList(); return success(ContactConvert.INSTANCE.convertAllList(list)); } @@ -108,18 +113,10 @@ public class ContactController { @PreAuthorize("@ss.hasPermission('crm:contact:query')") public CommonResult> getContactPage(@Valid ContactPageReqVO pageVO) { PageResult pageData = contactService.getContactPage(pageVO); - PageResult pageResult = ContactConvert.INSTANCE.convertPage(pageData); - // TODO @zyna:需要考虑 null 的情况; - // TODO @zyna:可以把数据读完后,convert 统一交给 ContactConvert,让 controller 更简洁;而 convert 专门去做一些转换逻辑 - //待接口实现后修改 - CrmCustomerPageReqVO reqVO = new CrmCustomerPageReqVO(); - reqVO.setPageSize(PAGE_SIZE_NONE); - List crmCustomerDOList = crmCustomerService.getCustomerPage(reqVO, getLoginUserId()).getList(); - Map crmCustomerDOMap = crmCustomerDOList.stream().collect(Collectors.toMap(CrmCustomerDO::getId, v -> v)); - pageResult.getList().forEach(item -> { - item.setCustomerName(Optional.ofNullable(crmCustomerDOMap.get(item.getCustomerId())).map(CrmCustomerDO::getName).orElse(null)); - }); - return success(pageResult); + List contactRespVOList = convertFieldValue2Name(pageData.getList()); + PageResult pageDataReturn = ContactConvert.INSTANCE.convertPage(pageData); + pageDataReturn.setList(contactRespVOList); + return success(pageDataReturn); } // TODO @zyna:可以看下新的导出写法,这里调整下 @@ -127,12 +124,30 @@ public class ContactController { @Operation(summary = "导出联系人 Excel") @PreAuthorize("@ss.hasPermission('crm:contact:export')") @OperateLog(type = EXPORT) - public void exportContactExcel(@Valid ContactExportReqVO exportReqVO, - HttpServletResponse response) throws IOException { + public void exportContactExcel(@Valid ContactPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { List list = contactService.getContactList(exportReqVO); // 导出 Excel - List datas = ContactConvert.INSTANCE.convertList02(list); - ExcelUtils.write(response, "crm联系人.xls", "数据", ContactExcelVO.class, datas); + List contactRespVOList = convertFieldValue2Name(list); + ExcelUtils.write(response, "crm联系人.xls", "数据", ContactRespVO.class, contactRespVOList); } + /** + * 翻译字段名称 + * @param contactDOList 联系人List + * @return List + */ + private List convertFieldValue2Name(List contactDOList){ + //1.获取客户列表 + List customerIdList = contactDOList.stream().map(ContactDO::getCustomerId).distinct().collect(Collectors.toList()); + List crmCustomerDOList = crmCustomerService.getCustomerList(customerIdList); + //2.获取创建人、责任人列表 + List userIdsList = contactDOList.stream().flatMap(item-> Stream.of(Long.parseLong(item.getCreator()),item.getOwnerUserId()).distinct()).collect(Collectors.toList()); + Map userMap = adminUserApi.getUserMap(userIdsList); + //3.直属上级 + List contactIdsList = contactDOList.stream().map(ContactDO::getParentId).distinct().collect(Collectors.toList()); + List contactList = contactService.getContactList(contactIdsList); + List pageResult =ContactConvert.INSTANCE.converList(contactDOList,userMap,crmCustomerDOList,contactList); + return pageResult; + } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactBaseVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactBaseVO.java index 9311ad365..99e613c23 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactBaseVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactBaseVO.java @@ -1,9 +1,18 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import org.apache.skywalking.apm.toolkit.trace.IgnoredException; import org.springframework.format.annotation.DateTimeFormat; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotNull; import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; @@ -17,57 +26,83 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Data public class ContactBaseVO { - // TODO @zyna:example 最好都写下 - // TODO @zyna:必要的字段校验,例如说 @Mobile,@Emal 等等 - - @Schema(description = "下次联系时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) - private LocalDateTime nextTime; - - @Schema(description = "手机号") - private String mobile; - - @Schema(description = "电话") - private String telephone; - - @Schema(description = "电子邮箱") - private String email; + @ExcelProperty(value = "姓名",order = 1) + @Schema(description = "姓名", example = "芋艿") + @NotNull(message = "姓名不能为空") + private String name; @Schema(description = "客户编号", example = "10795") + @ExcelIgnore private Long customerId; + @ExcelProperty(value = "性别",converter = DictConvert.class ,order = 3) + @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_SEX) + @Schema(description = "性别") + private Integer sex; + + @Schema(description = "职位") + @ExcelProperty(value = "职位",order = 3) + private String post; + + @Schema(description = "是否关键决策人") + @ExcelProperty(value = "是否关键决策人",converter = DictConvert.class,order = 3) + @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.INFRA_BOOLEAN_STRING) + private Boolean master; + + @Schema(description = "直属上级", example = "23457") + @ExcelIgnore + private Long parentId; + + + @Schema(description = "手机号",example = "1387171766") + @Mobile + @ExcelProperty(value = "手机号",order = 4) + private String mobile; + + @Schema(description = "座机",example = "021-0029922") + @Telephone + @ExcelProperty(value = "座机",order = 4) + private String telephone; + + @ExcelProperty(value = "QQ",order = 4) + @Schema(description = "QQ",example = "197272662") + private Long qq; + + @ExcelProperty(value = "微信",order = 4) + @Schema(description = "微信",example = "zzz3883") + private String wechat; + + @Schema(description = "电子邮箱",example = "1111@22.com") + @Email + @ExcelProperty(value = "邮箱",order = 4) + private String email; + + @ExcelProperty(value = "地址",order = 5) @Schema(description = "地址") private String address; + @Schema(description = "下次联系时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + @ExcelProperty(value = "下次联系时间",order = 6) + private LocalDateTime nextTime; + @Schema(description = "备注", example = "你说的对") + @ExcelProperty(value = "备注",order = 6) private String remark; @Schema(description = "最后跟进时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ExcelProperty(value = "最后跟进时间",order = 6) private LocalDateTime lastTime; - @Schema(description = "直属上级", example = "23457") - private Long parentId; - - @Schema(description = "姓名", example = "芋艿") - private String name; - - @Schema(description = "职位") - private String post; - - @Schema(description = "QQ") - private Long qq; - - @Schema(description = "微信") - private String webchat; - - @Schema(description = "性别") - private Integer sex; - - @Schema(description = "是否关键决策人") - private Boolean policyMakers; @Schema(description = "负责人用户编号", example = "14334") - private String ownerUserId; + @NotNull(message = "负责人不能为空") + @ExcelIgnore + private Long ownerUserId; + + @Schema(description = "地区编号", example = "20158") + @ExcelIgnore + private Integer areaId; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactExcelVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactExcelVO.java deleted file mode 100644 index d13db6c3e..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactExcelVO.java +++ /dev/null @@ -1,72 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; - -import com.alibaba.excel.annotation.ExcelProperty; -import lombok.Data; - -import java.time.LocalDateTime; - -// TODO @zyna:参考新的 VO 结构,把 ContactExcelVO 融合到 ContactRespVO 中 -/** - * crm联系人 Excel VO - * - * @author 芋道源码 - */ -@Data -@Deprecated -public class ContactExcelVO { - - @ExcelProperty("下次联系时间") - private LocalDateTime nextTime; - - @ExcelProperty("手机号") - private String mobile; - - @ExcelProperty("电话") - private String telephone; - - @ExcelProperty("电子邮箱") - private String email; - - @ExcelProperty("客户编号") - private Long customerId; - - @ExcelProperty("地址") - private String address; - - @ExcelProperty("备注") - private String remark; - - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @ExcelProperty("最后跟进时间") - private LocalDateTime lastTime; - - @ExcelProperty("主键") - private Long id; - - @ExcelProperty("直属上级") - private Long parentId; - - @ExcelProperty("姓名") - private String name; - - @ExcelProperty("职位") - private String post; - - @ExcelProperty("QQ") - private Long qq; - - @ExcelProperty("微信") - private String webchat; - - @ExcelProperty("性别") - private Integer sex; - - @ExcelProperty("是否关键决策人") - private Boolean policyMakers; - - @ExcelProperty("负责人用户编号") - private String ownerUserId; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactExportReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactExportReqVO.java deleted file mode 100644 index f05f6dcde..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactExportReqVO.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -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; - -// TODO @zyna:参考新的 VO 结构,使用 ContactPageReqVO 查询导出的数据 -@Schema(description = "管理后台 - crm联系人 Excel 导出 Request VO,参数和 ContactPageReqVO 是一致的") -@Data -@Deprecated -public class ContactExportReqVO { - - @Schema(description = "下次联系时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] nextTime; - - @Schema(description = "手机号") - private String mobile; - - @Schema(description = "电话") - private String telephone; - - @Schema(description = "电子邮箱") - private String email; - - @Schema(description = "客户编号", example = "10795") - private Long customerId; - - @Schema(description = "地址") - private String address; - - @Schema(description = "备注", example = "你说的对") - private String remark; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - - @Schema(description = "最后跟进时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] lastTime; - - @Schema(description = "直属上级", example = "23457") - private Long parentId; - - @Schema(description = "姓名", example = "芋艿") - private String name; - - @Schema(description = "职位") - private String post; - - @Schema(description = "QQ") - private Long qq; - - @Schema(description = "微信") - private String webchat; - - @Schema(description = "性别") - private Integer sex; - - @Schema(description = "是否关键决策人") - private Boolean policyMakers; - - @Schema(description = "负责人用户编号", example = "14334") - private String ownerUserId; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactPageReqVO.java index a20826b0a..f5ed1b275 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactPageReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactPageReqVO.java @@ -26,13 +26,13 @@ public class ContactPageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] nextTime; - @Schema(description = "手机号") + @Schema(description = "手机号",example = "13898273941") private String mobile; - @Schema(description = "电话") + @Schema(description = "电话",example = "021-383773") private String telephone; - @Schema(description = "电子邮箱") + @Schema(description = "电子邮箱",example = "111@22.com") private String email; @Schema(description = "客户编号", example = "10795") @@ -61,19 +61,19 @@ public class ContactPageReqVO extends PageParam { @Schema(description = "职位") private String post; - @Schema(description = "QQ") + @Schema(description = "QQ",example = "3882872") private Long qq; - @Schema(description = "微信") - private String webchat; + @Schema(description = "微信",example = "zzZ98373") + private String wechat; @Schema(description = "性别") private Integer sex; @Schema(description = "是否关键决策人") - private Boolean policyMakers; + private Boolean master; @Schema(description = "负责人用户编号", example = "14334") - private String ownerUserId; + private Long ownerUserId; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactRespVO.java index 5a69424dc..438a0b336 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/ContactRespVO.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.time.LocalDateTime; @@ -11,17 +13,34 @@ import java.time.LocalDateTime; public class ContactRespVO extends ContactBaseVO { @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") + @ExcelIgnore private Long id; @Schema(description = "创建时间") + @ExcelProperty(value = "创建时间",order = 8) private LocalDateTime createTime; - // TODO @zyna:example 最好写下; + @Schema(description = "创建人", example = "25682") + @ExcelIgnore + private String creator; - @Schema(description = "创建人") + @Schema(description = "创建人名字", example = "test") + @ExcelProperty(value = "创建人",order = 8) private String creatorName; - @Schema(description = "客户名字") + @ExcelProperty(value = "客户名称",order = 2) + @Schema(description = "客户名字", example = "test") private String customerName; + @Schema(description = "负责人", example = "test") + @ExcelProperty(value = "负责人",order = 7) + private String ownerUserName; + + @Schema(description = "直属上级名",example = "芋头") + @ExcelProperty(value = "直属上级",order = 4) + private String parentName; + + @Schema(description = "地区名",example = "上海上海市浦东新区") + @ExcelProperty(value = "地区",order = 5) + private String areaName; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index d86e24f7c..6881518d5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -172,5 +172,12 @@ public class CrmCustomerController { customerService.receiveCustomer(ids, ownerUserId); return success(true); } - + @GetMapping("/query-all-list") + @Operation(summary = "查询客户列表") + @PreAuthorize("@ss.hasPermission('crm:customer:all')") + public CommonResult> queryAll(){ + List crmCustomerDOList = customerService.getCustomerList(); + List data = CrmCustomerConvert.INSTANCE.convertQueryAll(crmCustomerDOList); + return success(data); + } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerQueryAllRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerQueryAllRespVO.java new file mode 100644 index 000000000..18c487997 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerQueryAllRespVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +@Schema(description = "管理后台 - CRM 全部客户 Response VO") +@Data +public class CrmCustomerQueryAllRespVO{ + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") + private Long id; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/ContactConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/ContactConvert.java index a5be7d84f..12a21dd64 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/ContactConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/ContactConvert.java @@ -1,15 +1,21 @@ package cn.iocoder.yudao.module.crm.convert.contact; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*; import cn.iocoder.yudao.module.crm.dal.dataobject.contact.ContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; - import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; /** * crm联系人 Convert @@ -31,8 +37,6 @@ public interface ContactConvert { PageResult convertPage(PageResult page); - List convertList02(List list); - List convertAllList(List list); @Mappings({ @@ -41,4 +45,46 @@ public interface ContactConvert { }) CrmPermissionTransferReqBO convert(CrmContactTransferReqVO reqVO, Long userId); + /** + * 详情信息 + * @param contactDO 联系人 + * @param userMap 用户列表 + * @param crmCustomerDOList 客户 + * @return ContactRespVO + */ + default ContactRespVO convert(ContactDO contactDO, Map userMap, List crmCustomerDOList, + List contactList) { + ContactRespVO contactRespVO = convert(contactDO); + setUserInfo(contactRespVO,userMap); + Map crmCustomerDOMap = crmCustomerDOList.stream().collect(Collectors.toMap(CrmCustomerDO::getId,v->v)); + Map contactDOMap = contactList.stream().collect(Collectors.toMap(ContactDO::getId,v->v)); + findAndThen(crmCustomerDOMap,contactDO.getCustomerId(),customer -> {contactRespVO.setCustomerName(customer.getName());}); + findAndThen(contactDOMap,contactDO.getParentId(),contactDOInner -> {contactRespVO.setParentName(contactDOInner.getName());}); + return contactRespVO; + } + default List converList(List contactDOList, Map userMap, + List crmCustomerDOList , List contactList){ + List result = convertList(contactDOList); + Map contactMap = contactList.stream().collect(Collectors.toMap(ContactDO::getId,v->v)); + Map customerMap = crmCustomerDOList.stream().collect(Collectors.toMap(CrmCustomerDO::getId,v->v)); + result.forEach(item -> { + setUserInfo(item, userMap); + findAndThen(customerMap,item.getCustomerId(),customer -> {item.setCustomerName(customer.getName());}); + findAndThen(contactMap,item.getParentId(),contactDO -> {item.setParentName(contactDO.getName());}); + }); + return result; + } + /** + * 设置用户信息 + * + * @param contactRespVO 联系人Response VO + * @param userMap 用户信息 map + */ + static void setUserInfo(ContactRespVO contactRespVO, Map userMap){ + contactRespVO.setAreaName(AreaUtils.format(contactRespVO.getAreaId())); + findAndThen(userMap, contactRespVO.getOwnerUserId(), user -> { + contactRespVO.setOwnerUserName(user == null?"":user.getNickname()); + }); + findAndThen(userMap, Long.parseLong(contactRespVO.getCreator()), user -> contactRespVO.setCreatorName(user.getNickname())); + } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java index 2cbc587ba..d2661bfb1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java @@ -82,4 +82,6 @@ public interface CrmCustomerConvert { CrmCustomerPoolConfigDO convert(CrmCustomerPoolConfigSaveReqVO updateReqVO); + CrmCustomerQueryAllRespVO convertQueryAll(CrmCustomerDO crmCustomerDO); + List convertQueryAll(List crmCustomerDO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/ContactDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/ContactDO.java index f98da52bc..0888d615d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/ContactDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/ContactDO.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.time.LocalDateTime; @@ -22,8 +23,11 @@ import java.time.LocalDateTime; @NoArgsConstructor @AllArgsConstructor public class ContactDO extends BaseDO { - - // TODO @zyna:这个字段的顺序,是不是整理下; + /** + * 主键 + */ + @TableId + private Long id; /** * 下次联系时间 */ @@ -56,15 +60,8 @@ public class ContactDO extends BaseDO { * 最后跟进时间 */ private LocalDateTime lastTime; - // TODO @zyna:这个放在最前面吧 /** - * 主键 - */ - @TableId - private Long id; - // TODO @zyna:直接上级,最好写下它关联的字段,例如说这个,应该关联 ContactDO 的 id 字段 - /** - * 直属上级 + * 直属上级 @link ContactDO#id */ private Long parentId; /** @@ -79,25 +76,23 @@ public class ContactDO extends BaseDO { * QQ */ private Long qq; - // TODO @zyna:wechat /** * 微信 */ - private String webchat; - // TODO @zyna:关联的枚举 + private String wechat; /** * 性别 + * @See 字典配置 */ private Integer sex; - // TODO @zyna:这个字段改成 master 哈; /** * 是否关键决策人 */ - private Boolean policyMakers; - // TODO @zyna:应该是 Long + private Boolean master; /** * 负责人用户编号 */ - private String ownerUserId; + private Long ownerUserId; + private Integer areaId; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/ContactMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/ContactMapper.java index ef336c37e..9db1691cb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/ContactMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/ContactMapper.java @@ -32,14 +32,14 @@ public interface ContactMapper extends BaseMapperX { .likeIfPresent(ContactDO::getName, reqVO.getName()) .eqIfPresent(ContactDO::getPost, reqVO.getPost()) .eqIfPresent(ContactDO::getQq, reqVO.getQq()) - .eqIfPresent(ContactDO::getWebchat, reqVO.getWebchat()) + .eqIfPresent(ContactDO::getWechat, reqVO.getWechat()) .eqIfPresent(ContactDO::getSex, reqVO.getSex()) - .eqIfPresent(ContactDO::getPolicyMakers, reqVO.getPolicyMakers()) + .eqIfPresent(ContactDO::getMaster, reqVO.getMaster()) .eqIfPresent(ContactDO::getOwnerUserId, reqVO.getOwnerUserId()) .orderByDesc(ContactDO::getId)); } - default List selectList(ContactExportReqVO reqVO) { + default List selectList(ContactPageReqVO reqVO) { return selectList(new LambdaQueryWrapperX() .betweenIfPresent(ContactDO::getNextTime, reqVO.getNextTime()) .eqIfPresent(ContactDO::getMobile, reqVO.getMobile()) @@ -54,9 +54,9 @@ public interface ContactMapper extends BaseMapperX { .likeIfPresent(ContactDO::getName, reqVO.getName()) .eqIfPresent(ContactDO::getPost, reqVO.getPost()) .eqIfPresent(ContactDO::getQq, reqVO.getQq()) - .eqIfPresent(ContactDO::getWebchat, reqVO.getWebchat()) + .eqIfPresent(ContactDO::getWechat, reqVO.getWechat()) .eqIfPresent(ContactDO::getSex, reqVO.getSex()) - .eqIfPresent(ContactDO::getPolicyMakers, reqVO.getPolicyMakers()) + .eqIfPresent(ContactDO::getMaster, reqVO.getMaster()) .eqIfPresent(ContactDO::getOwnerUserId, reqVO.getOwnerUserId()) .orderByDesc(ContactDO::getId)); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactService.java index c27c1541a..f1278a529 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactService.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.crm.service.contact; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactCreateReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactExportReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactUpdateReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.contact.ContactDO; @@ -71,11 +70,11 @@ public interface ContactService { * @param exportReqVO 查询条件 * @return crm联系人列表 */ - List getContactList(ContactExportReqVO exportReqVO); + List getContactList(ContactPageReqVO exportReqVO); /** * 获取所有联系人列表,只返回姓名和id * @return 所有联系人列表 */ - List allContactList(); + List getContactList(); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactServiceImpl.java index 279bbc568..95f3131e2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactServiceImpl.java @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactCreateReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactExportReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.ContactUpdateReqVO; import cn.iocoder.yudao.module.crm.convert.contact.ContactConvert; @@ -57,7 +56,7 @@ public class ContactServiceImpl implements ContactService { @Override @Transactional(rollbackFor = Exception.class) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS, level = CrmPermissionLevelEnum.WRITE) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS,bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) public void updateContact(ContactUpdateReqVO updateReqVO) { // 校验存在 validateContactExists(updateReqVO.getId()); @@ -68,7 +67,7 @@ public class ContactServiceImpl implements ContactService { @Override @Transactional(rollbackFor = Exception.class) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS, level = CrmPermissionLevelEnum.WRITE) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS,bizId = "#id", level = CrmPermissionLevelEnum.WRITE) public void deleteContact(Long id) { // 校验存在 validateContactExists(id); @@ -83,7 +82,7 @@ public class ContactServiceImpl implements ContactService { } @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS, level = CrmPermissionLevelEnum.READ) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS,bizId = "#id", level = CrmPermissionLevelEnum.READ) public ContactDO getContact(Long id) { return contactMapper.selectById(id); } @@ -102,13 +101,12 @@ public class ContactServiceImpl implements ContactService { } @Override - public List getContactList(ContactExportReqVO exportReqVO) { + public List getContactList(ContactPageReqVO exportReqVO) { return contactMapper.selectList(exportReqVO); } @Override - public List allContactList() { + public List getContactList() { return contactMapper.selectList(); } - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java index 8f745ba78..1834f9031 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java @@ -107,4 +107,10 @@ public interface CrmCustomerService { */ void receiveCustomer(List ids, Long ownerUserId); + /** + * 获取客户列表 + * @return 客户列表 + * @author zyna + */ + List getCustomerList(); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java index 4f1e1c367..7d4f27ad0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java @@ -228,4 +228,57 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { } } + // TODO @puhui999:合并到 receiveCustomer 里 + @Override + @Transactional(rollbackFor = Exception.class) + public void receive(Long id, Long userId) { + // 1. 校验存在 + CrmCustomerDO customer = customerMapper.selectById(id); + if (customer == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + // 1.2. 校验是否为公海数据 + if (customer.getOwnerUserId() != null) { + throw exception(CUSTOMER_NOT_IN_POOL); + } + + // 2. 领取公海数据-设置负责人 + customerMapper.updateById(new CrmCustomerDO().setId(customer.getId()).setOwnerUserId(userId)); + // 3. 创建负责人数据权限 + crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) + .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 + } + + @Override + @Transactional(rollbackFor = Exception.class) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) + public void putCustomerPool(Long id) { + // 1. 校验存在 + CrmCustomerDO customer = customerMapper.selectById(id); + if (customer == null) { + throw exception(CUSTOMER_NOT_EXISTS); + } + // TODO puhui999:校验合并到 validateCustomerOwnerExists、validateCustomerIsLocked + // 1.2. 校验是否为公海数据 + if (customer.getOwnerUserId() == null) { + throw exception(CUSTOMER_IN_POOL); + } + // 1.3. 校验客户是否锁定 + if (customer.getLockStatus()) { + throw exception(CUSTOMER_LOCKED_PUT_POOL_FAIL); + } + + // 2. 设置负责人为 NULL + // TODO @puhui999:updateById 这么操作,是无法设置 null 的; + customerMapper.updateById(new CrmCustomerDO().setId(customer.getId()).setOwnerUserId(null)); + // 3. 删除负责人数据权限 + crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(), + CrmPermissionLevelEnum.OWNER.getLevel()); + } + + @Override + public List getCustomerList() { + return customerMapper.selectList(); + } + } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java index c0e342383..7a78f18f3 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java @@ -26,4 +26,6 @@ public interface DictTypeConstants { String SMS_SEND_STATUS = "system_sms_send_status"; // 短信发送状态 String SMS_RECEIVE_STATUS = "system_sms_receive_status"; // 短信接收状态 + String INFRA_BOOLEAN_STRING = "infra_boolean_string"; // boolean字典 + }