Commit 088fbb2096f4bf36c46d85e5057529e9b7bc3d93
Merge branch 'develop' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk21
Showing
251 changed files
with
5370 additions
and
5571 deletions
Too many changes.
To preserve performance only 100 of 251 files are displayed.
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
| @@ -257,11 +257,11 @@ public class CollectionUtils { | @@ -257,11 +257,11 @@ public class CollectionUtils { | ||
| 257 | return !CollectionUtil.isEmpty(from) ? from.get(0) : null; | 257 | return !CollectionUtil.isEmpty(from) ? from.get(0) : null; |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | - public static <T> T findFirst(List<T> from, Predicate<T> predicate) { | 260 | + public static <T> T findFirst(Collection<T> from, Predicate<T> predicate) { |
| 261 | return findFirst(from, predicate, Function.identity()); | 261 | return findFirst(from, predicate, Function.identity()); |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | - public static <T, U> U findFirst(List<T> from, Predicate<T> predicate, Function<T, U> func) { | 264 | + public static <T, U> U findFirst(Collection<T> from, Predicate<T> predicate, Function<T, U> func) { |
| 265 | if (CollUtil.isEmpty(from)) { | 265 | if (CollUtil.isEmpty(from)) { |
| 266 | return null; | 266 | return null; |
| 267 | } | 267 | } |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
| @@ -132,4 +132,40 @@ public class LocalDateTimeUtils { | @@ -132,4 +132,40 @@ public class LocalDateTimeUtils { | ||
| 132 | return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS); | 132 | return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | + /** | ||
| 136 | + * 获取今天的开始时间 | ||
| 137 | + * | ||
| 138 | + * @return 今天 | ||
| 139 | + */ | ||
| 140 | + public static LocalDateTime getToday() { | ||
| 141 | + return LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + /** | ||
| 145 | + * 获取昨天的开始时间 | ||
| 146 | + * | ||
| 147 | + * @return 昨天 | ||
| 148 | + */ | ||
| 149 | + public static LocalDateTime getYesterday() { | ||
| 150 | + return LocalDateTimeUtil.beginOfDay(LocalDateTime.now().minusDays(1)); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + /** | ||
| 154 | + * 获取本月的开始时间 | ||
| 155 | + * | ||
| 156 | + * @return 本月 | ||
| 157 | + */ | ||
| 158 | + public static LocalDateTime getMonth() { | ||
| 159 | + return beginOfMonth(LocalDateTime.now()); | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + /** | ||
| 163 | + * 获取本年的开始时间 | ||
| 164 | + * | ||
| 165 | + * @return 本年 | ||
| 166 | + */ | ||
| 167 | + public static LocalDateTime getYear() { | ||
| 168 | + return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN); | ||
| 169 | + } | ||
| 170 | + | ||
| 135 | } | 171 | } |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java
| @@ -17,6 +17,7 @@ import java.util.Map; | @@ -17,6 +17,7 @@ import java.util.Map; | ||
| 17 | import java.util.function.Function; | 17 | import java.util.function.Function; |
| 18 | 18 | ||
| 19 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 19 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 20 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; | ||
| 20 | 21 | ||
| 21 | /** | 22 | /** |
| 22 | * 区域工具类 | 23 | * 区域工具类 |
| @@ -70,11 +71,62 @@ public class AreaUtils { | @@ -70,11 +71,62 @@ public class AreaUtils { | ||
| 70 | * @param id 区域编号 | 71 | * @param id 区域编号 |
| 71 | * @return 区域 | 72 | * @return 区域 |
| 72 | */ | 73 | */ |
| 73 | - public static Area getArea(Integer id) { | 74 | + public static Area parseArea(Integer id) { |
| 74 | return areas.get(id); | 75 | return areas.get(id); |
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | /** | 78 | /** |
| 79 | + * 获得指定区域对应的编号 | ||
| 80 | + * | ||
| 81 | + * @param pathStr 区域路径,例如说:河南省/石家庄市/新华区 | ||
| 82 | + * @return 区域 | ||
| 83 | + */ | ||
| 84 | + public static Area parseArea(String pathStr) { | ||
| 85 | + String[] paths = pathStr.split("/"); | ||
| 86 | + Area area = null; | ||
| 87 | + for (String path : paths) { | ||
| 88 | + if (area == null) { | ||
| 89 | + area = findFirst(areas.values(), item -> item.getName().equals(path)); | ||
| 90 | + } else { | ||
| 91 | + area = findFirst(area.getChildren(), item -> item.getName().equals(path)); | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + return area; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + /** | ||
| 98 | + * 获取所有节点的全路径名称如:河南省/石家庄市/新华区 | ||
| 99 | + * | ||
| 100 | + * @param areas 地区树 | ||
| 101 | + * @return 所有节点的全路径名称 | ||
| 102 | + */ | ||
| 103 | + public static List<String> getAreaNodePathList(List<Area> areas) { | ||
| 104 | + List<String> paths = new ArrayList<>(); | ||
| 105 | + areas.forEach(area -> getAreaNodePathList(area, "", paths)); | ||
| 106 | + return paths; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + /** | ||
| 110 | + * 构建一棵树的所有节点的全路径名称,并将其存储为 "祖先/父级/子级" 的形式 | ||
| 111 | + * | ||
| 112 | + * @param node 父节点 | ||
| 113 | + * @param path 全路径名称 | ||
| 114 | + * @param paths 全路径名称列表,省份/城市/地区 | ||
| 115 | + */ | ||
| 116 | + private static void getAreaNodePathList(Area node, String path, List<String> paths) { | ||
| 117 | + if (node == null) { | ||
| 118 | + return; | ||
| 119 | + } | ||
| 120 | + // 构建当前节点的路径 | ||
| 121 | + String currentPath = path.isEmpty() ? node.getName() : path + "/" + node.getName(); | ||
| 122 | + paths.add(currentPath); | ||
| 123 | + // 递归遍历子节点 | ||
| 124 | + for (Area child : node.getChildren()) { | ||
| 125 | + getAreaNodePathList(child, currentPath, paths); | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + /** | ||
| 78 | * 格式化区域 | 130 | * 格式化区域 |
| 79 | * | 131 | * |
| 80 | * @param id 区域编号 | 132 | * @param id 区域编号 |
| @@ -88,13 +140,13 @@ public class AreaUtils { | @@ -88,13 +140,13 @@ public class AreaUtils { | ||
| 88 | * 格式化区域 | 140 | * 格式化区域 |
| 89 | * | 141 | * |
| 90 | * 例如说: | 142 | * 例如说: |
| 91 | - * 1. id = “静安区”时:上海 上海市 静安区 | ||
| 92 | - * 2. id = “上海市”时:上海 上海市 | ||
| 93 | - * 3. id = “上海”时:上海 | ||
| 94 | - * 4. id = “美国”时:美国 | 143 | + * 1. id = “静安区”时:上海 上海市 静安区 |
| 144 | + * 2. id = “上海市”时:上海 上海市 | ||
| 145 | + * 3. id = “上海”时:上海 | ||
| 146 | + * 4. id = “美国”时:美国 | ||
| 95 | * 当区域在中国时,默认不显示中国 | 147 | * 当区域在中国时,默认不显示中国 |
| 96 | * | 148 | * |
| 97 | - * @param id 区域编号 | 149 | + * @param id 区域编号 |
| 98 | * @param separator 分隔符 | 150 | * @param separator 分隔符 |
| 99 | * @return 格式化后的区域 | 151 | * @return 格式化后的区域 |
| 100 | */ | 152 | */ |
| @@ -141,7 +193,7 @@ public class AreaUtils { | @@ -141,7 +193,7 @@ public class AreaUtils { | ||
| 141 | */ | 193 | */ |
| 142 | public static Integer getParentIdByType(Integer id, @NonNull AreaTypeEnum type) { | 194 | public static Integer getParentIdByType(Integer id, @NonNull AreaTypeEnum type) { |
| 143 | for (int i = 0; i < Byte.MAX_VALUE; i++) { | 195 | for (int i = 0; i < Byte.MAX_VALUE; i++) { |
| 144 | - Area area = AreaUtils.getArea(id); | 196 | + Area area = AreaUtils.parseArea(id); |
| 145 | if (area == null) { | 197 | if (area == null) { |
| 146 | return null; | 198 | return null; |
| 147 | } | 199 | } |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java
| @@ -72,7 +72,7 @@ public class IPUtils { | @@ -72,7 +72,7 @@ public class IPUtils { | ||
| 72 | * @return 地区 | 72 | * @return 地区 |
| 73 | */ | 73 | */ |
| 74 | public static Area getArea(String ip) { | 74 | public static Area getArea(String ip) { |
| 75 | - return AreaUtils.getArea(getAreaId(ip)); | 75 | + return AreaUtils.parseArea(getAreaId(ip)); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | /** | 78 | /** |
| @@ -82,6 +82,6 @@ public class IPUtils { | @@ -82,6 +82,6 @@ public class IPUtils { | ||
| 82 | * @return 地区 | 82 | * @return 地区 |
| 83 | */ | 83 | */ |
| 84 | public static Area getArea(long ip) { | 84 | public static Area getArea(long ip) { |
| 85 | - return AreaUtils.getArea(getAreaId(ip)); | 85 | + return AreaUtils.parseArea(getAreaId(ip)); |
| 86 | } | 86 | } |
| 87 | } | 87 | } |
yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java
| @@ -17,7 +17,7 @@ public class AreaUtilsTest { | @@ -17,7 +17,7 @@ public class AreaUtilsTest { | ||
| 17 | @Test | 17 | @Test |
| 18 | public void testGetArea() { | 18 | public void testGetArea() { |
| 19 | // 调用:北京 | 19 | // 调用:北京 |
| 20 | - Area area = AreaUtils.getArea(110100); | 20 | + Area area = AreaUtils.parseArea(110100); |
| 21 | // 断言 | 21 | // 断言 |
| 22 | assertEquals(area.getId(), 110100); | 22 | assertEquals(area.getId(), 110100); |
| 23 | assertEquals(area.getName(), "北京市"); | 23 | assertEquals(area.getName(), "北京市"); |
yudao-framework/yudao-spring-boot-starter-excel/pom.xml
| @@ -46,6 +46,11 @@ | @@ -46,6 +46,11 @@ | ||
| 46 | <groupId>com.alibaba</groupId> | 46 | <groupId>com.alibaba</groupId> |
| 47 | <artifactId>easyexcel</artifactId> | 47 | <artifactId>easyexcel</artifactId> |
| 48 | </dependency> | 48 | </dependency> |
| 49 | + <dependency> | ||
| 50 | + <groupId>cn.iocoder.boot</groupId> | ||
| 51 | + <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> | ||
| 52 | + <optional>true</optional> <!-- 设置为 optional,只有在 AreaConvert 的时候使用 --> | ||
| 53 | + </dependency> | ||
| 49 | </dependencies> | 54 | </dependencies> |
| 50 | 55 | ||
| 51 | </project> | 56 | </project> |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.excel.core.convert; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.convert.Convert; | ||
| 4 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 5 | +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | ||
| 6 | +import com.alibaba.excel.converters.Converter; | ||
| 7 | +import com.alibaba.excel.enums.CellDataTypeEnum; | ||
| 8 | +import com.alibaba.excel.metadata.GlobalConfiguration; | ||
| 9 | +import com.alibaba.excel.metadata.data.ReadCellData; | ||
| 10 | +import com.alibaba.excel.metadata.property.ExcelContentProperty; | ||
| 11 | +import lombok.extern.slf4j.Slf4j; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * Excel 数据地区转换器 | ||
| 15 | + * | ||
| 16 | + * @author HUIHUI | ||
| 17 | + */ | ||
| 18 | +@Slf4j | ||
| 19 | +public class AreaConvert implements Converter<Object> { | ||
| 20 | + | ||
| 21 | + @Override | ||
| 22 | + public Class<?> supportJavaTypeKey() { | ||
| 23 | + throw new UnsupportedOperationException("暂不支持,也不需要"); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + @Override | ||
| 27 | + public CellDataTypeEnum supportExcelTypeKey() { | ||
| 28 | + throw new UnsupportedOperationException("暂不支持,也不需要"); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public Object convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty, | ||
| 33 | + GlobalConfiguration globalConfiguration) { | ||
| 34 | + // 解析地区编号 | ||
| 35 | + String label = readCellData.getStringValue(); | ||
| 36 | + Area area = AreaUtils.parseArea(label); | ||
| 37 | + if (area == null) { | ||
| 38 | + log.error("[convertToJavaData][label({}) 解析不掉]", label); | ||
| 39 | + return null; | ||
| 40 | + } | ||
| 41 | + // 将 value 转换成对应的属性 | ||
| 42 | + Class<?> fieldClazz = contentProperty.getField().getType(); | ||
| 43 | + return Convert.convert(fieldClazz, area.getId()); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | +} |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionRoleCodeEnum.java renamed to yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/enums/ExcelColumn.java
| 1 | -package cn.iocoder.yudao.module.crm.enums.permission; | 1 | +package cn.iocoder.yudao.framework.excel.core.enums; |
| 2 | 2 | ||
| 3 | import lombok.AllArgsConstructor; | 3 | import lombok.AllArgsConstructor; |
| 4 | import lombok.Getter; | 4 | import lombok.Getter; |
| 5 | 5 | ||
| 6 | +// TODO @puhui999:列表有办法通过 field name 么?主要考虑一个点,可能导入模版的顺序可能会变 | ||
| 6 | /** | 7 | /** |
| 7 | - * Crm 数据权限角色枚举 | 8 | + * Excel 列名枚举 |
| 9 | + * 默认枚举 26 列列名如果有需求更多的列名请自行补充 | ||
| 8 | * | 10 | * |
| 9 | * @author HUIHUI | 11 | * @author HUIHUI |
| 10 | */ | 12 | */ |
| 11 | @Getter | 13 | @Getter |
| 12 | @AllArgsConstructor | 14 | @AllArgsConstructor |
| 13 | -public enum CrmPermissionRoleCodeEnum { | 15 | +public enum ExcelColumn { |
| 14 | 16 | ||
| 15 | - CRM_ADMIN("crm_admin", "CRM 管理员"); | 17 | + A(0), B(1), C(2), D(3), E(4), F(5), G(6), H(7), I(8), |
| 18 | + J(9), K(10), L(11), M(12), N(13), O(14), P(15), Q(16), | ||
| 19 | + R(17), S(18), T(19), U(20), V(21), W(22), X(23), Y(24), | ||
| 20 | + Z(25); | ||
| 16 | 21 | ||
| 17 | /** | 22 | /** |
| 18 | - * 角色标识 | 23 | + * 列索引 |
| 19 | */ | 24 | */ |
| 20 | - private String code; | ||
| 21 | - /** | ||
| 22 | - * 角色名称 | ||
| 23 | - */ | ||
| 24 | - private String name; | 25 | + private final int colNum; |
| 25 | 26 | ||
| 26 | } | 27 | } |
| 27 | - |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.excel.core.handler; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.lang.Assert; | ||
| 5 | +import cn.iocoder.yudao.framework.common.core.KeyValue; | ||
| 6 | +import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn; | ||
| 7 | +import com.alibaba.excel.write.handler.SheetWriteHandler; | ||
| 8 | +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; | ||
| 9 | +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; | ||
| 10 | +import org.apache.poi.hssf.usermodel.HSSFDataValidation; | ||
| 11 | +import org.apache.poi.ss.usermodel.*; | ||
| 12 | +import org.apache.poi.ss.util.CellRangeAddressList; | ||
| 13 | + | ||
| 14 | +import java.util.Comparator; | ||
| 15 | +import java.util.List; | ||
| 16 | +import java.util.Map; | ||
| 17 | +import java.util.stream.Collectors; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * 基于固定 sheet 实现下拉框 | ||
| 21 | + * | ||
| 22 | + * @author HUIHUI | ||
| 23 | + */ | ||
| 24 | +public class SelectSheetWriteHandler implements SheetWriteHandler { | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 数据起始行从 0 开始 | ||
| 28 | + * | ||
| 29 | + * 约定:本项目第一行有标题所以从 1 开始如果您的 Excel 有多行标题请自行更改 | ||
| 30 | + */ | ||
| 31 | + public static final int FIRST_ROW = 1; | ||
| 32 | + /** | ||
| 33 | + * 下拉列需要创建下拉框的行数,默认两千行如需更多请自行调整 | ||
| 34 | + */ | ||
| 35 | + public static final int LAST_ROW = 2000; | ||
| 36 | + | ||
| 37 | + private static final String DICT_SHEET_NAME = "字典sheet"; | ||
| 38 | + | ||
| 39 | + // TODO @puhui999:Map<ExcelColumn, List<String>> 可以么?之前用 keyvalue 的原因,返回给前端,无法用 linkedhashmap,默认 key 会乱序 | ||
| 40 | + private final List<KeyValue<ExcelColumn, List<String>>> selectMap; | ||
| 41 | + | ||
| 42 | + public SelectSheetWriteHandler(List<KeyValue<ExcelColumn, List<String>>> selectMap) { | ||
| 43 | + if (CollUtil.isEmpty(selectMap)) { | ||
| 44 | + this.selectMap = null; | ||
| 45 | + return; | ||
| 46 | + } | ||
| 47 | + // 校验一下 key 是否唯一 | ||
| 48 | + Map<String, Long> nameCounts = selectMap.stream() | ||
| 49 | + .collect(Collectors.groupingBy(item -> item.getKey().name(), Collectors.counting())); | ||
| 50 | + Assert.isFalse(nameCounts.entrySet().stream().allMatch(entry -> entry.getValue() > 1), "下拉数据 key 重复请排查!!!"); | ||
| 51 | + | ||
| 52 | + selectMap.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 | ||
| 53 | + this.selectMap = selectMap; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { | ||
| 58 | + if (CollUtil.isEmpty(selectMap)) { | ||
| 59 | + return; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + // 1. 获取相应操作对象 | ||
| 63 | + DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper(); // 需要设置下拉框的 sheet 页的数据验证助手 | ||
| 64 | + Workbook workbook = writeWorkbookHolder.getWorkbook(); // 获得工作簿 | ||
| 65 | + | ||
| 66 | + // 2. 创建数据字典的 sheet 页 | ||
| 67 | + Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); | ||
| 68 | + for (KeyValue<ExcelColumn, List<String>> keyValue : selectMap) { | ||
| 69 | + int rowLength = keyValue.getValue().size(); | ||
| 70 | + // 2.1 设置字典 sheet 页的值 每一列一个字典项 | ||
| 71 | + for (int i = 0; i < rowLength; i++) { | ||
| 72 | + Row row = dictSheet.getRow(i); | ||
| 73 | + if (row == null) { | ||
| 74 | + row = dictSheet.createRow(i); | ||
| 75 | + } | ||
| 76 | + row.createCell(keyValue.getKey().getColNum()).setCellValue(keyValue.getValue().get(i)); | ||
| 77 | + } | ||
| 78 | + // 2.2 设置单元格下拉选择 | ||
| 79 | + setColumnSelect(writeSheetHolder, workbook, helper, keyValue); | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /** | ||
| 84 | + * 设置单元格下拉选择 | ||
| 85 | + */ | ||
| 86 | + private static void setColumnSelect(WriteSheetHolder writeSheetHolder, Workbook workbook, DataValidationHelper helper, | ||
| 87 | + KeyValue<ExcelColumn, List<String>> keyValue) { | ||
| 88 | + // 1.1 创建可被其他单元格引用的名称 | ||
| 89 | + Name name = workbook.createName(); | ||
| 90 | + String excelColumn = keyValue.getKey().name(); | ||
| 91 | + // 1.2 下拉框数据来源 eg:字典sheet!$B1:$B2 | ||
| 92 | + String refers = DICT_SHEET_NAME + "!$" + excelColumn + "$1:$" + excelColumn + "$" + keyValue.getValue().size(); | ||
| 93 | + name.setNameName("dict" + keyValue.getKey()); // 设置名称的名字 | ||
| 94 | + name.setRefersToFormula(refers); // 设置公式 | ||
| 95 | + | ||
| 96 | + // 2.1 设置约束 | ||
| 97 | + DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + keyValue.getKey()); // 设置引用约束 | ||
| 98 | + // 设置下拉单元格的首行、末行、首列、末列 | ||
| 99 | + CellRangeAddressList rangeAddressList = new CellRangeAddressList(FIRST_ROW, LAST_ROW, | ||
| 100 | + keyValue.getKey().getColNum(), keyValue.getKey().getColNum()); | ||
| 101 | + DataValidation validation = helper.createValidation(constraint, rangeAddressList); | ||
| 102 | + if (validation instanceof HSSFDataValidation) { | ||
| 103 | + validation.setSuppressDropDownArrow(false); | ||
| 104 | + } else { | ||
| 105 | + validation.setSuppressDropDownArrow(true); | ||
| 106 | + validation.setShowErrorBox(true); | ||
| 107 | + } | ||
| 108 | + // 2.2 阻止输入非下拉框的值 | ||
| 109 | + validation.setErrorStyle(DataValidation.ErrorStyle.STOP); | ||
| 110 | + validation.createErrorBox("提示", "此值不存在于下拉选择中!"); | ||
| 111 | + // 2.3 添加下拉框约束 | ||
| 112 | + writeSheetHolder.getSheet().addValidationData(validation); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | +} | ||
| 0 | \ No newline at end of file | 116 | \ No newline at end of file |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
| 1 | package cn.iocoder.yudao.framework.excel.core.util; | 1 | package cn.iocoder.yudao.framework.excel.core.util; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.KeyValue; | ||
| 4 | +import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn; | ||
| 5 | +import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; | ||
| 3 | import com.alibaba.excel.EasyExcel; | 6 | import com.alibaba.excel.EasyExcel; |
| 4 | import com.alibaba.excel.converters.longconverter.LongStringConverter; | 7 | import com.alibaba.excel.converters.longconverter.LongStringConverter; |
| 5 | import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; | 8 | import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; |
| 9 | +import jakarta.servlet.http.HttpServletResponse; | ||
| 6 | import org.springframework.web.multipart.MultipartFile; | 10 | import org.springframework.web.multipart.MultipartFile; |
| 7 | 11 | ||
| 8 | -import jakarta.servlet.http.HttpServletResponse; | ||
| 9 | import java.io.IOException; | 12 | import java.io.IOException; |
| 10 | import java.net.URLEncoder; | 13 | import java.net.URLEncoder; |
| 11 | import java.nio.charset.StandardCharsets; | 14 | import java.nio.charset.StandardCharsets; |
| @@ -21,29 +24,46 @@ public class ExcelUtils { | @@ -21,29 +24,46 @@ public class ExcelUtils { | ||
| 21 | /** | 24 | /** |
| 22 | * 将列表以 Excel 响应给前端 | 25 | * 将列表以 Excel 响应给前端 |
| 23 | * | 26 | * |
| 24 | - * @param response 响应 | ||
| 25 | - * @param filename 文件名 | 27 | + * @param response 响应 |
| 28 | + * @param filename 文件名 | ||
| 26 | * @param sheetName Excel sheet 名 | 29 | * @param sheetName Excel sheet 名 |
| 27 | - * @param head Excel head 头 | ||
| 28 | - * @param data 数据列表哦 | ||
| 29 | - * @param <T> 泛型,保证 head 和 data 类型的一致性 | 30 | + * @param head Excel head 头 |
| 31 | + * @param data 数据列表哦 | ||
| 32 | + * @param <T> 泛型,保证 head 和 data 类型的一致性 | ||
| 30 | * @throws IOException 写入失败的情况 | 33 | * @throws IOException 写入失败的情况 |
| 31 | */ | 34 | */ |
| 32 | public static <T> void write(HttpServletResponse response, String filename, String sheetName, | 35 | public static <T> void write(HttpServletResponse response, String filename, String sheetName, |
| 33 | Class<T> head, List<T> data) throws IOException { | 36 | Class<T> head, List<T> data) throws IOException { |
| 37 | + write(response, filename, sheetName, head, data, null); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 将列表以 Excel 响应给前端 | ||
| 42 | + * | ||
| 43 | + * @param response 响应 | ||
| 44 | + * @param filename 文件名 | ||
| 45 | + * @param sheetName Excel sheet 名 | ||
| 46 | + * @param head Excel head 头 | ||
| 47 | + * @param data 数据列表哦 | ||
| 48 | + * @param selectMap 下拉选择数据 Map<下拉所对应的列表名,下拉数据> | ||
| 49 | + * @throws IOException 写入失败的情况 | ||
| 50 | + */ | ||
| 51 | + public static <T> void write(HttpServletResponse response, String filename, String sheetName, | ||
| 52 | + Class<T> head, List<T> data, List<KeyValue<ExcelColumn, List<String>>> selectMap) throws IOException { | ||
| 34 | // 输出 Excel | 53 | // 输出 Excel |
| 35 | EasyExcel.write(response.getOutputStream(), head) | 54 | EasyExcel.write(response.getOutputStream(), head) |
| 36 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 | 55 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 |
| 37 | .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 | 56 | .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 |
| 57 | + .registerWriteHandler(new SelectSheetWriteHandler(selectMap)) // 基于固定 sheet 实现下拉框 | ||
| 38 | .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 | 58 | .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 |
| 39 | .sheet(sheetName).doWrite(data); | 59 | .sheet(sheetName).doWrite(data); |
| 40 | // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 | 60 | // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 |
| 41 | - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8)); | 61 | + response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); |
| 42 | response.setContentType("application/vnd.ms-excel;charset=UTF-8"); | 62 | response.setContentType("application/vnd.ms-excel;charset=UTF-8"); |
| 43 | } | 63 | } |
| 44 | 64 | ||
| 45 | public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException { | 65 | public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException { |
| 46 | - return EasyExcel.read(file.getInputStream(), head, null) | 66 | + return EasyExcel.read(file.getInputStream(), head, null) |
| 47 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 | 67 | .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 |
| 48 | .doReadAllSync(); | 68 | .doReadAllSync(); |
| 49 | } | 69 | } |
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/listener/BpmResultListenerApi.java deleted
| 1 | -package cn.iocoder.yudao.module.bpm.api.listener; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; | ||
| 4 | - | ||
| 5 | -// TODO @芋艿:后续改成支持 RPC | ||
| 6 | -/** | ||
| 7 | - * 业务流程实例的结果发生变化的监听器 Api | ||
| 8 | - * | ||
| 9 | - * @author HUIHUI | ||
| 10 | - */ | ||
| 11 | -public interface BpmResultListenerApi { | ||
| 12 | - | ||
| 13 | - /** | ||
| 14 | - * 监听的流程定义 Key | ||
| 15 | - * | ||
| 16 | - * @return 返回监听的流程定义 Key | ||
| 17 | - */ | ||
| 18 | - String getProcessDefinitionKey(); | ||
| 19 | - | ||
| 20 | - /** | ||
| 21 | - * 处理事件 | ||
| 22 | - * | ||
| 23 | - * @param event 事件 | ||
| 24 | - */ | ||
| 25 | - void onEvent(BpmResultListenerRespDTO event); | ||
| 26 | - | ||
| 27 | -} |
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/listener/dto/BpmResultListenerRespDTO.java deleted
| 1 | -package cn.iocoder.yudao.module.bpm.api.listener.dto; | ||
| 2 | - | ||
| 3 | -import lombok.Data; | ||
| 4 | - | ||
| 5 | -// TODO @芋艿:后续改成支持 RPC | ||
| 6 | -/** | ||
| 7 | - * 业务流程实例的结果 Response DTO | ||
| 8 | - * | ||
| 9 | - * @author HUIHUI | ||
| 10 | - */ | ||
| 11 | -@Data | ||
| 12 | -public class BpmResultListenerRespDTO { | ||
| 13 | - | ||
| 14 | - /** | ||
| 15 | - * 流程实例的编号 | ||
| 16 | - */ | ||
| 17 | - private String id; | ||
| 18 | - /** | ||
| 19 | - * 流程实例的 key | ||
| 20 | - */ | ||
| 21 | - private String processDefinitionKey; | ||
| 22 | - /** | ||
| 23 | - * 流程实例的结果 | ||
| 24 | - */ | ||
| 25 | - private Integer result; | ||
| 26 | - /** | ||
| 27 | - * 流程实例对应的业务标识 | ||
| 28 | - * 例如说,请假 | ||
| 29 | - */ | ||
| 30 | - private String businessKey; | ||
| 31 | - | ||
| 32 | -} |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEvent.java renamed to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java
| 1 | -package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; | 1 | +package cn.iocoder.yudao.module.bpm.event; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; | 3 | +import jakarta.validation.constraints.NotNull; |
| 4 | import lombok.Data; | 4 | import lombok.Data; |
| 5 | import org.springframework.context.ApplicationEvent; | 5 | import org.springframework.context.ApplicationEvent; |
| 6 | 6 | ||
| 7 | -import jakarta.validation.constraints.NotNull; | ||
| 8 | - | ||
| 9 | /** | 7 | /** |
| 10 | * 流程实例的结果发生变化的 Event | 8 | * 流程实例的结果发生变化的 Event |
| 11 | * 定位:由于额外增加了 {@link BpmProcessInstanceExtDO#getResult()} 结果,所以增加该事件 | 9 | * 定位:由于额外增加了 {@link BpmProcessInstanceExtDO#getResult()} 结果,所以增加该事件 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventListener.java renamed to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java
| 1 | -package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; | 1 | +package cn.iocoder.yudao.module.bpm.event; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.StrUtil; | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | import org.springframework.context.ApplicationListener; | 4 | import org.springframework.context.ApplicationListener; |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
| @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI | @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI | ||
| 7 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; | 7 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; |
| 8 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; | 8 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; |
| 9 | import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; | 9 | import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; |
| 10 | -import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; | 10 | +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; |
| 11 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; | 11 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; |
| 12 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; | 12 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; |
| 13 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | 13 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; | 1 | package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; | ||
| 3 | import lombok.AllArgsConstructor; | 4 | import lombok.AllArgsConstructor; |
| 4 | import org.springframework.context.ApplicationEventPublisher; | 5 | import org.springframework.context.ApplicationEventPublisher; |
| 5 | import org.springframework.validation.annotation.Validated; | 6 | import org.springframework.validation.annotation.Validated; |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/listener/BpmServiceResultListener.java deleted
| 1 | -package cn.iocoder.yudao.module.bpm.framework.bpm.listener; | ||
| 2 | - | ||
| 3 | -import cn.hutool.core.util.StrUtil; | ||
| 4 | -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 5 | -import cn.iocoder.yudao.module.bpm.api.listener.BpmResultListenerApi; | ||
| 6 | -import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO; | ||
| 7 | -import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; | ||
| 8 | -import jakarta.annotation.Resource; | ||
| 9 | -import org.springframework.context.ApplicationListener; | ||
| 10 | -import org.springframework.stereotype.Component; | ||
| 11 | - | ||
| 12 | -import java.util.List; | ||
| 13 | - | ||
| 14 | -// TODO @芋艿:后续改成支持 RPC | ||
| 15 | -/** | ||
| 16 | - * 业务流程结果监听器实现类 | ||
| 17 | - * | ||
| 18 | - * @author HUIHUI | ||
| 19 | - */ | ||
| 20 | -@Component | ||
| 21 | -public class BpmServiceResultListener implements ApplicationListener<BpmProcessInstanceResultEvent> { | ||
| 22 | - | ||
| 23 | - @Resource | ||
| 24 | - private List<BpmResultListenerApi> bpmResultListenerApis; | ||
| 25 | - | ||
| 26 | - @Override | ||
| 27 | - public final void onApplicationEvent(BpmProcessInstanceResultEvent event) { | ||
| 28 | - bpmResultListenerApis.forEach(bpmResultListenerApi -> { | ||
| 29 | - if (!StrUtil.equals(event.getProcessDefinitionKey(), bpmResultListenerApi.getProcessDefinitionKey())) { | ||
| 30 | - return; | ||
| 31 | - } | ||
| 32 | - bpmResultListenerApi.onEvent(BeanUtils.toBean(event, BpmResultListenerRespDTO.class)); | ||
| 33 | - }); | ||
| 34 | - } | ||
| 35 | - | ||
| 36 | -} |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java
| 1 | package cn.iocoder.yudao.module.bpm.service.oa.listener; | 1 | package cn.iocoder.yudao.module.bpm.service.oa.listener; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; | ||
| 4 | -import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventListener; | 3 | +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; |
| 4 | +import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEventListener; | ||
| 5 | import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; | 5 | import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; |
| 6 | import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveServiceImpl; | 6 | import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveServiceImpl; |
| 7 | import org.springframework.stereotype.Component; | 7 | import org.springframework.stereotype.Component; |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java
| @@ -14,5 +14,6 @@ public interface DictTypeConstants { | @@ -14,5 +14,6 @@ public interface DictTypeConstants { | ||
| 14 | String CRM_PRODUCT_UNIT = "crm_product_unit"; // CRM 产品单位 | 14 | String CRM_PRODUCT_UNIT = "crm_product_unit"; // CRM 产品单位 |
| 15 | String CRM_PRODUCT_STATUS = "crm_product_status"; // CRM 产品状态 | 15 | String CRM_PRODUCT_STATUS = "crm_product_status"; // CRM 产品状态 |
| 16 | String CRM_FOLLOW_UP_TYPE = "crm_follow_up_type"; // CRM 跟进方式 | 16 | String CRM_FOLLOW_UP_TYPE = "crm_follow_up_type"; // CRM 跟进方式 |
| 17 | + String CRM_RECEIVABLE_RETURN_TYPE = "crm_receivable_return_type"; // CRM 回款方式 | ||
| 17 | 18 | ||
| 18 | } | 19 | } |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
| @@ -11,31 +11,40 @@ public interface ErrorCodeConstants { | @@ -11,31 +11,40 @@ public interface ErrorCodeConstants { | ||
| 11 | 11 | ||
| 12 | // ========== 合同管理 1-020-000-000 ========== | 12 | // ========== 合同管理 1-020-000-000 ========== |
| 13 | ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在"); | 13 | ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在"); |
| 14 | - ErrorCode CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_000_001, "更新合同失败,原因:禁止编辑"); | 14 | + ErrorCode CONTRACT_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_001, "合同更新失败,原因:合同不是草稿状态"); |
| 15 | ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态"); | 15 | ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态"); |
| 16 | + ErrorCode CONTRACT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_000_003, "更新合同审核状态失败,原因:合同不是审核中状态"); | ||
| 17 | + ErrorCode CONTRACT_NO_EXISTS = new ErrorCode(1_020_000_004, "生成合同序列号重复,请重试"); | ||
| 16 | 18 | ||
| 17 | // ========== 线索管理 1-020-001-000 ========== | 19 | // ========== 线索管理 1-020-001-000 ========== |
| 18 | ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); | 20 | ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); |
| 19 | - ErrorCode CLUE_ANY_CLUE_NOT_EXISTS = new ErrorCode(1_020_001_001, "线索【{}】不存在"); | ||
| 20 | - ErrorCode CLUE_ANY_CLUE_ALREADY_TRANSLATED = new ErrorCode(1_020_001_002, "线索【{}】已经转化过了,请勿重复转化"); | 21 | + ErrorCode CLUE_TRANSFORM_FAIL_ALREADY = new ErrorCode(1_020_001_001, "线索已经转化过了,请勿重复转化"); |
| 21 | 22 | ||
| 22 | // ========== 商机管理 1-020-002-000 ========== | 23 | // ========== 商机管理 1-020-002-000 ========== |
| 23 | ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在"); | 24 | ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在"); |
| 24 | - ErrorCode BUSINESS_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "商机已关联合同,不能删除"); | ||
| 25 | - | ||
| 26 | - // TODO @lilleo:商机状态、商机类型,都单独错误码段 | ||
| 27 | - | 25 | + ErrorCode BUSINESS_DELETE_FAIL_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "商机已关联合同,不能删除"); |
| 26 | + ErrorCode BUSINESS_UPDATE_STATUS_FAIL_END_STATUS = new ErrorCode(1_020_002_002, "更新商机状态失败,原因:已经是结束状态"); | ||
| 27 | + ErrorCode BUSINESS_UPDATE_STATUS_FAIL_STATUS_EQUALS = new ErrorCode(1_020_002_003, "更新商机状态失败,原因:已经是该状态"); | ||
| 28 | 28 | ||
| 29 | // ========== 联系人管理 1-020-003-000 ========== | 29 | // ========== 联系人管理 1-020-003-000 ========== |
| 30 | ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); | 30 | ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); |
| 31 | - ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode(1_020_003_001, "联系人商机关联不存在"); | ||
| 32 | ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除"); | 31 | ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除"); |
| 32 | + ErrorCode CONTACT_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_003_003, "更新联系人负责人失败"); | ||
| 33 | 33 | ||
| 34 | // ========== 回款 1-020-004-000 ========== | 34 | // ========== 回款 1-020-004-000 ========== |
| 35 | ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); | 35 | ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); |
| 36 | - | ||
| 37 | - // ========== 合同管理 1-020-005-000 ========== | 36 | + ErrorCode RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_004_001, "更新回款失败,原因:禁止编辑"); |
| 37 | + ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除"); | ||
| 38 | + ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态"); | ||
| 39 | + ErrorCode RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_004_004, "更新回款审核状态失败,原因:回款不是审核中状态"); | ||
| 40 | + ErrorCode RECEIVABLE_NO_EXISTS = new ErrorCode(1_020_004_005, "生成回款序列号重复,请重试"); | ||
| 41 | + ErrorCode RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE = new ErrorCode(1_020_004_006, "创建回款失败,原因:合同不是审核通过状态"); | ||
| 42 | + ErrorCode RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT = new ErrorCode(1_020_004_007, "创建回款失败,原因:回款金额超出合同金额,目前剩余可退:{} 元"); | ||
| 43 | + | ||
| 44 | + // ========== 回款计划 1-020-005-000 ========== | ||
| 38 | ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); | 45 | ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); |
| 46 | + ErrorCode RECEIVABLE_PLAN_UPDATE_FAIL = new ErrorCode(1_020_006_000, "更想回款计划失败,原因:已经有对应的还款"); | ||
| 47 | + ErrorCode RECEIVABLE_PLAN_EXISTS_RECEIVABLE = new ErrorCode(1_020_006_001, "回款计划已经有对应的回款,不能使用"); | ||
| 39 | 48 | ||
| 40 | // ========== 客户管理 1_020_006_000 ========== | 49 | // ========== 客户管理 1_020_006_000 ========== |
| 41 | ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在"); | 50 | ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在"); |
| @@ -53,14 +62,13 @@ public interface ErrorCodeConstants { | @@ -53,14 +62,13 @@ public interface ErrorCodeConstants { | ||
| 53 | ErrorCode CUSTOMER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_020_006_012, "导入客户数据不能为空!"); | 62 | ErrorCode CUSTOMER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_020_006_012, "导入客户数据不能为空!"); |
| 54 | ErrorCode CUSTOMER_CREATE_NAME_NOT_NULL = new ErrorCode(1_020_006_013, "客户名称不能为空!"); | 63 | ErrorCode CUSTOMER_CREATE_NAME_NOT_NULL = new ErrorCode(1_020_006_013, "客户名称不能为空!"); |
| 55 | ErrorCode CUSTOMER_NAME_EXISTS = new ErrorCode(1_020_006_014, "已存在名为【{}】的客户!"); | 64 | ErrorCode CUSTOMER_NAME_EXISTS = new ErrorCode(1_020_006_014, "已存在名为【{}】的客户!"); |
| 65 | + ErrorCode CUSTOMER_UPDATE_DEAL_STATUS_FAIL = new ErrorCode(1_020_006_015, "更新客户的成交状态失败,原因:已经是该状态,无需更新"); | ||
| 56 | 66 | ||
| 57 | // ========== 权限管理 1_020_007_000 ========== | 67 | // ========== 权限管理 1_020_007_000 ========== |
| 58 | ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); | 68 | ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); |
| 59 | ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限"); | 69 | ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限"); |
| 60 | - ErrorCode CRM_PERMISSION_MODEL_NOT_EXISTS = new ErrorCode(1_020_007_002, "{}不存在"); | ||
| 61 | ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人"); | 70 | ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人"); |
| 62 | ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下"); | 71 | ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下"); |
| 63 | - ErrorCode CRM_PERMISSION_DELETE_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_005, "删除数据权限失败,原因:存在负责人"); | ||
| 64 | ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限"); | 72 | ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限"); |
| 65 | ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); | 73 | ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); |
| 66 | ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); | 74 | ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); |
| @@ -68,6 +76,7 @@ public interface ErrorCodeConstants { | @@ -68,6 +76,7 @@ public interface ErrorCodeConstants { | ||
| 68 | // ========== 产品 1_020_008_000 ========== | 76 | // ========== 产品 1_020_008_000 ========== |
| 69 | ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); | 77 | ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); |
| 70 | ErrorCode PRODUCT_NO_EXISTS = new ErrorCode(1_020_008_001, "产品编号已存在"); | 78 | ErrorCode PRODUCT_NO_EXISTS = new ErrorCode(1_020_008_001, "产品编号已存在"); |
| 79 | + ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_020_008_002, "产品【{}】已禁用"); | ||
| 71 | 80 | ||
| 72 | // ========== 产品分类 1_020_009_000 ========== | 81 | // ========== 产品分类 1_020_009_000 ========== |
| 73 | ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_009_000, "产品分类不存在"); | 82 | ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_009_000, "产品分类不存在"); |
| @@ -77,21 +86,18 @@ public interface ErrorCodeConstants { | @@ -77,21 +86,18 @@ public interface ErrorCodeConstants { | ||
| 77 | ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_020_009_004, "父分类不能是二级分类"); | 86 | ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_020_009_004, "父分类不能是二级分类"); |
| 78 | ErrorCode product_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); | 87 | ErrorCode product_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); |
| 79 | 88 | ||
| 80 | - // ========== 商机状态类型 1_020_010_000 ========== | ||
| 81 | - ErrorCode BUSINESS_STATUS_TYPE_NOT_EXISTS = new ErrorCode(1_020_010_000, "商机状态类型不存在"); | ||
| 82 | - ErrorCode BUSINESS_STATUS_TYPE_NAME_EXISTS = new ErrorCode(1_020_010_001, "商机状态类型名称已存在"); | ||
| 83 | - | ||
| 84 | - // ========== 商机状态 1_020_011_000 ========== | ||
| 85 | - ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_011_000, "商机状态不存在"); | 89 | + // ========== 商机状态 1_020_010_000 ========== |
| 90 | + ErrorCode BUSINESS_STATUS_TYPE_NOT_EXISTS = new ErrorCode(1_020_010_000, "商机状态组不存在"); | ||
| 91 | + ErrorCode BUSINESS_STATUS_TYPE_NAME_EXISTS = new ErrorCode(1_020_010_001, "商机状态组的名称已存在"); | ||
| 92 | + ErrorCode BUSINESS_STATUS_UPDATE_FAIL_USED = new ErrorCode(1_020_010_002, "已经被使用的商机状态组,无法进行更新"); | ||
| 93 | + ErrorCode BUSINESS_STATUS_DELETE_FAIL_USED = new ErrorCode(1_020_010_002, "已经被使用的商机状态组,无法进行删除"); | ||
| 94 | + ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_010_003, "商机状态不存在"); | ||
| 86 | 95 | ||
| 87 | // ========== 客户公海规则设置 1_020_012_000 ========== | 96 | // ========== 客户公海规则设置 1_020_012_000 ========== |
| 88 | - ErrorCode CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED = new ErrorCode(1_020_012_000, "客户公海配置不存在或未启用"); | ||
| 89 | ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在"); | 97 | ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在"); |
| 90 | 98 | ||
| 91 | // ========== 跟进记录 1_020_013_000 ========== | 99 | // ========== 跟进记录 1_020_013_000 ========== |
| 92 | ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); | 100 | ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); |
| 93 | ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); | 101 | ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); |
| 94 | 102 | ||
| 95 | - // ========== 待办消息 1_020_014_000 ========== | ||
| 96 | - | ||
| 97 | } | 103 | } |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
| @@ -8,19 +8,21 @@ package cn.iocoder.yudao.module.crm.enums; | @@ -8,19 +8,21 @@ package cn.iocoder.yudao.module.crm.enums; | ||
| 8 | */ | 8 | */ |
| 9 | public interface LogRecordConstants { | 9 | public interface LogRecordConstants { |
| 10 | 10 | ||
| 11 | - // ======================= CRM_LEADS 线索 ======================= | ||
| 12 | - | ||
| 13 | - String CRM_LEADS_TYPE = "CRM 线索"; | ||
| 14 | - String CRM_LEADS_CREATE_SUB_TYPE = "创建线索"; | ||
| 15 | - String CRM_LEADS_CREATE_SUCCESS = "创建了线索{{#clue.name}}"; | ||
| 16 | - String CRM_LEADS_UPDATE_SUB_TYPE = "更新线索"; | ||
| 17 | - String CRM_LEADS_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReq}}"; | ||
| 18 | - String CRM_LEADS_DELETE_SUB_TYPE = "删除线索"; | ||
| 19 | - String CRM_LEADS_DELETE_SUCCESS = "删除了线索【{{#clueName}}】"; | ||
| 20 | - String CRM_LEADS_TRANSFER_SUB_TYPE = "转移线索"; | ||
| 21 | - String CRM_LEADS_TRANSFER_SUCCESS = "将线索【{{#clue.name}}】的负责人从【{getAdminUserById{#clue.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | ||
| 22 | - String CRM_LEADS_TRANSLATE_SUB_TYPE = "线索转化为客户"; | ||
| 23 | - String CRM_LEADS_TRANSLATE_SUCCESS = "将线索【{{#clue.name}}】转化为客户"; | 11 | + // ======================= CRM_CLUE 线索 ======================= |
| 12 | + | ||
| 13 | + String CRM_CLUE_TYPE = "CRM 线索"; | ||
| 14 | + String CRM_CLUE_CREATE_SUB_TYPE = "创建线索"; | ||
| 15 | + String CRM_CLUE_CREATE_SUCCESS = "创建了线索{{#clue.name}}"; | ||
| 16 | + String CRM_CLUE_UPDATE_SUB_TYPE = "更新线索"; | ||
| 17 | + String CRM_CLUE_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReq}}"; | ||
| 18 | + String CRM_CLUE_DELETE_SUB_TYPE = "删除线索"; | ||
| 19 | + String CRM_CLUE_DELETE_SUCCESS = "删除了线索【{{#clueName}}】"; | ||
| 20 | + String CRM_CLUE_TRANSFER_SUB_TYPE = "转移线索"; | ||
| 21 | + String CRM_CLUE_TRANSFER_SUCCESS = "将线索【{{#clue.name}}】的负责人从【{getAdminUserById{#clue.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | ||
| 22 | + String CRM_CLUE_TRANSLATE_SUB_TYPE = "线索转化为客户"; | ||
| 23 | + String CRM_CLUE_TRANSLATE_SUCCESS = "将线索【{{#clueName}}】转化为客户"; | ||
| 24 | + String CRM_CLUE_FOLLOW_UP_SUB_TYPE = "线索跟进"; | ||
| 25 | + String CRM_CLUE_FOLLOW_UP_SUCCESS = "线索跟进【{{#clueName}}】"; | ||
| 24 | 26 | ||
| 25 | // ======================= CRM_CUSTOMER 客户 ======================= | 27 | // ======================= CRM_CUSTOMER 客户 ======================= |
| 26 | 28 | ||
| @@ -41,6 +43,10 @@ public interface LogRecordConstants { | @@ -41,6 +43,10 @@ public interface LogRecordConstants { | ||
| 41 | String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}"; | 43 | String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}"; |
| 42 | String CRM_CUSTOMER_IMPORT_SUB_TYPE = "{{#isUpdate ? '导入并更新客户' : '导入客户'}}"; | 44 | String CRM_CUSTOMER_IMPORT_SUB_TYPE = "{{#isUpdate ? '导入并更新客户' : '导入客户'}}"; |
| 43 | String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}"; | 45 | String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}"; |
| 46 | + String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUB_TYPE = "更新客户成交状态"; | ||
| 47 | + String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUCCESS = "更新了客户【{{#customerName}}】的成交状态为【{{#dealStatus ? '已成交' : '未成交'}}】"; | ||
| 48 | + String CRM_CUSTOMER_FOLLOW_UP_SUB_TYPE = "客户跟进"; | ||
| 49 | + String CRM_CUSTOMER_FOLLOW_UP_SUCCESS = "客户跟进【{{#customerName}}】"; | ||
| 44 | 50 | ||
| 45 | // ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 ======================= | 51 | // ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 ======================= |
| 46 | 52 | ||
| @@ -69,6 +75,10 @@ public interface LogRecordConstants { | @@ -69,6 +75,10 @@ public interface LogRecordConstants { | ||
| 69 | String CRM_CONTACT_DELETE_SUCCESS = "删除了联系人【{{#contactName}}】"; | 75 | String CRM_CONTACT_DELETE_SUCCESS = "删除了联系人【{{#contactName}}】"; |
| 70 | String CRM_CONTACT_TRANSFER_SUB_TYPE = "转移联系人"; | 76 | String CRM_CONTACT_TRANSFER_SUB_TYPE = "转移联系人"; |
| 71 | String CRM_CONTACT_TRANSFER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | 77 | String CRM_CONTACT_TRANSFER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; |
| 78 | + String CRM_CONTACT_FOLLOW_UP_SUB_TYPE = "联系人跟进"; | ||
| 79 | + String CRM_CONTACT_FOLLOW_UP_SUCCESS = "联系人跟进【{{#contactName}}】"; | ||
| 80 | + String CRM_CONTACT_UPDATE_OWNER_USER_SUB_TYPE = "更新联系人负责人"; | ||
| 81 | + String CRM_CONTACT_UPDATE_OWNER_USER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#ownerUserId}}】"; | ||
| 72 | 82 | ||
| 73 | // ======================= CRM_BUSINESS 商机 ======================= | 83 | // ======================= CRM_BUSINESS 商机 ======================= |
| 74 | 84 | ||
| @@ -81,6 +91,16 @@ public interface LogRecordConstants { | @@ -81,6 +91,16 @@ public interface LogRecordConstants { | ||
| 81 | String CRM_BUSINESS_DELETE_SUCCESS = "删除了商机【{{#businessName}}】"; | 91 | String CRM_BUSINESS_DELETE_SUCCESS = "删除了商机【{{#businessName}}】"; |
| 82 | String CRM_BUSINESS_TRANSFER_SUB_TYPE = "转移商机"; | 92 | String CRM_BUSINESS_TRANSFER_SUB_TYPE = "转移商机"; |
| 83 | String CRM_BUSINESS_TRANSFER_SUCCESS = "将商机【{{#business.name}}】的负责人从【{getAdminUserById{#business.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | 93 | String CRM_BUSINESS_TRANSFER_SUCCESS = "将商机【{{#business.name}}】的负责人从【{getAdminUserById{#business.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; |
| 94 | + String CRM_BUSINESS_FOLLOW_UP_SUB_TYPE = "商机跟进"; | ||
| 95 | + String CRM_BUSINESS_FOLLOW_UP_SUCCESS = "商机跟进【{{#businessName}}】"; | ||
| 96 | + String CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE = "更新商机状态"; | ||
| 97 | + String CRM_BUSINESS_UPDATE_STATUS_SUCCESS = "更新了商机【{{#businessName}}】的状态从【{{#oldStatusName}}】变更为了【{{#newStatusName}}】"; | ||
| 98 | + | ||
| 99 | + // ======================= CRM_CONTRACT_CONFIG 合同配置 ======================= | ||
| 100 | + | ||
| 101 | + String CRM_CONTRACT_CONFIG_TYPE = "CRM 合同配置"; | ||
| 102 | + String CRM_CONTRACT_CONFIG_SUB_TYPE = "{{#isPoolConfigUpdate ? '更新合同配置' : '创建合同配置'}}"; | ||
| 103 | + String CRM_CONTRACT_CONFIG_SUCCESS = "{{#isPoolConfigUpdate ? '更新了合同配置' : '创建了合同配置'}}"; | ||
| 84 | 104 | ||
| 85 | // ======================= CRM_CONTRACT 合同 ======================= | 105 | // ======================= CRM_CONTRACT 合同 ======================= |
| 86 | 106 | ||
| @@ -95,6 +115,8 @@ public interface LogRecordConstants { | @@ -95,6 +115,8 @@ public interface LogRecordConstants { | ||
| 95 | String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | 115 | String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; |
| 96 | String CRM_CONTRACT_SUBMIT_SUB_TYPE = "提交合同审批"; | 116 | String CRM_CONTRACT_SUBMIT_SUB_TYPE = "提交合同审批"; |
| 97 | String CRM_CONTRACT_SUBMIT_SUCCESS = "提交合同【{{#contractName}}】审批成功"; | 117 | String CRM_CONTRACT_SUBMIT_SUCCESS = "提交合同【{{#contractName}}】审批成功"; |
| 118 | + String CRM_CONTRACT_FOLLOW_UP_SUB_TYPE = "合同跟进"; | ||
| 119 | + String CRM_CONTRACT_FOLLOW_UP_SUCCESS = "合同跟进【{{#contractName}}】"; | ||
| 98 | 120 | ||
| 99 | // ======================= CRM_PRODUCT 产品 ======================= | 121 | // ======================= CRM_PRODUCT 产品 ======================= |
| 100 | 122 | ||
| @@ -125,6 +147,8 @@ public interface LogRecordConstants { | @@ -125,6 +147,8 @@ public interface LogRecordConstants { | ||
| 125 | String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款: {_DIFF{#updateReqVO}}"; | 147 | String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款: {_DIFF{#updateReqVO}}"; |
| 126 | String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; | 148 | String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; |
| 127 | String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; | 149 | String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; |
| 150 | + String CRM_RECEIVABLE_SUBMIT_SUB_TYPE = "提交回款审批"; | ||
| 151 | + String CRM_RECEIVABLE_SUBMIT_SUCCESS = "提交编号为【{{#receivableNo}}】的回款审批成功"; | ||
| 128 | 152 | ||
| 129 | // ======================= CRM_RECEIVABLE_PLAN 回款计划 ======================= | 153 | // ======================= CRM_RECEIVABLE_PLAN 回款计划 ======================= |
| 130 | 154 |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBizEndStatus.java renamed to yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java
| 1 | package cn.iocoder.yudao.module.crm.enums.business; | 1 | package cn.iocoder.yudao.module.crm.enums.business; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.util.ObjectUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | 3 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; |
| 5 | import lombok.Getter; | 4 | import lombok.Getter; |
| 6 | import lombok.RequiredArgsConstructor; | 5 | import lombok.RequiredArgsConstructor; |
| 7 | 6 | ||
| 8 | import java.util.Arrays; | 7 | import java.util.Arrays; |
| 9 | 8 | ||
| 10 | -// TODO @lzxhqs:1)title、description、create 可以删除,非标准的 javadoc 注释哈,然后可以在类上加下这个类的注释;2)CrmBizEndStatus 改成 CrmBusinessEndStatus,非必要不缩写哈,可阅读比较重要 | ||
| 11 | /** | 9 | /** |
| 10 | + * 商机的结束状态枚举 | ||
| 11 | + * | ||
| 12 | * @author lzxhqs | 12 | * @author lzxhqs |
| 13 | - * @version 1.0 | ||
| 14 | - * @title CrmBizEndStatus | ||
| 15 | - * @description | ||
| 16 | - * @create 2024/1/12 | ||
| 17 | */ | 13 | */ |
| 18 | @RequiredArgsConstructor | 14 | @RequiredArgsConstructor |
| 19 | @Getter | 15 | @Getter |
| 20 | -public enum CrmBizEndStatus implements IntArrayValuable { | 16 | +public enum CrmBusinessEndStatusEnum implements IntArrayValuable { |
| 21 | 17 | ||
| 22 | WIN(1, "赢单"), | 18 | WIN(1, "赢单"), |
| 23 | LOSE(2, "输单"), | 19 | LOSE(2, "输单"), |
| 24 | INVALID(3, "无效"); | 20 | INVALID(3, "无效"); |
| 25 | 21 | ||
| 26 | - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBizEndStatus::getStatus).toArray(); | ||
| 27 | - | ||
| 28 | - // TODO @lzxhqs:这里的方法,建议放到 49 行之后;一般类里是,静态变量,普通变量;静态方法;普通方法 | ||
| 29 | - public static boolean isWin(Integer status) { | ||
| 30 | - return ObjectUtil.equal(WIN.getStatus(), status); | ||
| 31 | - } | ||
| 32 | - | ||
| 33 | - public static boolean isLose(Integer status) { | ||
| 34 | - return ObjectUtil.equal(LOSE.getStatus(), status); | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | - public static boolean isInvalid(Integer status) { | ||
| 38 | - return ObjectUtil.equal(INVALID.getStatus(), status); | ||
| 39 | - } | 22 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBusinessEndStatusEnum::getStatus).toArray(); |
| 40 | 23 | ||
| 41 | /** | 24 | /** |
| 42 | * 场景类型 | 25 | * 场景类型 |
| @@ -52,4 +35,11 @@ public enum CrmBizEndStatus implements IntArrayValuable { | @@ -52,4 +35,11 @@ public enum CrmBizEndStatus implements IntArrayValuable { | ||
| 52 | return ARRAYS; | 35 | return ARRAYS; |
| 53 | } | 36 | } |
| 54 | 37 | ||
| 38 | + public static CrmBusinessEndStatusEnum fromStatus(Integer status) { | ||
| 39 | + return Arrays.stream(values()) | ||
| 40 | + .filter(value -> value.getStatus().equals(status)) | ||
| 41 | + .findFirst() | ||
| 42 | + .orElse(null); | ||
| 43 | + } | ||
| 44 | + | ||
| 55 | } | 45 | } |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java
| @@ -17,7 +17,7 @@ import java.util.Arrays; | @@ -17,7 +17,7 @@ import java.util.Arrays; | ||
| 17 | @Getter | 17 | @Getter |
| 18 | public enum CrmBizTypeEnum implements IntArrayValuable { | 18 | public enum CrmBizTypeEnum implements IntArrayValuable { |
| 19 | 19 | ||
| 20 | - CRM_LEADS(1, "线索"), | 20 | + CRM_CLUE(1, "线索"), |
| 21 | CRM_CUSTOMER(2, "客户"), | 21 | CRM_CUSTOMER(2, "客户"), |
| 22 | CRM_CONTACT(3, "联系人"), | 22 | CRM_CONTACT(3, "联系人"), |
| 23 | CRM_BUSINESS(4, "商机"), | 23 | CRM_BUSINESS(4, "商机"), |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java
| @@ -10,6 +10,8 @@ import java.util.Arrays; | @@ -10,6 +10,8 @@ import java.util.Arrays; | ||
| 10 | /** | 10 | /** |
| 11 | * CRM 数据权限级别枚举 | 11 | * CRM 数据权限级别枚举 |
| 12 | * | 12 | * |
| 13 | + * OWNER > WRITE > READ | ||
| 14 | + * | ||
| 13 | * @author HUIHUI | 15 | * @author HUIHUI |
| 14 | */ | 16 | */ |
| 15 | @Getter | 17 | @Getter |
| @@ -17,8 +19,8 @@ import java.util.Arrays; | @@ -17,8 +19,8 @@ import java.util.Arrays; | ||
| 17 | public enum CrmPermissionLevelEnum implements IntArrayValuable { | 19 | public enum CrmPermissionLevelEnum implements IntArrayValuable { |
| 18 | 20 | ||
| 19 | OWNER(1, "负责人"), | 21 | OWNER(1, "负责人"), |
| 20 | - READ(2, "读"), | ||
| 21 | - WRITE(3, "写"); | 22 | + READ(2, "只读"), |
| 23 | + WRITE(3, "读写"); | ||
| 22 | 24 | ||
| 23 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmPermissionLevelEnum::getLevel).toArray(); | 25 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmPermissionLevelEnum::getLevel).toArray(); |
| 24 | 26 |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.enums.receivable; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||
| 4 | +import lombok.AllArgsConstructor; | ||
| 5 | +import lombok.Getter; | ||
| 6 | + | ||
| 7 | +import java.util.Arrays; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * CRM 回款方式枚举 | ||
| 11 | + * | ||
| 12 | + * @author HUIHUI | ||
| 13 | + */ | ||
| 14 | +@Getter | ||
| 15 | +@AllArgsConstructor | ||
| 16 | +public enum CrmReceivableReturnTypeEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + CHECK(1, "支票"), | ||
| 19 | + CASH(2, "现金"), | ||
| 20 | + POSTAL_REMITTANCE(3, "邮政汇款"), | ||
| 21 | + TELEGRAPHIC_TRANSFER(4, "电汇"), | ||
| 22 | + ONLINE_TRANSFER(5, "网上转账"), | ||
| 23 | + ALIPAY(6, "支付宝"), | ||
| 24 | + WECHAT_PAY(7, "微信支付"), | ||
| 25 | + OTHER(8, "其它"); | ||
| 26 | + | ||
| 27 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReceivableReturnTypeEnum::getType).toArray(); | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 类型 | ||
| 31 | + */ | ||
| 32 | + private final Integer type; | ||
| 33 | + /** | ||
| 34 | + * 名称 | ||
| 35 | + */ | ||
| 36 | + private final String name; | ||
| 37 | + | ||
| 38 | + @Override | ||
| 39 | + public int[] array() { | ||
| 40 | + return ARRAYS; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/backlog/CrmBacklogController.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.backlog; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerRespVO; | ||
| 7 | -import cn.iocoder.yudao.module.crm.controller.admin.backlog.vo.CrmTodayCustomerPageReqVO; | ||
| 8 | -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | ||
| 9 | -import cn.iocoder.yudao.module.crm.service.message.CrmBacklogService; | ||
| 10 | -import io.swagger.v3.oas.annotations.Operation; | ||
| 11 | -import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 12 | -import jakarta.annotation.Resource; | ||
| 13 | -import jakarta.validation.Valid; | ||
| 14 | -import org.springframework.security.access.prepost.PreAuthorize; | ||
| 15 | -import org.springframework.validation.annotation.Validated; | ||
| 16 | -import org.springframework.web.bind.annotation.GetMapping; | ||
| 17 | -import org.springframework.web.bind.annotation.RequestMapping; | ||
| 18 | -import org.springframework.web.bind.annotation.RestController; | ||
| 19 | - | ||
| 20 | -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 21 | -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | ||
| 22 | - | ||
| 23 | -@Tag(name = "管理后台 - CRM待办消息") | ||
| 24 | -@RestController | ||
| 25 | -@RequestMapping("/crm/backlog") | ||
| 26 | -@Validated | ||
| 27 | -public class CrmBacklogController { | ||
| 28 | - | ||
| 29 | - @Resource | ||
| 30 | - private CrmBacklogService crmMessageService; | ||
| 31 | - | ||
| 32 | - // TODO 芋艿:未来可能合并到 CrmCustomerController | ||
| 33 | - @GetMapping("/today-customer-page") | ||
| 34 | - @Operation(summary = "今日需联系客户") | ||
| 35 | - @PreAuthorize("@ss.hasPermission('crm:customer:query')") | ||
| 36 | - public CommonResult<PageResult<CrmCustomerRespVO>> getTodayCustomerPage(@Valid CrmTodayCustomerPageReqVO pageReqVO) { | ||
| 37 | - PageResult<CrmCustomerDO> pageResult = crmMessageService.getTodayCustomerPage(pageReqVO, getLoginUserId()); | ||
| 38 | - return success(BeanUtils.toBean(pageResult, CrmCustomerRespVO.class)); | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | -} | ||
| 42 | \ No newline at end of file | 0 | \ No newline at end of file |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/backlog/vo/CrmTodayCustomerPageReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.backlog.vo; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | -import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 5 | -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; | ||
| 6 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 7 | -import lombok.Data; | ||
| 8 | -import lombok.EqualsAndHashCode; | ||
| 9 | -import lombok.ToString; | ||
| 10 | - | ||
| 11 | -@Schema(description = "管理后台 - 今日需联系客户 Request VO") | ||
| 12 | -@Data | ||
| 13 | -@EqualsAndHashCode(callSuper = true) | ||
| 14 | -@ToString(callSuper = true) | ||
| 15 | -public class CrmTodayCustomerPageReqVO extends PageParam { | ||
| 16 | - | ||
| 17 | - /** | ||
| 18 | - * 联系状态 - 今日需联系 | ||
| 19 | - */ | ||
| 20 | - public static final int CONTACT_TODAY = 1; | ||
| 21 | - /** | ||
| 22 | - * 联系状态 - 已逾期 | ||
| 23 | - */ | ||
| 24 | - public static final int CONTACT_EXPIRED = 2; | ||
| 25 | - /** | ||
| 26 | - * 联系状态 - 已联系 | ||
| 27 | - */ | ||
| 28 | - public static final int CONTACT_ALREADY = 3; | ||
| 29 | - | ||
| 30 | - @Schema(description = "联系状态", example = "1") | ||
| 31 | - private Integer contactStatus; | ||
| 32 | - | ||
| 33 | - @Schema(description = "场景类型", example = "1") | ||
| 34 | - @InEnum(CrmSceneTypeEnum.class) | ||
| 35 | - private Integer sceneType; | ||
| 36 | - | ||
| 37 | -} | ||
| 38 | \ No newline at end of file | 0 | \ No newline at end of file |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.http deleted
| 1 | -### 请求 /transfer | ||
| 2 | -PUT {{baseUrl}}/crm/business/transfer | ||
| 3 | -Content-Type: application/json | ||
| 4 | -Authorization: Bearer {{token}} | ||
| 5 | -tenant-id: {{adminTenentId}} | ||
| 6 | - | ||
| 7 | -{ | ||
| 8 | - "id": 1, | ||
| 9 | - "ownerUserId": 2, | ||
| 10 | - "transferType": 2, | ||
| 11 | - "permissionType": 2 | ||
| 12 | -} | ||
| 13 | - | ||
| 14 | -### 请求 /update | ||
| 15 | -PUT {{baseUrl}}/crm/business/update | ||
| 16 | -Content-Type: application/json | ||
| 17 | -Authorization: Bearer {{token}} | ||
| 18 | -tenant-id: {{adminTenentId}} | ||
| 19 | - | ||
| 20 | -{ | ||
| 21 | - "id": 1, | ||
| 22 | - "name": "2", | ||
| 23 | - "statusTypeId": 2, | ||
| 24 | - "statusId": 2, | ||
| 25 | - "customerId": 1 | ||
| 26 | -} | ||
| 27 | - | ||
| 28 | -### 请求 /get | ||
| 29 | -GET {{baseUrl}}/crm/business/get?id=1024 | ||
| 30 | -Content-Type: application/json | ||
| 31 | -Authorization: Bearer {{token}} | ||
| 32 | -tenant-id: {{adminTenentId}} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
| @@ -3,22 +3,26 @@ package cn.iocoder.yudao.module.crm.controller.admin.business; | @@ -3,22 +3,26 @@ package cn.iocoder.yudao.module.crm.controller.admin.business; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 7 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 9 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 8 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 10 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 9 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; | ||
| 10 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; | ||
| 11 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; | ||
| 12 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; | ||
| 13 | -import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert; | 11 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.*; |
| 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; | 12 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; |
| 13 | +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; | ||
| 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; | 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; |
| 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; | 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; |
| 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 17 | +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; | ||
| 18 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; | 18 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; |
| 19 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; | 19 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; |
| 20 | -import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusTypeService; | ||
| 21 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | 20 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 21 | +import cn.iocoder.yudao.module.crm.service.product.CrmProductService; | ||
| 22 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 23 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 24 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 25 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 22 | import io.swagger.v3.oas.annotations.Operation; | 26 | import io.swagger.v3.oas.annotations.Operation; |
| 23 | import io.swagger.v3.oas.annotations.Parameter; | 27 | import io.swagger.v3.oas.annotations.Parameter; |
| 24 | import io.swagger.v3.oas.annotations.tags.Tag; | 28 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -30,13 +34,15 @@ import org.springframework.validation.annotation.Validated; | @@ -30,13 +34,15 @@ import org.springframework.validation.annotation.Validated; | ||
| 30 | import org.springframework.web.bind.annotation.*; | 34 | import org.springframework.web.bind.annotation.*; |
| 31 | 35 | ||
| 32 | import java.io.IOException; | 36 | import java.io.IOException; |
| 37 | +import java.util.Collections; | ||
| 33 | import java.util.List; | 38 | import java.util.List; |
| 39 | +import java.util.Map; | ||
| 40 | +import java.util.stream.Stream; | ||
| 34 | 41 | ||
| 35 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 42 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 36 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 43 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 37 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | 44 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 38 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 39 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 45 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 40 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 46 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 41 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 47 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 42 | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; | 48 | import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; |
| @@ -52,9 +58,16 @@ public class CrmBusinessController { | @@ -52,9 +58,16 @@ public class CrmBusinessController { | ||
| 52 | @Resource | 58 | @Resource |
| 53 | private CrmCustomerService customerService; | 59 | private CrmCustomerService customerService; |
| 54 | @Resource | 60 | @Resource |
| 55 | - private CrmBusinessStatusTypeService businessStatusTypeService; | 61 | + private CrmBusinessStatusService businessStatusTypeService; |
| 56 | @Resource | 62 | @Resource |
| 57 | private CrmBusinessStatusService businessStatusService; | 63 | private CrmBusinessStatusService businessStatusService; |
| 64 | + @Resource | ||
| 65 | + private CrmProductService productService; | ||
| 66 | + | ||
| 67 | + @Resource | ||
| 68 | + private AdminUserApi adminUserApi; | ||
| 69 | + @Resource | ||
| 70 | + private DeptApi deptApi; | ||
| 58 | 71 | ||
| 59 | @PostMapping("/create") | 72 | @PostMapping("/create") |
| 60 | @Operation(summary = "创建商机") | 73 | @Operation(summary = "创建商机") |
| @@ -71,6 +84,14 @@ public class CrmBusinessController { | @@ -71,6 +84,14 @@ public class CrmBusinessController { | ||
| 71 | return success(true); | 84 | return success(true); |
| 72 | } | 85 | } |
| 73 | 86 | ||
| 87 | + @PutMapping("/update-status") | ||
| 88 | + @Operation(summary = "更新商机状态") | ||
| 89 | + @PreAuthorize("@ss.hasPermission('crm:business:update')") | ||
| 90 | + public CommonResult<Boolean> updateBusinessStatus(@Valid @RequestBody CrmBusinessUpdateStatusReqVO updateStatusReqVO) { | ||
| 91 | + businessService.updateBusinessStatus(updateStatusReqVO); | ||
| 92 | + return success(true); | ||
| 93 | + } | ||
| 94 | + | ||
| 74 | @DeleteMapping("/delete") | 95 | @DeleteMapping("/delete") |
| 75 | @Operation(summary = "删除商机") | 96 | @Operation(summary = "删除商机") |
| 76 | @Parameter(name = "id", description = "编号", required = true) | 97 | @Parameter(name = "id", description = "编号", required = true) |
| @@ -86,15 +107,23 @@ public class CrmBusinessController { | @@ -86,15 +107,23 @@ public class CrmBusinessController { | ||
| 86 | @PreAuthorize("@ss.hasPermission('crm:business:query')") | 107 | @PreAuthorize("@ss.hasPermission('crm:business:query')") |
| 87 | public CommonResult<CrmBusinessRespVO> getBusiness(@RequestParam("id") Long id) { | 108 | public CommonResult<CrmBusinessRespVO> getBusiness(@RequestParam("id") Long id) { |
| 88 | CrmBusinessDO business = businessService.getBusiness(id); | 109 | CrmBusinessDO business = businessService.getBusiness(id); |
| 89 | - return success(BeanUtils.toBean(business, CrmBusinessRespVO.class)); | 110 | + return success(buildBusinessDetail(business)); |
| 90 | } | 111 | } |
| 91 | 112 | ||
| 92 | - @GetMapping("/list-by-ids") | ||
| 93 | - @Operation(summary = "获得商机列表") | ||
| 94 | - @Parameter(name = "ids", description = "编号", required = true, example = "[1024]") | ||
| 95 | - @PreAuthorize("@ss.hasPermission('crm:business:query')") | ||
| 96 | - public CommonResult<List<CrmBusinessRespVO>> getContactListByIds(@RequestParam("ids") List<Long> ids) { | ||
| 97 | - return success(BeanUtils.toBean(businessService.getBusinessList(ids, getLoginUserId()), CrmBusinessRespVO.class)); | 113 | + private CrmBusinessRespVO buildBusinessDetail(CrmBusinessDO business) { |
| 114 | + if (business == null) { | ||
| 115 | + return null; | ||
| 116 | + } | ||
| 117 | + CrmBusinessRespVO businessVO = buildBusinessDetailList(Collections.singletonList(business)).get(0); | ||
| 118 | + // 拼接产品项 | ||
| 119 | + List<CrmBusinessProductDO> businessProducts = businessService.getBusinessProductListByBusinessId(businessVO.getId()); | ||
| 120 | + Map<Long, CrmProductDO> productMap = productService.getProductMap( | ||
| 121 | + convertSet(businessProducts, CrmBusinessProductDO::getProductId)); | ||
| 122 | + businessVO.setProducts(BeanUtils.toBean(businessProducts, CrmBusinessRespVO.Product.class, businessProductVO -> | ||
| 123 | + MapUtils.findAndThen(productMap, businessProductVO.getProductId(), | ||
| 124 | + product -> businessProductVO.setProductName(product.getName()) | ||
| 125 | + .setProductNo(product.getNo()).setProductUnit(product.getUnit())))); | ||
| 126 | + return businessVO; | ||
| 98 | } | 127 | } |
| 99 | 128 | ||
| 100 | @GetMapping("/simple-all-list") | 129 | @GetMapping("/simple-all-list") |
| @@ -105,7 +134,8 @@ public class CrmBusinessController { | @@ -105,7 +134,8 @@ public class CrmBusinessController { | ||
| 105 | reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 | 134 | reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 |
| 106 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(reqVO, getLoginUserId()); | 135 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(reqVO, getLoginUserId()); |
| 107 | return success(convertList(pageResult.getList(), business -> // 只返回 id、name 字段 | 136 | return success(convertList(pageResult.getList(), business -> // 只返回 id、name 字段 |
| 108 | - new CrmBusinessRespVO().setId(business.getId()).setName(business.getName()))); | 137 | + new CrmBusinessRespVO().setId(business.getId()).setName(business.getName()) |
| 138 | + .setCustomerId(business.getCustomerId()))); | ||
| 109 | } | 139 | } |
| 110 | 140 | ||
| 111 | @GetMapping("/page") | 141 | @GetMapping("/page") |
| @@ -113,7 +143,7 @@ public class CrmBusinessController { | @@ -113,7 +143,7 @@ public class CrmBusinessController { | ||
| 113 | @PreAuthorize("@ss.hasPermission('crm:business:query')") | 143 | @PreAuthorize("@ss.hasPermission('crm:business:query')") |
| 114 | public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { | 144 | public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { |
| 115 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(pageVO, getLoginUserId()); | 145 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(pageVO, getLoginUserId()); |
| 116 | - return success(buildBusinessDetailPageResult(pageResult)); | 146 | + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); |
| 117 | } | 147 | } |
| 118 | 148 | ||
| 119 | @GetMapping("/page-by-customer") | 149 | @GetMapping("/page-by-customer") |
| @@ -123,7 +153,7 @@ public class CrmBusinessController { | @@ -123,7 +153,7 @@ public class CrmBusinessController { | ||
| 123 | throw exception(CUSTOMER_NOT_EXISTS); | 153 | throw exception(CUSTOMER_NOT_EXISTS); |
| 124 | } | 154 | } |
| 125 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByCustomerId(pageReqVO); | 155 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByCustomerId(pageReqVO); |
| 126 | - return success(buildBusinessDetailPageResult(pageResult)); | 156 | + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); |
| 127 | } | 157 | } |
| 128 | 158 | ||
| 129 | @GetMapping("/page-by-contact") | 159 | @GetMapping("/page-by-contact") |
| @@ -131,7 +161,7 @@ public class CrmBusinessController { | @@ -131,7 +161,7 @@ public class CrmBusinessController { | ||
| 131 | @PreAuthorize("@ss.hasPermission('crm:business:query')") | 161 | @PreAuthorize("@ss.hasPermission('crm:business:query')") |
| 132 | public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) { | 162 | public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) { |
| 133 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByContact(pageReqVO); | 163 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByContact(pageReqVO); |
| 134 | - return success(buildBusinessDetailPageResult(pageResult)); | 164 | + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); |
| 135 | } | 165 | } |
| 136 | 166 | ||
| 137 | @GetMapping("/export-excel") | 167 | @GetMapping("/export-excel") |
| @@ -141,29 +171,44 @@ public class CrmBusinessController { | @@ -141,29 +171,44 @@ public class CrmBusinessController { | ||
| 141 | public void exportBusinessExcel(@Valid CrmBusinessPageReqVO exportReqVO, | 171 | public void exportBusinessExcel(@Valid CrmBusinessPageReqVO exportReqVO, |
| 142 | HttpServletResponse response) throws IOException { | 172 | HttpServletResponse response) throws IOException { |
| 143 | exportReqVO.setPageSize(PAGE_SIZE_NONE); | 173 | exportReqVO.setPageSize(PAGE_SIZE_NONE); |
| 144 | - PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(exportReqVO, getLoginUserId()); | 174 | + List<CrmBusinessDO> list = businessService.getBusinessPage(exportReqVO, getLoginUserId()).getList(); |
| 145 | // 导出 Excel | 175 | // 导出 Excel |
| 146 | ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessRespVO.class, | 176 | ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessRespVO.class, |
| 147 | - buildBusinessDetailPageResult(pageResult).getList()); | 177 | + buildBusinessDetailList(list)); |
| 148 | } | 178 | } |
| 149 | 179 | ||
| 150 | - /** | ||
| 151 | - * 构建详细的商机分页结果 | ||
| 152 | - * | ||
| 153 | - * @param pageResult 简单的商机分页结果 | ||
| 154 | - * @return 详细的商机分页结果 | ||
| 155 | - */ | ||
| 156 | - private PageResult<CrmBusinessRespVO> buildBusinessDetailPageResult(PageResult<CrmBusinessDO> pageResult) { | ||
| 157 | - if (CollUtil.isEmpty(pageResult.getList())) { | ||
| 158 | - return PageResult.empty(pageResult.getTotal()); | 180 | + private List<CrmBusinessRespVO> buildBusinessDetailList(List<CrmBusinessDO> list) { |
| 181 | + if (CollUtil.isEmpty(list)) { | ||
| 182 | + return Collections.emptyList(); | ||
| 159 | } | 183 | } |
| 160 | - List<CrmBusinessStatusTypeDO> statusTypeList = businessStatusTypeService.getBusinessStatusTypeList( | ||
| 161 | - convertSet(pageResult.getList(), CrmBusinessDO::getStatusTypeId)); | ||
| 162 | - List<CrmBusinessStatusDO> statusList = businessStatusService.getBusinessStatusList( | ||
| 163 | - convertSet(pageResult.getList(), CrmBusinessDO::getStatusId)); | ||
| 164 | - List<CrmCustomerDO> customerList = customerService.getCustomerList( | ||
| 165 | - convertSet(pageResult.getList(), CrmBusinessDO::getCustomerId)); | ||
| 166 | - return CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList); | 184 | + // 1.1 获取客户列表 |
| 185 | + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap( | ||
| 186 | + convertSet(list, CrmBusinessDO::getCustomerId)); | ||
| 187 | + // 1.2 获取创建人、负责人列表 | ||
| 188 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(list, | ||
| 189 | + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | ||
| 190 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||
| 191 | + // 1.3 获得商机状态组 | ||
| 192 | + Map<Long, CrmBusinessStatusTypeDO> statusTypeMap = businessStatusTypeService.getBusinessStatusTypeMap( | ||
| 193 | + convertSet(list, CrmBusinessDO::getStatusTypeId)); | ||
| 194 | + Map<Long, CrmBusinessStatusDO> statusMap = businessStatusService.getBusinessStatusMap( | ||
| 195 | + convertSet(list, CrmBusinessDO::getStatusId)); | ||
| 196 | + // 2. 拼接数据 | ||
| 197 | + return BeanUtils.toBean(list, CrmBusinessRespVO.class, businessVO -> { | ||
| 198 | + // 2.1 设置客户名称 | ||
| 199 | + MapUtils.findAndThen(customerMap, businessVO.getCustomerId(), customer -> businessVO.setCustomerName(customer.getName())); | ||
| 200 | + // 2.2 设置创建人、负责人名称 | ||
| 201 | + MapUtils.findAndThen(userMap, NumberUtils.parseLong(businessVO.getCreator()), | ||
| 202 | + user -> businessVO.setCreatorName(user.getNickname())); | ||
| 203 | + MapUtils.findAndThen(userMap, businessVO.getOwnerUserId(), user -> { | ||
| 204 | + businessVO.setOwnerUserName(user.getNickname()); | ||
| 205 | + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> businessVO.setOwnerUserDeptName(dept.getName())); | ||
| 206 | + }); | ||
| 207 | + // 2.3 设置商机状态 | ||
| 208 | + MapUtils.findAndThen(statusTypeMap, businessVO.getStatusTypeId(), statusType -> businessVO.setStatusTypeName(statusType.getName())); | ||
| 209 | + MapUtils.findAndThen(statusMap, businessVO.getStatusId(), status -> businessVO.setStatusName( | ||
| 210 | + businessService.getBusinessStatusName(businessVO.getEndStatus(), status))); | ||
| 211 | + }); | ||
| 167 | } | 212 | } |
| 168 | 213 | ||
| 169 | @PutMapping("/transfer") | 214 | @PutMapping("/transfer") |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.business; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||
| 8 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 9 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusRespVO; | ||
| 10 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; | ||
| 11 | +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; | ||
| 12 | +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; | ||
| 13 | +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; | ||
| 14 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 15 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 16 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 17 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 18 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 19 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 20 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 21 | +import jakarta.annotation.Resource; | ||
| 22 | +import jakarta.validation.Valid; | ||
| 23 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 24 | +import org.springframework.validation.annotation.Validated; | ||
| 25 | +import org.springframework.web.bind.annotation.*; | ||
| 26 | + | ||
| 27 | +import java.util.Collection; | ||
| 28 | +import java.util.List; | ||
| 29 | +import java.util.Map; | ||
| 30 | + | ||
| 31 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 32 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||
| 33 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | ||
| 34 | + | ||
| 35 | +@Tag(name = "管理后台 - CRM 商机状态") | ||
| 36 | +@RestController | ||
| 37 | +@RequestMapping("/crm/business-status") | ||
| 38 | +@Validated | ||
| 39 | +public class CrmBusinessStatusController { | ||
| 40 | + | ||
| 41 | + @Resource | ||
| 42 | + private CrmBusinessStatusService businessStatusTypeService; | ||
| 43 | + | ||
| 44 | + @Resource | ||
| 45 | + private AdminUserApi adminUserApi; | ||
| 46 | + @Resource | ||
| 47 | + private DeptApi deptApi; | ||
| 48 | + | ||
| 49 | + @PostMapping("/create") | ||
| 50 | + @Operation(summary = "创建商机状态") | ||
| 51 | + @PreAuthorize("@ss.hasPermission('crm:business-status:create')") | ||
| 52 | + public CommonResult<Long> createBusinessStatus(@Valid @RequestBody CrmBusinessStatusSaveReqVO createReqVO) { | ||
| 53 | + return success(businessStatusTypeService.createBusinessStatus(createReqVO)); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + @PutMapping("/update") | ||
| 57 | + @Operation(summary = "更新商机状态") | ||
| 58 | + @PreAuthorize("@ss.hasPermission('crm:business-status:update')") | ||
| 59 | + public CommonResult<Boolean> updateBusinessStatus(@Valid @RequestBody CrmBusinessStatusSaveReqVO updateReqVO) { | ||
| 60 | + businessStatusTypeService.updateBusinessStatus(updateReqVO); | ||
| 61 | + return success(true); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + @DeleteMapping("/delete") | ||
| 65 | + @Operation(summary = "删除商机状态") | ||
| 66 | + @Parameter(name = "id", description = "编号", required = true) | ||
| 67 | + @PreAuthorize("@ss.hasPermission('crm:business-status:delete')") | ||
| 68 | + public CommonResult<Boolean> deleteBusinessStatusType(@RequestParam("id") Long id) { | ||
| 69 | + businessStatusTypeService.deleteBusinessStatusType(id); | ||
| 70 | + return success(true); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @GetMapping("/get") | ||
| 74 | + @Operation(summary = "获得商机状态") | ||
| 75 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 76 | + @PreAuthorize("@ss.hasPermission('crm:business-status:query')") | ||
| 77 | + public CommonResult<CrmBusinessStatusRespVO> getBusinessStatusType(@RequestParam("id") Long id) { | ||
| 78 | + CrmBusinessStatusTypeDO statusType = businessStatusTypeService.getBusinessStatusType(id); | ||
| 79 | + if (statusType == null) { | ||
| 80 | + return success(null); | ||
| 81 | + } | ||
| 82 | + List<CrmBusinessStatusDO> statuses = businessStatusTypeService.getBusinessStatusListByTypeId(id); | ||
| 83 | + return success(BeanUtils.toBean(statusType, CrmBusinessStatusRespVO.class, | ||
| 84 | + statusTypeVO -> statusTypeVO.setStatuses(BeanUtils.toBean(statuses, CrmBusinessStatusRespVO.Status.class)))); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + @GetMapping("/page") | ||
| 88 | + @Operation(summary = "获得商机状态分页") | ||
| 89 | + @PreAuthorize("@ss.hasPermission('crm:business-status:query')") | ||
| 90 | + public CommonResult<PageResult<CrmBusinessStatusRespVO>> getBusinessStatusPage(@Valid PageParam pageReqVO) { | ||
| 91 | + // 1. 查询数据 | ||
| 92 | + PageResult<CrmBusinessStatusTypeDO> pageResult = businessStatusTypeService.getBusinessStatusTypePage(pageReqVO); | ||
| 93 | + if (CollUtil.isEmpty(pageResult.getList())) { | ||
| 94 | + return success(PageResult.empty(pageResult.getTotal())); | ||
| 95 | + } | ||
| 96 | + // 2. 拼接数据 | ||
| 97 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 98 | + convertSet(pageResult.getList(), statusType -> Long.parseLong(statusType.getCreator()))); | ||
| 99 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( | ||
| 100 | + convertSetByFlatMap(pageResult.getList(), CrmBusinessStatusTypeDO::getDeptIds, Collection::stream)); | ||
| 101 | + return success(BeanUtils.toBean(pageResult, CrmBusinessStatusRespVO.class, statusTypeVO -> { | ||
| 102 | + statusTypeVO.setCreator(userMap.get(NumberUtils.parseLong(statusTypeVO.getCreator())).getNickname()); | ||
| 103 | + statusTypeVO.setDeptNames(convertList(statusTypeVO.getDeptIds(), | ||
| 104 | + deptId -> deptMap.containsKey(deptId) ? deptMap.get(deptId).getName() : null)); | ||
| 105 | + })); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + @GetMapping("/type-simple-list") | ||
| 109 | + @Operation(summary = "获得商机状态组列表") | ||
| 110 | + public CommonResult<List<CrmBusinessStatusRespVO>> getBusinessStatusTypeSimpleList() { | ||
| 111 | + List<CrmBusinessStatusTypeDO> list = businessStatusTypeService.getBusinessStatusTypeList(); | ||
| 112 | + // 过滤掉部门不匹配的 | ||
| 113 | + Long deptId = adminUserApi.getUser(getLoginUserId()).getDeptId(); | ||
| 114 | + list.removeIf(statusType -> CollUtil.isNotEmpty(statusType.getDeptIds()) && !statusType.getDeptIds().contains(deptId)); | ||
| 115 | + return success(BeanUtils.toBean(list, CrmBusinessStatusRespVO.class)); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + @GetMapping("/status-simple-list") | ||
| 119 | + @Operation(summary = "获得商机状态列表") | ||
| 120 | + @Parameter(name = "typeId", description = "商机状态组", required = true, example = "1024") | ||
| 121 | + public CommonResult<List<CrmBusinessStatusRespVO.Status>> getBusinessStatusSimpleList(@RequestParam("typeId") Long typeId) { | ||
| 122 | + List<CrmBusinessStatusDO> list = businessStatusTypeService.getBusinessStatusListByTypeId(typeId); | ||
| 123 | + return success(BeanUtils.toBean(list, CrmBusinessStatusRespVO.Status.class)); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusTypeController.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 5 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 6 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 7 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 8 | -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 9 | -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | ||
| 10 | -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | ||
| 11 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusQueryVO; | ||
| 12 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusRespVO; | ||
| 13 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypePageReqVO; | ||
| 14 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeQueryVO; | ||
| 15 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeRespVO; | ||
| 16 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeSaveReqVO; | ||
| 17 | -import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessStatusConvert; | ||
| 18 | -import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessStatusTypeConvert; | ||
| 19 | -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; | ||
| 20 | -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; | ||
| 21 | -import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; | ||
| 22 | -import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusTypeService; | ||
| 23 | -import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 24 | -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 25 | -import io.swagger.v3.oas.annotations.Operation; | ||
| 26 | -import io.swagger.v3.oas.annotations.Parameter; | ||
| 27 | -import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 28 | -import jakarta.annotation.Resource; | ||
| 29 | -import jakarta.servlet.http.HttpServletResponse; | ||
| 30 | -import jakarta.validation.Valid; | ||
| 31 | -import org.springframework.security.access.prepost.PreAuthorize; | ||
| 32 | -import org.springframework.validation.annotation.Validated; | ||
| 33 | -import org.springframework.web.bind.annotation.*; | ||
| 34 | - | ||
| 35 | -import java.io.IOException; | ||
| 36 | -import java.util.Collection; | ||
| 37 | -import java.util.List; | ||
| 38 | -import java.util.Set; | ||
| 39 | - | ||
| 40 | -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 41 | -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | ||
| 42 | - | ||
| 43 | -@Tag(name = "管理后台 - CRM 商机状态类型") | ||
| 44 | -@RestController | ||
| 45 | -@RequestMapping("/crm/business-status-type") | ||
| 46 | -@Validated | ||
| 47 | -public class CrmBusinessStatusTypeController { | ||
| 48 | - | ||
| 49 | - @Resource | ||
| 50 | - private CrmBusinessStatusTypeService businessStatusTypeService; | ||
| 51 | - | ||
| 52 | - @Resource | ||
| 53 | - private CrmBusinessStatusService businessStatusService; | ||
| 54 | - | ||
| 55 | - @Resource | ||
| 56 | - private DeptApi deptApi; | ||
| 57 | - | ||
| 58 | - @PostMapping("/create") | ||
| 59 | - @Operation(summary = "创建商机状态类型") | ||
| 60 | - @PreAuthorize("@ss.hasPermission('crm:business-status-type:create')") | ||
| 61 | - public CommonResult<Long> createBusinessStatusType(@Valid @RequestBody CrmBusinessStatusTypeSaveReqVO createReqVO) { | ||
| 62 | - return success(businessStatusTypeService.createBusinessStatusType(createReqVO)); | ||
| 63 | - } | ||
| 64 | - | ||
| 65 | - @PutMapping("/update") | ||
| 66 | - @Operation(summary = "更新商机状态类型") | ||
| 67 | - @PreAuthorize("@ss.hasPermission('crm:business-status-type:update')") | ||
| 68 | - public CommonResult<Boolean> updateBusinessStatusType(@Valid @RequestBody CrmBusinessStatusTypeSaveReqVO updateReqVO) { | ||
| 69 | - businessStatusTypeService.updateBusinessStatusType(updateReqVO); | ||
| 70 | - return success(true); | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - @DeleteMapping("/delete") | ||
| 74 | - @Operation(summary = "删除商机状态类型") | ||
| 75 | - @Parameter(name = "id", description = "编号", required = true) | ||
| 76 | - @PreAuthorize("@ss.hasPermission('crm:business-status-type:delete')") | ||
| 77 | - public CommonResult<Boolean> deleteBusinessStatusType(@RequestParam("id") Long id) { | ||
| 78 | - businessStatusTypeService.deleteBusinessStatusType(id); | ||
| 79 | - return success(true); | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - @GetMapping("/get") | ||
| 83 | - @Operation(summary = "获得商机状态类型") | ||
| 84 | - @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 85 | - @PreAuthorize("@ss.hasPermission('crm:business-status-type:query')") | ||
| 86 | - public CommonResult<CrmBusinessStatusTypeRespVO> getBusinessStatusType(@RequestParam("id") Long id) { | ||
| 87 | - CrmBusinessStatusTypeDO statusType = businessStatusTypeService.getBusinessStatusType(id); | ||
| 88 | - // 处理状态回显 | ||
| 89 | - // TODO @lzxhqs:可以在 businessStatusService 加个 getBusinessStatusListByTypeId 方法,直接返回 List<CrmBusinessStatusDO> 哈,常用的,尽量封装个简单易懂的方法,不用追求绝对通用哈; | ||
| 90 | - CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO(); | ||
| 91 | - queryVO.setTypeId(id); | ||
| 92 | - List<CrmBusinessStatusDO> statusList = businessStatusService.selectList(queryVO); | ||
| 93 | - return success(CrmBusinessStatusTypeConvert.INSTANCE.convert(statusType, statusList)); | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - @GetMapping("/page") | ||
| 97 | - @Operation(summary = "获得商机状态类型分页") | ||
| 98 | - @PreAuthorize("@ss.hasPermission('crm:business-status-type:query')") | ||
| 99 | - public CommonResult<PageResult<CrmBusinessStatusTypeRespVO>> getBusinessStatusTypePage(@Valid CrmBusinessStatusTypePageReqVO pageReqVO) { | ||
| 100 | - PageResult<CrmBusinessStatusTypeDO> pageResult = businessStatusTypeService.getBusinessStatusTypePage(pageReqVO); | ||
| 101 | - // 处理部门回显 | ||
| 102 | - Set<Long> deptIds = CollectionUtils.convertSetByFlatMap(pageResult.getList(), CrmBusinessStatusTypeDO::getDeptIds,Collection::stream); | ||
| 103 | - List<DeptRespDTO> deptList = deptApi.getDeptList(deptIds); | ||
| 104 | - return success(CrmBusinessStatusTypeConvert.INSTANCE.convertPage(pageResult, deptList)); | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - @GetMapping("/export-excel") | ||
| 108 | - @Operation(summary = "导出商机状态类型 Excel") | ||
| 109 | - @PreAuthorize("@ss.hasPermission('crm:business-status-type:export')") | ||
| 110 | - @OperateLog(type = EXPORT) | ||
| 111 | - public void exportBusinessStatusTypeExcel(@Valid CrmBusinessStatusTypePageReqVO pageReqVO, | ||
| 112 | - HttpServletResponse response) throws IOException { | ||
| 113 | - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | ||
| 114 | - List<CrmBusinessStatusTypeDO> list = businessStatusTypeService.getBusinessStatusTypePage(pageReqVO).getList(); | ||
| 115 | - // 导出 Excel | ||
| 116 | - ExcelUtils.write(response, "商机状态类型.xls", "数据", CrmBusinessStatusTypeRespVO.class, | ||
| 117 | - BeanUtils.toBean(list, CrmBusinessStatusTypeRespVO.class)); | ||
| 118 | - } | ||
| 119 | - | ||
| 120 | - @GetMapping("/get-simple-list") | ||
| 121 | - @Operation(summary = "获得商机状态类型列表") | ||
| 122 | - @PreAuthorize("@ss.hasPermission('crm:business-status-type:query')") | ||
| 123 | - public CommonResult<List<CrmBusinessStatusTypeRespVO>> getBusinessStatusTypeList() { | ||
| 124 | - CrmBusinessStatusTypeQueryVO queryVO = new CrmBusinessStatusTypeQueryVO(); | ||
| 125 | - queryVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | ||
| 126 | - List<CrmBusinessStatusTypeDO> list = businessStatusTypeService.selectList(queryVO); | ||
| 127 | - return success(BeanUtils.toBean(list, CrmBusinessStatusTypeRespVO.class)); | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - // TODO @ljlleo 这个接口,是不是可以和 getBusinessStatusTypeList 合并成一个? | ||
| 131 | - @GetMapping("/get-status-list") | ||
| 132 | - @Operation(summary = "获得商机状态列表") | ||
| 133 | - @PreAuthorize("@ss.hasPermission('crm:business-status:query')") | ||
| 134 | - public CommonResult<List<CrmBusinessStatusRespVO>> getBusinessStatusListByTypeId(@RequestParam("typeId") Long typeId) { | ||
| 135 | - CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO(); | ||
| 136 | - queryVO.setTypeId(typeId); | ||
| 137 | - List<CrmBusinessStatusDO> list = businessStatusService.selectList(queryVO); | ||
| 138 | - return success(CrmBusinessStatusConvert.INSTANCE.convertList(list)); | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessExcelVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; | ||
| 2 | - | ||
| 3 | -import com.alibaba.excel.annotation.ExcelProperty; | ||
| 4 | -import lombok.Data; | ||
| 5 | - | ||
| 6 | -import java.math.BigDecimal; | ||
| 7 | -import java.time.LocalDateTime; | ||
| 8 | -import java.util.Set; | ||
| 9 | - | ||
| 10 | -/** | ||
| 11 | - * 商机 Excel VO | ||
| 12 | - * | ||
| 13 | - * @author ljlleo | ||
| 14 | - */ | ||
| 15 | -@Data | ||
| 16 | -public class CrmBusinessExcelVO { | ||
| 17 | - | ||
| 18 | - @ExcelProperty("主键") | ||
| 19 | - private Long id; | ||
| 20 | - | ||
| 21 | - @ExcelProperty("商机名称") | ||
| 22 | - private String name; | ||
| 23 | - | ||
| 24 | - @ExcelProperty("商机状态类型编号") | ||
| 25 | - private Long statusTypeId; | ||
| 26 | - | ||
| 27 | - @ExcelProperty("商机状态编号") | ||
| 28 | - private Long statusId; | ||
| 29 | - | ||
| 30 | - @ExcelProperty("下次联系时间") | ||
| 31 | - private LocalDateTime contactNextTime; | ||
| 32 | - | ||
| 33 | - @ExcelProperty("客户编号") | ||
| 34 | - private Long customerId; | ||
| 35 | - | ||
| 36 | - @ExcelProperty("预计成交日期") | ||
| 37 | - private LocalDateTime dealTime; | ||
| 38 | - | ||
| 39 | - @ExcelProperty("商机金额") | ||
| 40 | - private BigDecimal price; | ||
| 41 | - | ||
| 42 | - @ExcelProperty("整单折扣") | ||
| 43 | - private BigDecimal discountPercent; | ||
| 44 | - | ||
| 45 | - @ExcelProperty("产品总金额") | ||
| 46 | - private BigDecimal productPrice; | ||
| 47 | - | ||
| 48 | - @ExcelProperty("备注") | ||
| 49 | - private String remark; | ||
| 50 | - | ||
| 51 | - @ExcelProperty("负责人的用户编号") | ||
| 52 | - private Long ownerUserId; | ||
| 53 | - | ||
| 54 | - @ExcelProperty("创建时间") | ||
| 55 | - private LocalDateTime createTime; | ||
| 56 | - | ||
| 57 | - @ExcelProperty("只读权限的用户编号数组") | ||
| 58 | - private Set<Long> roUserIds; | ||
| 59 | - | ||
| 60 | - @ExcelProperty("读写权限的用户编号数组") | ||
| 61 | - private Set<Long> rwUserIds; | ||
| 62 | - | ||
| 63 | - @ExcelProperty("1赢单2输单3无效") | ||
| 64 | - private Integer endStatus; | ||
| 65 | - | ||
| 66 | - @ExcelProperty("结束时的备注") | ||
| 67 | - private String endRemark; | ||
| 68 | - | ||
| 69 | - @ExcelProperty("最后跟进时间") | ||
| 70 | - private LocalDateTime contactLastTime; | ||
| 71 | - | ||
| 72 | - @ExcelProperty("跟进状态") | ||
| 73 | - private Integer followUpStatus; | ||
| 74 | - | ||
| 75 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; |
| 2 | 2 | ||
| 3 | +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | ||
| 4 | +import com.alibaba.excel.annotation.ExcelProperty; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import jakarta.validation.constraints.NotNull; | 6 | +import lombok.AllArgsConstructor; |
| 5 | import lombok.Data; | 7 | import lombok.Data; |
| 6 | -import org.springframework.format.annotation.DateTimeFormat; | 8 | +import lombok.NoArgsConstructor; |
| 7 | 9 | ||
| 8 | import java.math.BigDecimal; | 10 | import java.math.BigDecimal; |
| 9 | import java.time.LocalDateTime; | 11 | import java.time.LocalDateTime; |
| 12 | +import java.util.List; | ||
| 10 | 13 | ||
| 11 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 12 | - | ||
| 13 | -@Schema(description = "管理后台 - 商机 Response VO") | 14 | +@Schema(description = "管理后台 - CRM 商机 Response VO") |
| 14 | @Data | 15 | @Data |
| 16 | +@ExcelIgnoreUnannotated | ||
| 15 | public class CrmBusinessRespVO { | 17 | public class CrmBusinessRespVO { |
| 16 | 18 | ||
| 17 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") | 19 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") |
| 20 | + @ExcelProperty("编号") | ||
| 18 | private Long id; | 21 | private Long id; |
| 19 | 22 | ||
| 20 | @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | 23 | @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") |
| 21 | - @NotNull(message = "商机名称不能为空") | 24 | + @ExcelProperty("商机名称") |
| 22 | private String name; | 25 | private String name; |
| 23 | 26 | ||
| 24 | - @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") | ||
| 25 | - @NotNull(message = "商机状态类型不能为空") | 27 | + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") |
| 28 | + private Long customerId; | ||
| 29 | + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 30 | + @ExcelProperty("客户名称") | ||
| 31 | + private String customerName; | ||
| 32 | + | ||
| 33 | + @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example ="true") | ||
| 34 | + @ExcelProperty("跟进状态") | ||
| 35 | + private Boolean followUpStatus; | ||
| 36 | + | ||
| 37 | + @Schema(description = "最后跟进时间") | ||
| 38 | + @ExcelProperty("最后跟进时间") | ||
| 39 | + private LocalDateTime contactLastTime; | ||
| 40 | + | ||
| 41 | + @Schema(description = "下次联系时间") | ||
| 42 | + @ExcelProperty("下次联系时间") | ||
| 43 | + private LocalDateTime contactNextTime; | ||
| 44 | + | ||
| 45 | + @Schema(description = "负责人的用户编号", example = "25682") | ||
| 46 | + @ExcelProperty("负责人的用户编号") | ||
| 47 | + private Long ownerUserId; | ||
| 48 | + @Schema(description = "负责人名字", example = "25682") | ||
| 49 | + @ExcelProperty("负责人名字") | ||
| 50 | + private String ownerUserName; | ||
| 51 | + @Schema(description = "负责人部门") | ||
| 52 | + @ExcelProperty("负责人部门") | ||
| 53 | + private String ownerUserDeptName; | ||
| 54 | + | ||
| 55 | + @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") | ||
| 26 | private Long statusTypeId; | 56 | private Long statusTypeId; |
| 57 | + @Schema(description = "商机状组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中") | ||
| 58 | + @ExcelProperty("商机状态组") | ||
| 59 | + private String statusTypeName; | ||
| 27 | 60 | ||
| 28 | @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | 61 | @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") |
| 29 | - @NotNull(message = "商机状态不能为空") | ||
| 30 | private Long statusId; | 62 | private Long statusId; |
| 63 | + @Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中") | ||
| 64 | + @ExcelProperty("商机状态") | ||
| 65 | + private String statusName; | ||
| 31 | 66 | ||
| 32 | - @Schema(description = "下次联系时间") | ||
| 33 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 34 | - private LocalDateTime contactNextTime; | 67 | + @Schema |
| 68 | + @ExcelProperty("结束状态") | ||
| 69 | + private Integer endStatus; | ||
| 35 | 70 | ||
| 36 | - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") | ||
| 37 | - @NotNull(message = "客户不能为空") | ||
| 38 | - private Long customerId; | 71 | + @ExcelProperty("结束时的备注") |
| 72 | + private String endRemark; | ||
| 39 | 73 | ||
| 40 | @Schema(description = "预计成交日期") | 74 | @Schema(description = "预计成交日期") |
| 41 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 75 | + @ExcelProperty("预计成交日期") |
| 42 | private LocalDateTime dealTime; | 76 | private LocalDateTime dealTime; |
| 43 | 77 | ||
| 44 | - @Schema(description = "商机金额", example = "12371") | ||
| 45 | - private Integer price; | 78 | + @Schema(description = "产品总金额", example = "12025") |
| 79 | + @ExcelProperty("产品总金额") | ||
| 80 | + private BigDecimal totalProductPrice; | ||
| 46 | 81 | ||
| 47 | - // TODO @ljileo:折扣使用 Integer 类型,存储时,默认 * 100;展示的时候,前端需要 / 100;避免精度丢失问题 | ||
| 48 | @Schema(description = "整单折扣") | 82 | @Schema(description = "整单折扣") |
| 49 | - private Integer discountPercent; | 83 | + @ExcelProperty("整单折扣") |
| 84 | + private BigDecimal discountPercent; | ||
| 50 | 85 | ||
| 51 | - @Schema(description = "产品总金额", example = "12025") | ||
| 52 | - private BigDecimal productPrice; | 86 | + @Schema(description = "商机总金额", example = "12371") |
| 87 | + @ExcelProperty("商机总金额") | ||
| 88 | + private BigDecimal totalPrice; | ||
| 53 | 89 | ||
| 54 | @Schema(description = "备注", example = "随便") | 90 | @Schema(description = "备注", example = "随便") |
| 91 | + @ExcelProperty("备注") | ||
| 55 | private String remark; | 92 | private String remark; |
| 56 | 93 | ||
| 94 | + @Schema(description = "创建人", example = "1024") | ||
| 95 | + @ExcelProperty("创建人") | ||
| 96 | + private String creator; | ||
| 97 | + @Schema(description = "创建人名字", example = "芋道源码") | ||
| 98 | + @ExcelProperty("创建人名字") | ||
| 99 | + private String creatorName; | ||
| 100 | + | ||
| 57 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 101 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 102 | + @ExcelProperty("创建时间") | ||
| 58 | private LocalDateTime createTime; | 103 | private LocalDateTime createTime; |
| 59 | 104 | ||
| 60 | - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 61 | - private String customerName; | 105 | + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 106 | + @ExcelProperty("更新时间") | ||
| 107 | + private LocalDateTime updateTime; | ||
| 62 | 108 | ||
| 63 | - @Schema(description = "状态类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中") | ||
| 64 | - private String statusTypeName; | 109 | + @Schema(description = "产品列表") |
| 110 | + private List<Product> products; | ||
| 65 | 111 | ||
| 66 | - @Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中") | ||
| 67 | - private String statusName; | 112 | + @Schema(description = "产品列表") |
| 113 | + @Data | ||
| 114 | + @NoArgsConstructor | ||
| 115 | + @AllArgsConstructor | ||
| 116 | + public static class Product { | ||
| 117 | + | ||
| 118 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") | ||
| 119 | + private Long id; | ||
| 120 | + | ||
| 121 | + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") | ||
| 122 | + private Long productId; | ||
| 123 | + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 124 | + private String productName; | ||
| 125 | + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") | ||
| 126 | + private String productNo; | ||
| 127 | + @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 128 | + private Integer productUnit; | ||
| 129 | + | ||
| 130 | + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") | ||
| 131 | + private BigDecimal productPrice; | ||
| 132 | + | ||
| 133 | + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") | ||
| 134 | + private BigDecimal businessPrice; | ||
| 135 | + | ||
| 136 | + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") | ||
| 137 | + private BigDecimal count; | ||
| 138 | + | ||
| 139 | + @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") | ||
| 140 | + private BigDecimal totalPrice; | ||
| 141 | + | ||
| 142 | + } | ||
| 68 | 143 | ||
| 69 | } | 144 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | -import cn.iocoder.yudao.module.crm.enums.business.CrmBizEndStatus; | ||
| 5 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; | 3 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; |
| 4 | +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFunction; | ||
| 6 | import com.mzt.logapi.starter.annotation.DiffLogField; | 5 | import com.mzt.logapi.starter.annotation.DiffLogField; |
| 7 | import io.swagger.v3.oas.annotations.media.Schema; | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | import jakarta.validation.constraints.NotNull; | 7 | import jakarta.validation.constraints.NotNull; |
| @@ -29,75 +28,68 @@ public class CrmBusinessSaveReqVO { | @@ -29,75 +28,68 @@ public class CrmBusinessSaveReqVO { | ||
| 29 | @NotNull(message = "商机名称不能为空") | 28 | @NotNull(message = "商机名称不能为空") |
| 30 | private String name; | 29 | private String name; |
| 31 | 30 | ||
| 32 | - @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") | ||
| 33 | - @DiffLogField(name = "商机状态") | ||
| 34 | - @NotNull(message = "商机状态类型不能为空") | ||
| 35 | - private Long statusTypeId; | ||
| 36 | - | ||
| 37 | - @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | ||
| 38 | - @DiffLogField(name = "商机状态") | ||
| 39 | - @NotNull(message = "商机状态不能为空") | ||
| 40 | - private Long statusId; | 31 | + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") |
| 32 | + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) | ||
| 33 | + @NotNull(message = "客户不能为空") | ||
| 34 | + private Long customerId; | ||
| 41 | 35 | ||
| 42 | @Schema(description = "下次联系时间") | 36 | @Schema(description = "下次联系时间") |
| 43 | @DiffLogField(name = "下次联系时间") | 37 | @DiffLogField(name = "下次联系时间") |
| 44 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 38 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 45 | private LocalDateTime contactNextTime; | 39 | private LocalDateTime contactNextTime; |
| 46 | 40 | ||
| 47 | - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") | ||
| 48 | - @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) | ||
| 49 | - @NotNull(message = "客户不能为空") | ||
| 50 | - private Long customerId; | 41 | + @Schema(description = "负责人用户编号", example = "14334") |
| 42 | + @NotNull(message = "负责人不能为空") | ||
| 43 | + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) | ||
| 44 | + private Long ownerUserId; | ||
| 45 | + | ||
| 46 | + @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") | ||
| 47 | + @DiffLogField(name = "商机状态组") | ||
| 48 | + @NotNull(message = "商机状态组不能为空") | ||
| 49 | + private Long statusTypeId; | ||
| 51 | 50 | ||
| 52 | @Schema(description = "预计成交日期") | 51 | @Schema(description = "预计成交日期") |
| 53 | @DiffLogField(name = "预计成交日期") | 52 | @DiffLogField(name = "预计成交日期") |
| 54 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 53 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 55 | private LocalDateTime dealTime; | 54 | private LocalDateTime dealTime; |
| 56 | 55 | ||
| 57 | - @Schema(description = "商机金额", example = "12371") | ||
| 58 | - @DiffLogField(name = "商机金额") | ||
| 59 | - private Integer price; | ||
| 60 | - | ||
| 61 | - @Schema(description = "整单折扣") | 56 | + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00") |
| 62 | @DiffLogField(name = "整单折扣") | 57 | @DiffLogField(name = "整单折扣") |
| 63 | - private Integer discountPercent; | ||
| 64 | - | ||
| 65 | - @Schema(description = "产品总金额", example = "12025") | ||
| 66 | - @DiffLogField(name = "产品总金额") | ||
| 67 | - private BigDecimal productPrice; | 58 | + @NotNull(message = "整单折扣不能为空") |
| 59 | + private BigDecimal discountPercent; | ||
| 68 | 60 | ||
| 69 | @Schema(description = "备注", example = "随便") | 61 | @Schema(description = "备注", example = "随便") |
| 70 | @DiffLogField(name = "备注") | 62 | @DiffLogField(name = "备注") |
| 71 | private String remark; | 63 | private String remark; |
| 72 | 64 | ||
| 73 | - @Schema(description = "结束状态", example = "1") | ||
| 74 | - @InEnum(CrmBizEndStatus.class) | ||
| 75 | - private Integer endStatus; | ||
| 76 | - | ||
| 77 | @Schema(description = "联系人编号", example = "110") | 65 | @Schema(description = "联系人编号", example = "110") |
| 78 | private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 | 66 | private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 |
| 79 | 67 | ||
| 80 | - // TODO @puhui999:传递 items 就行啦; | ||
| 81 | @Schema(description = "产品列表") | 68 | @Schema(description = "产品列表") |
| 82 | - private List<CrmBusinessProductItem> productItems; | 69 | + private List<Product> products; |
| 83 | 70 | ||
| 84 | @Schema(description = "产品列表") | 71 | @Schema(description = "产品列表") |
| 85 | @Data | 72 | @Data |
| 86 | @NoArgsConstructor | 73 | @NoArgsConstructor |
| 87 | @AllArgsConstructor | 74 | @AllArgsConstructor |
| 88 | - public static class CrmBusinessProductItem { | 75 | + public static class Product { |
| 89 | 76 | ||
| 90 | @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") | 77 | @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") |
| 91 | @NotNull(message = "产品编号不能为空") | 78 | @NotNull(message = "产品编号不能为空") |
| 92 | - private Long id; | 79 | + private Long productId; |
| 80 | + | ||
| 81 | + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") | ||
| 82 | + @NotNull(message = "产品单价不能为空") | ||
| 83 | + private BigDecimal productPrice; | ||
| 84 | + | ||
| 85 | + @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") | ||
| 86 | + @NotNull(message = "商机价格不能为空") | ||
| 87 | + private BigDecimal businessPrice; | ||
| 93 | 88 | ||
| 94 | @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") | 89 | @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") |
| 95 | @NotNull(message = "产品数量不能为空") | 90 | @NotNull(message = "产品数量不能为空") |
| 96 | private Integer count; | 91 | private Integer count; |
| 97 | 92 | ||
| 98 | - @Schema(description = "产品折扣") | ||
| 99 | - private Integer discountPercent; | ||
| 100 | - | ||
| 101 | } | 93 | } |
| 102 | 94 | ||
| 103 | } | 95 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | +import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; | ||
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | +import jakarta.validation.constraints.AssertTrue; | ||
| 7 | +import jakarta.validation.constraints.NotNull; | ||
| 8 | +import lombok.Data; | ||
| 9 | + | ||
| 10 | +@Schema(description = "管理后台 - CRM 商机更新状态 Request VO") | ||
| 11 | +@Data | ||
| 12 | +public class CrmBusinessUpdateStatusReqVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") | ||
| 15 | + @NotNull(message = "商机编号不能为空") | ||
| 16 | + private Long id; | ||
| 17 | + | ||
| 18 | + @Schema(description = "状态编号", example = "1") | ||
| 19 | + private Long statusId; | ||
| 20 | + | ||
| 21 | + @Schema(description = "结束状态", example = "1") | ||
| 22 | + @InEnum(value = CrmBusinessEndStatusEnum.class) | ||
| 23 | + private Integer endStatus; | ||
| 24 | + | ||
| 25 | + @AssertTrue(message = "变更状态不正确") | ||
| 26 | + public boolean isStatusValid() { | ||
| 27 | + return statusId != null || endStatus != null; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusPageReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | -import lombok.Data; | ||
| 6 | -import lombok.EqualsAndHashCode; | ||
| 7 | -import lombok.ToString; | ||
| 8 | - | ||
| 9 | -@Schema(description = "管理后台 - 商机状态分页 Request VO") | ||
| 10 | -@Data | ||
| 11 | -@EqualsAndHashCode(callSuper = true) | ||
| 12 | -@ToString(callSuper = true) | ||
| 13 | -public class CrmBusinessStatusPageReqVO extends PageParam { | ||
| 14 | - | ||
| 15 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusQueryVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.Data; | ||
| 5 | -import lombok.ToString; | ||
| 6 | - | ||
| 7 | -import java.util.Collection; | ||
| 8 | - | ||
| 9 | -@Schema(description = "管理后台 - 商机状态 Query VO") | ||
| 10 | -@Data | ||
| 11 | -@ToString(callSuper = true) | ||
| 12 | -public class CrmBusinessStatusQueryVO { | ||
| 13 | - | ||
| 14 | - @Schema(description = "主键集合") | ||
| 15 | - private Collection<Long> idList; | ||
| 16 | - | ||
| 17 | - @Schema(description = "状态类型编号") | ||
| 18 | - private Long typeId; | ||
| 19 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; |
| 2 | 2 | ||
| 3 | -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | ||
| 4 | -import com.alibaba.excel.annotation.ExcelProperty; | ||
| 5 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | import lombok.Data; | 4 | import lombok.Data; |
| 7 | 5 | ||
| 6 | +import java.math.BigDecimal; | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 8 | @Schema(description = "管理后台 - 商机状态 Response VO") | 10 | @Schema(description = "管理后台 - 商机状态 Response VO") |
| 9 | @Data | 11 | @Data |
| 10 | -@ExcelIgnoreUnannotated | ||
| 11 | public class CrmBusinessStatusRespVO { | 12 | public class CrmBusinessStatusRespVO { |
| 12 | 13 | ||
| 13 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "23899") | ||
| 14 | - @ExcelProperty("主键") | 14 | + @Schema(description = "状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") |
| 15 | private Long id; | 15 | private Long id; |
| 16 | 16 | ||
| 17 | - @Schema(description = "状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7139") | ||
| 18 | - @ExcelProperty("状态类型编号") | ||
| 19 | - private Long typeId; | ||
| 20 | - | ||
| 21 | - @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") | ||
| 22 | - @ExcelProperty("状态名") | 17 | + @Schema(description = "状态组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") |
| 23 | private String name; | 18 | private String name; |
| 24 | 19 | ||
| 25 | - @Schema(description = "赢单率") | ||
| 26 | - @ExcelProperty("赢单率") | ||
| 27 | - private String percent; | 20 | + @Schema(description = "使用的部门编号", requiredMode = Schema.RequiredMode.REQUIRED) |
| 21 | + private List<Long> deptIds; | ||
| 22 | + @Schema(description = "使用的部门名称", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 23 | + private List<String> deptNames; | ||
| 24 | + | ||
| 25 | + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 26 | + private String creator; | ||
| 27 | + | ||
| 28 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 29 | + private LocalDateTime createTime; | ||
| 30 | + | ||
| 31 | + @Schema(description = "状态集合", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 32 | + private List<Status> statuses; | ||
| 33 | + | ||
| 34 | + @Data | ||
| 35 | + public static class Status { | ||
| 36 | + | ||
| 37 | + @Schema(description = "状态编号", example = "23899") | ||
| 38 | + private Long id; | ||
| 39 | + | ||
| 40 | + @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") | ||
| 41 | + private String name; | ||
| 42 | + | ||
| 43 | + @Schema(description = "赢单率", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") | ||
| 44 | + private BigDecimal percent; | ||
| 45 | + | ||
| 46 | + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 47 | + private Integer sort; | ||
| 28 | 48 | ||
| 29 | - @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 30 | - @ExcelProperty("排序") | ||
| 31 | - private Integer sort; | 49 | + } |
| 32 | 50 | ||
| 33 | } | 51 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.Data; | ||
| 5 | - | 4 | +import jakarta.validation.Valid; |
| 6 | import jakarta.validation.constraints.NotEmpty; | 5 | import jakarta.validation.constraints.NotEmpty; |
| 7 | import jakarta.validation.constraints.NotNull; | 6 | import jakarta.validation.constraints.NotNull; |
| 7 | +import lombok.Data; | ||
| 8 | 8 | ||
| 9 | -@Schema(description = "管理后台 - 商机状态新增/修改 Request VO") | 9 | +import java.math.BigDecimal; |
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 12 | +@Schema(description = "管理后台 - 商机状态组新增/修改 Request VO") | ||
| 10 | @Data | 13 | @Data |
| 11 | public class CrmBusinessStatusSaveReqVO { | 14 | public class CrmBusinessStatusSaveReqVO { |
| 12 | 15 | ||
| 13 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "23899") | 16 | + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") |
| 14 | private Long id; | 17 | private Long id; |
| 15 | 18 | ||
| 16 | - @Schema(description = "状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7139") | ||
| 17 | - @NotNull(message = "状态类型编号不能为空") | ||
| 18 | - private Long typeId; | ||
| 19 | - | ||
| 20 | - @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") | ||
| 21 | - @NotEmpty(message = "状态名不能为空") | 19 | + @Schema(description = "状态类型名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") |
| 20 | + @NotEmpty(message = "状态类型名不能为空") | ||
| 22 | private String name; | 21 | private String name; |
| 23 | 22 | ||
| 24 | - // TODO @lzxhqs::percent 应该是 Integer; | ||
| 25 | - @Schema(description = "赢单率") | ||
| 26 | - private String percent; | 23 | + @Schema(description = "使用的部门编号") |
| 24 | + private List<Long> deptIds; | ||
| 25 | + | ||
| 26 | + @Schema(description = "商机状态集合", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 27 | + @NotEmpty(message = "商机状态集合不能为空") | ||
| 28 | + @Valid | ||
| 29 | + private List<Status> statuses; | ||
| 30 | + | ||
| 31 | + @Data | ||
| 32 | + public static class Status { | ||
| 33 | + | ||
| 34 | + @Schema(description = "状态编号", example = "23899") | ||
| 35 | + private Long id; | ||
| 36 | + | ||
| 37 | + @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") | ||
| 38 | + @NotEmpty(message = "状态名不能为空") | ||
| 39 | + private String name; | ||
| 40 | + | ||
| 41 | + @Schema(description = "赢单率", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") | ||
| 42 | + @NotNull(message = "赢单率不能为空") | ||
| 43 | + private BigDecimal percent; | ||
| 44 | + | ||
| 45 | + @Schema(description = "排序", hidden = true, example = "1") | ||
| 46 | + private Integer sort; | ||
| 27 | 47 | ||
| 28 | - // TODO @lzxhqs:这个是不是不用前端新增和修改的时候传递,交给顺序计算出来,存储起来就好了; | ||
| 29 | - @Schema(description = "排序") | ||
| 30 | - private Integer sort; | 48 | + } |
| 31 | 49 | ||
| 32 | } | 50 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/type/CrmBusinessStatusTypePageReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.type; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | -import lombok.Data; | ||
| 6 | -import lombok.EqualsAndHashCode; | ||
| 7 | -import lombok.ToString; | ||
| 8 | - | ||
| 9 | -@Schema(description = "管理后台 - 商机状态类型分页 Request VO") | ||
| 10 | -@Data | ||
| 11 | -@EqualsAndHashCode(callSuper = true) | ||
| 12 | -@ToString(callSuper = true) | ||
| 13 | -public class CrmBusinessStatusTypePageReqVO extends PageParam { | ||
| 14 | - | ||
| 15 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/type/CrmBusinessStatusTypeQueryVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.type; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.Data; | ||
| 5 | -import lombok.ToString; | ||
| 6 | - | ||
| 7 | -import java.util.Collection; | ||
| 8 | - | ||
| 9 | -@Schema(description = "管理后台 - 商机状态类型 Query VO") | ||
| 10 | -@Data | ||
| 11 | -@ToString(callSuper = true) | ||
| 12 | -public class CrmBusinessStatusTypeQueryVO { | ||
| 13 | - | ||
| 14 | - @Schema(description = "主键集合") | ||
| 15 | - private Collection<Long> idList; | ||
| 16 | - | ||
| 17 | - @Schema(description = "状态") | ||
| 18 | - private Integer status; | ||
| 19 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/type/CrmBusinessStatusTypeRespVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.type; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; | ||
| 4 | -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | ||
| 5 | -import com.alibaba.excel.annotation.ExcelProperty; | ||
| 6 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 7 | -import lombok.Data; | ||
| 8 | - | ||
| 9 | -import java.time.LocalDateTime; | ||
| 10 | -import java.util.List; | ||
| 11 | - | ||
| 12 | -@Schema(description = "管理后台 - 商机状态类型 Response VO") | ||
| 13 | -@Data | ||
| 14 | -@ExcelIgnoreUnannotated | ||
| 15 | -public class CrmBusinessStatusTypeRespVO { | ||
| 16 | - | ||
| 17 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") | ||
| 18 | - @ExcelProperty("主键") | ||
| 19 | - private Long id; | ||
| 20 | - | ||
| 21 | - @Schema(description = "状态类型名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 22 | - @ExcelProperty("状态类型名") | ||
| 23 | - private String name; | ||
| 24 | - | ||
| 25 | - @Schema(description = "使用的部门编号", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 26 | - @ExcelProperty("使用的部门编号") | ||
| 27 | - private List<Long> deptIds; | ||
| 28 | - @Schema(description = "使用的部门名称", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 29 | - @ExcelProperty("使用的部门名称") | ||
| 30 | - private List<String> deptNames; | ||
| 31 | - | ||
| 32 | - @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 33 | - @ExcelProperty("创建人") | ||
| 34 | - private String creator; | ||
| 35 | - | ||
| 36 | - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 37 | - @ExcelProperty("创建时间") | ||
| 38 | - private LocalDateTime createTime; | ||
| 39 | - | ||
| 40 | - // TODO @ljlleo 字段后缀改成 statuses,保持和 deptIds 风格一致;CrmBusinessStatusDO 改成 VO 哈;一般不使用 do 直接返回 | ||
| 41 | - @Schema(description = "状态集合", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 42 | - private List<CrmBusinessStatusDO> statusList; | ||
| 43 | - | ||
| 44 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/type/CrmBusinessStatusTypeSaveReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.type; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; | ||
| 4 | -import com.google.common.collect.Lists; | ||
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | -import lombok.Data; | ||
| 7 | - | ||
| 8 | -import jakarta.validation.constraints.NotEmpty; | ||
| 9 | -import java.util.List; | ||
| 10 | - | ||
| 11 | -@Schema(description = "管理后台 - 商机状态类型新增/修改 Request VO") | ||
| 12 | -@Data | ||
| 13 | -public class CrmBusinessStatusTypeSaveReqVO { | ||
| 14 | - | ||
| 15 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") | ||
| 16 | - private Long id; | ||
| 17 | - | ||
| 18 | - @Schema(description = "状态类型名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 19 | - @NotEmpty(message = "状态类型名不能为空") | ||
| 20 | - private String name; | ||
| 21 | - | ||
| 22 | - // TODO @lzxhqs: VO 里面,我们不使用默认值哈。这里 Lists.newArrayList() 看看怎么去掉。上面 deptIds 也是类似噢 | ||
| 23 | - @Schema(description = "使用的部门编号", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 24 | - private List<Long> deptIds = Lists.newArrayList(); | ||
| 25 | - | ||
| 26 | - @Schema(description = "商机状态集合", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 27 | - private List<CrmBusinessStatusSaveReqVO> statusList; | ||
| 28 | - | ||
| 29 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.clue; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.clue; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 6 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 9 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 10 | +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | ||
| 7 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 8 | -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*; | 12 | +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; |
| 13 | +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueRespVO; | ||
| 14 | +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; | ||
| 15 | +import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; | ||
| 9 | import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; | 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; |
| 17 | +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | ||
| 10 | import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; | 18 | import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; |
| 19 | +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | ||
| 20 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 21 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 22 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 23 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 11 | import io.swagger.v3.oas.annotations.Operation; | 24 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | import io.swagger.v3.oas.annotations.Parameter; | 25 | import io.swagger.v3.oas.annotations.Parameter; |
| 13 | import io.swagger.v3.oas.annotations.tags.Tag; | 26 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -19,12 +32,18 @@ import org.springframework.validation.annotation.Validated; | @@ -19,12 +32,18 @@ import org.springframework.validation.annotation.Validated; | ||
| 19 | import org.springframework.web.bind.annotation.*; | 32 | import org.springframework.web.bind.annotation.*; |
| 20 | 33 | ||
| 21 | import java.io.IOException; | 34 | import java.io.IOException; |
| 35 | +import java.util.Collections; | ||
| 22 | import java.util.List; | 36 | import java.util.List; |
| 37 | +import java.util.Map; | ||
| 38 | +import java.util.stream.Stream; | ||
| 23 | 39 | ||
| 24 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 40 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 25 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | 41 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 42 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; | ||
| 43 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 26 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 44 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 27 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 45 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 46 | +import static java.util.Collections.singletonList; | ||
| 28 | 47 | ||
| 29 | @Tag(name = "管理后台 - 线索") | 48 | @Tag(name = "管理后台 - 线索") |
| 30 | @RestController | 49 | @RestController |
| @@ -34,12 +53,19 @@ public class CrmClueController { | @@ -34,12 +53,19 @@ public class CrmClueController { | ||
| 34 | 53 | ||
| 35 | @Resource | 54 | @Resource |
| 36 | private CrmClueService clueService; | 55 | private CrmClueService clueService; |
| 56 | + @Resource | ||
| 57 | + private CrmCustomerService customerService; | ||
| 58 | + | ||
| 59 | + @Resource | ||
| 60 | + private AdminUserApi adminUserApi; | ||
| 61 | + @Resource | ||
| 62 | + private DeptApi deptApi; | ||
| 37 | 63 | ||
| 38 | @PostMapping("/create") | 64 | @PostMapping("/create") |
| 39 | @Operation(summary = "创建线索") | 65 | @Operation(summary = "创建线索") |
| 40 | @PreAuthorize("@ss.hasPermission('crm:clue:create')") | 66 | @PreAuthorize("@ss.hasPermission('crm:clue:create')") |
| 41 | public CommonResult<Long> createClue(@Valid @RequestBody CrmClueSaveReqVO createReqVO) { | 67 | public CommonResult<Long> createClue(@Valid @RequestBody CrmClueSaveReqVO createReqVO) { |
| 42 | - return success(clueService.createClue(createReqVO, getLoginUserId())); | 68 | + return success(clueService.createClue(createReqVO)); |
| 43 | } | 69 | } |
| 44 | 70 | ||
| 45 | @PutMapping("/update") | 71 | @PutMapping("/update") |
| @@ -65,7 +91,14 @@ public class CrmClueController { | @@ -65,7 +91,14 @@ public class CrmClueController { | ||
| 65 | @PreAuthorize("@ss.hasPermission('crm:clue:query')") | 91 | @PreAuthorize("@ss.hasPermission('crm:clue:query')") |
| 66 | public CommonResult<CrmClueRespVO> getClue(@RequestParam("id") Long id) { | 92 | public CommonResult<CrmClueRespVO> getClue(@RequestParam("id") Long id) { |
| 67 | CrmClueDO clue = clueService.getClue(id); | 93 | CrmClueDO clue = clueService.getClue(id); |
| 68 | - return success(BeanUtils.toBean(clue, CrmClueRespVO.class)); | 94 | + return success(buildClueDetail(clue)); |
| 95 | + } | ||
| 96 | + | ||
| 97 | + private CrmClueRespVO buildClueDetail(CrmClueDO clue) { | ||
| 98 | + if (clue == null) { | ||
| 99 | + return null; | ||
| 100 | + } | ||
| 101 | + return buildClueDetailList(singletonList(clue)).get(0); | ||
| 69 | } | 102 | } |
| 70 | 103 | ||
| 71 | @GetMapping("/page") | 104 | @GetMapping("/page") |
| @@ -73,7 +106,7 @@ public class CrmClueController { | @@ -73,7 +106,7 @@ public class CrmClueController { | ||
| 73 | @PreAuthorize("@ss.hasPermission('crm:clue:query')") | 106 | @PreAuthorize("@ss.hasPermission('crm:clue:query')") |
| 74 | public CommonResult<PageResult<CrmClueRespVO>> getCluePage(@Valid CrmCluePageReqVO pageVO) { | 107 | public CommonResult<PageResult<CrmClueRespVO>> getCluePage(@Valid CrmCluePageReqVO pageVO) { |
| 75 | PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO, getLoginUserId()); | 108 | PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO, getLoginUserId()); |
| 76 | - return success(BeanUtils.toBean(pageResult, CrmClueRespVO.class)); | 109 | + return success(new PageResult<>(buildClueDetailList(pageResult.getList()), pageResult.getTotal())); |
| 77 | } | 110 | } |
| 78 | 111 | ||
| 79 | @GetMapping("/export-excel") | 112 | @GetMapping("/export-excel") |
| @@ -84,8 +117,33 @@ public class CrmClueController { | @@ -84,8 +117,33 @@ public class CrmClueController { | ||
| 84 | pageReqVO.setPageSize(PAGE_SIZE_NONE); | 117 | pageReqVO.setPageSize(PAGE_SIZE_NONE); |
| 85 | List<CrmClueDO> list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList(); | 118 | List<CrmClueDO> list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList(); |
| 86 | // 导出 Excel | 119 | // 导出 Excel |
| 87 | - List<CrmClueRespVO> datas = BeanUtils.toBean(list, CrmClueRespVO.class); | ||
| 88 | - ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, datas); | 120 | + ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, buildClueDetailList(list)); |
| 121 | + } | ||
| 122 | + | ||
| 123 | + private List<CrmClueRespVO> buildClueDetailList(List<CrmClueDO> list) { | ||
| 124 | + if (CollUtil.isEmpty(list)) { | ||
| 125 | + return Collections.emptyList(); | ||
| 126 | + } | ||
| 127 | + // 1.1 获取客户列表 | ||
| 128 | + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap( | ||
| 129 | + convertSet(list, CrmClueDO::getCustomerId)); | ||
| 130 | + // 1.2 获取创建人、负责人列表 | ||
| 131 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(list, | ||
| 132 | + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | ||
| 133 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||
| 134 | + // 2. 转换成 VO | ||
| 135 | + return BeanUtils.toBean(list, CrmClueRespVO.class, clueVO -> { | ||
| 136 | + clueVO.setAreaName(AreaUtils.format(clueVO.getAreaId())); | ||
| 137 | + // 2.1 设置客户名称 | ||
| 138 | + MapUtils.findAndThen(customerMap, clueVO.getCustomerId(), customer -> clueVO.setCustomerName(customer.getName())); | ||
| 139 | + // 2.2 设置创建人、负责人名称 | ||
| 140 | + MapUtils.findAndThen(userMap, NumberUtils.parseLong(clueVO.getCreator()), | ||
| 141 | + user -> clueVO.setCreatorName(user.getNickname())); | ||
| 142 | + MapUtils.findAndThen(userMap, clueVO.getOwnerUserId(), user -> { | ||
| 143 | + clueVO.setOwnerUserName(user.getNickname()); | ||
| 144 | + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> clueVO.setOwnerUserDeptName(dept.getName())); | ||
| 145 | + }); | ||
| 146 | + }); | ||
| 89 | } | 147 | } |
| 90 | 148 | ||
| 91 | @PutMapping("/transfer") | 149 | @PutMapping("/transfer") |
| @@ -96,12 +154,20 @@ public class CrmClueController { | @@ -96,12 +154,20 @@ public class CrmClueController { | ||
| 96 | return success(true); | 154 | return success(true); |
| 97 | } | 155 | } |
| 98 | 156 | ||
| 99 | - @PostMapping("/transform") | 157 | + @PutMapping("/transform") |
| 100 | @Operation(summary = "线索转化为客户") | 158 | @Operation(summary = "线索转化为客户") |
| 159 | + @Parameter(name = "id", description = "编号", required = true) | ||
| 101 | @PreAuthorize("@ss.hasPermission('crm:clue:update')") | 160 | @PreAuthorize("@ss.hasPermission('crm:clue:update')") |
| 102 | - public CommonResult<Boolean> translateCustomer(@Valid @RequestBody CrmClueTranslateReqVO reqVO) { | ||
| 103 | - clueService.translateCustomer(reqVO, getLoginUserId()); | 161 | + public CommonResult<Boolean> transformClue(@RequestParam("id") Long id) { |
| 162 | + clueService.transformClue(id, getLoginUserId()); | ||
| 104 | return success(Boolean.TRUE); | 163 | return success(Boolean.TRUE); |
| 105 | } | 164 | } |
| 106 | 165 | ||
| 166 | + @GetMapping("/follow-count") | ||
| 167 | + @Operation(summary = "获得分配给我的、待跟进的线索数量") | ||
| 168 | + @PreAuthorize("@ss.hasPermission('crm:clue:query')") | ||
| 169 | + public CommonResult<Long> getFollowClueCount() { | ||
| 170 | + return success(clueService.getFollowClueCount(getLoginUserId())); | ||
| 171 | + } | ||
| 172 | + | ||
| 107 | } | 173 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java
| @@ -17,6 +17,9 @@ public class CrmCluePageReqVO extends PageParam { | @@ -17,6 +17,9 @@ public class CrmCluePageReqVO extends PageParam { | ||
| 17 | @Schema(description = "线索名称", example = "线索xxx") | 17 | @Schema(description = "线索名称", example = "线索xxx") |
| 18 | private String name; | 18 | private String name; |
| 19 | 19 | ||
| 20 | + @Schema(description = "转化状态", example = "2048") | ||
| 21 | + private Boolean transformStatus; | ||
| 22 | + | ||
| 20 | @Schema(description = "电话", example = "18000000000") | 23 | @Schema(description = "电话", example = "18000000000") |
| 21 | private String telephone; | 24 | private String telephone; |
| 22 | 25 | ||
| @@ -39,4 +42,7 @@ public class CrmCluePageReqVO extends PageParam { | @@ -39,4 +42,7 @@ public class CrmCluePageReqVO extends PageParam { | ||
| 39 | @Schema(description = "客户来源", example = "1") | 42 | @Schema(description = "客户来源", example = "1") |
| 40 | private Integer source; | 43 | private Integer source; |
| 41 | 44 | ||
| 45 | + @Schema(description = "跟进状态", example = "true") | ||
| 46 | + private Boolean followUpStatus; | ||
| 47 | + | ||
| 42 | } | 48 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java
| @@ -8,12 +8,9 @@ import com.alibaba.excel.annotation.ExcelProperty; | @@ -8,12 +8,9 @@ import com.alibaba.excel.annotation.ExcelProperty; | ||
| 8 | import io.swagger.v3.oas.annotations.media.Schema; | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | import lombok.Data; | 9 | import lombok.Data; |
| 10 | import lombok.ToString; | 10 | import lombok.ToString; |
| 11 | -import org.springframework.format.annotation.DateTimeFormat; | ||
| 12 | 11 | ||
| 13 | import java.time.LocalDateTime; | 12 | import java.time.LocalDateTime; |
| 14 | 13 | ||
| 15 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 16 | - | ||
| 17 | @Schema(description = "管理后台 - 线索 Response VO") | 14 | @Schema(description = "管理后台 - 线索 Response VO") |
| 18 | @Data | 15 | @Data |
| 19 | @ToString(callSuper = true) | 16 | @ToString(callSuper = true) |
| @@ -24,58 +21,76 @@ public class CrmClueRespVO { | @@ -24,58 +21,76 @@ public class CrmClueRespVO { | ||
| 24 | @ExcelProperty("编号") | 21 | @ExcelProperty("编号") |
| 25 | private Long id; | 22 | private Long id; |
| 26 | 23 | ||
| 27 | - @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||
| 28 | - @ExcelProperty(value = "转化状态", converter = DictConvert.class) | ||
| 29 | - @DictFormat(DictTypeConstants.BOOLEAN_STRING) | ||
| 30 | - private Boolean transformStatus; | 24 | + @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") |
| 25 | + @ExcelProperty("线索名称") | ||
| 26 | + private String name; | ||
| 31 | 27 | ||
| 32 | @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | 28 | @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") |
| 33 | @ExcelProperty(value = "跟进状态", converter = DictConvert.class) | 29 | @ExcelProperty(value = "跟进状态", converter = DictConvert.class) |
| 34 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) | 30 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) |
| 35 | private Boolean followUpStatus; | 31 | private Boolean followUpStatus; |
| 36 | 32 | ||
| 37 | - @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") | ||
| 38 | - @ExcelProperty("线索名称") | ||
| 39 | - private String name; | 33 | + @Schema(description = "最后跟进时间") |
| 34 | + @ExcelProperty("最后跟进时间") | ||
| 35 | + private LocalDateTime contactLastTime; | ||
| 40 | 36 | ||
| 41 | - @Schema(description = "客户 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "520") | ||
| 42 | - // TODO 这里需要导出成客户名称 | ||
| 43 | - @ExcelProperty("客户id") | ||
| 44 | - private Long customerId; | 37 | + @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗") |
| 38 | + @ExcelProperty("最后跟进内容") | ||
| 39 | + private String contactLastContent; | ||
| 45 | 40 | ||
| 46 | @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") | 41 | @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") |
| 47 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 48 | @ExcelProperty("下次联系时间") | 42 | @ExcelProperty("下次联系时间") |
| 49 | private LocalDateTime contactNextTime; | 43 | private LocalDateTime contactNextTime; |
| 50 | 44 | ||
| 51 | - @Schema(description = "电话", example = "18000000000") | ||
| 52 | - @ExcelProperty("电话") | ||
| 53 | - private String telephone; | 45 | + @Schema(description = "负责人编号") |
| 46 | + private Long ownerUserId; | ||
| 47 | + @Schema(description = "负责人名字", example = "25682") | ||
| 48 | + @ExcelProperty("负责人名字") | ||
| 49 | + private String ownerUserName; | ||
| 50 | + @Schema(description = "负责人部门") | ||
| 51 | + @ExcelProperty("负责人部门") | ||
| 52 | + private String ownerUserDeptName; | ||
| 53 | + | ||
| 54 | + @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||
| 55 | + @ExcelProperty(value = "转化状态", converter = DictConvert.class) | ||
| 56 | + @DictFormat(DictTypeConstants.BOOLEAN_STRING) | ||
| 57 | + private Boolean transformStatus; | ||
| 58 | + | ||
| 59 | + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "520") | ||
| 60 | + private Long customerId; | ||
| 61 | + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "客户名称") | ||
| 62 | + @ExcelProperty("客户名称") | ||
| 63 | + private String customerName; | ||
| 54 | 64 | ||
| 55 | @Schema(description = "手机号", example = "18000000000") | 65 | @Schema(description = "手机号", example = "18000000000") |
| 56 | @ExcelProperty("手机号") | 66 | @ExcelProperty("手机号") |
| 57 | private String mobile; | 67 | private String mobile; |
| 58 | 68 | ||
| 59 | - @Schema(description = "地址", example = "北京市海淀区") | ||
| 60 | - @ExcelProperty("地址") | ||
| 61 | - private String address; | 69 | + @Schema(description = "电话", example = "18000000000") |
| 70 | + @ExcelProperty("电话") | ||
| 71 | + private String telephone; | ||
| 62 | 72 | ||
| 63 | - @Schema(description = "负责人编号") | ||
| 64 | - @ExcelProperty("负责人的用户编号") | ||
| 65 | - private Long ownerUserId; | 73 | + @Schema(description = "QQ", example = "25682") |
| 74 | + @ExcelProperty("QQ") | ||
| 75 | + private String qq; | ||
| 66 | 76 | ||
| 67 | - @Schema(description = "最后跟进时间") | ||
| 68 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 69 | - @ExcelProperty("最后跟进时间") | ||
| 70 | - private LocalDateTime contactLastTime; | 77 | + @Schema(description = "wechat", example = "25682") |
| 78 | + @ExcelProperty("wechat") | ||
| 79 | + private String wechat; | ||
| 71 | 80 | ||
| 72 | - @Schema(description = "备注", example = "随便") | ||
| 73 | - @ExcelProperty("备注") | ||
| 74 | - private String remark; | 81 | + @Schema(description = "email", example = "25682") |
| 82 | + @ExcelProperty("email") | ||
| 83 | + private String email; | ||
| 75 | 84 | ||
| 76 | - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 77 | - @ExcelProperty("创建时间") | ||
| 78 | - private LocalDateTime createTime; | 85 | + @Schema(description = "地区编号", example = "1024") |
| 86 | + @ExcelProperty("地区编号") | ||
| 87 | + private Integer areaId; | ||
| 88 | + @Schema(description = "地区名称", example = "北京市") | ||
| 89 | + @ExcelProperty("地区名称") | ||
| 90 | + private String areaName; | ||
| 91 | + @Schema(description = "详细地址", example = "北京市成华大道") | ||
| 92 | + @ExcelProperty("详细地址") | ||
| 93 | + private String detailAddress; | ||
| 79 | 94 | ||
| 80 | @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | 95 | @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") |
| 81 | @ExcelProperty(value = "所属行业", converter = DictConvert.class) | 96 | @ExcelProperty(value = "所属行业", converter = DictConvert.class) |
| @@ -92,24 +107,23 @@ public class CrmClueRespVO { | @@ -92,24 +107,23 @@ public class CrmClueRespVO { | ||
| 92 | @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) | 107 | @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) |
| 93 | private Integer source; | 108 | private Integer source; |
| 94 | 109 | ||
| 95 | - @Schema(description = "网址", example = "25682") | ||
| 96 | - @ExcelProperty("网址") | ||
| 97 | - private String website; | ||
| 98 | - | ||
| 99 | - @Schema(description = "QQ", example = "25682") | ||
| 100 | - @ExcelProperty("QQ") | ||
| 101 | - private String qq; | 110 | + @Schema(description = "备注", example = "随便") |
| 111 | + @ExcelProperty("备注") | ||
| 112 | + private String remark; | ||
| 102 | 113 | ||
| 103 | - @Schema(description = "wechat", example = "25682") | ||
| 104 | - @ExcelProperty("wechat") | ||
| 105 | - private String wechat; | 114 | + @Schema(description = "创建人", example = "1024") |
| 115 | + @ExcelProperty("创建人") | ||
| 116 | + private String creator; | ||
| 117 | + @Schema(description = "创建人名字", example = "芋道源码") | ||
| 118 | + @ExcelProperty("创建人名字") | ||
| 119 | + private String creatorName; | ||
| 106 | 120 | ||
| 107 | - @Schema(description = "email", example = "25682") | ||
| 108 | - @ExcelProperty("email") | ||
| 109 | - private String email; | 121 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 122 | + @ExcelProperty("创建时间") | ||
| 123 | + private LocalDateTime createTime; | ||
| 110 | 124 | ||
| 111 | - @Schema(description = "客户描述", example = "25682") | ||
| 112 | - @ExcelProperty("客户描述") | ||
| 113 | - private String description; | 125 | + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 126 | + @ExcelProperty("更新时间") | ||
| 127 | + private LocalDateTime updateTime; | ||
| 114 | 128 | ||
| 115 | } | 129 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java
| @@ -8,10 +8,12 @@ import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLevelEnum; | @@ -8,10 +8,12 @@ import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLevelEnum; | ||
| 8 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerIndustryParseFunction; | 8 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerIndustryParseFunction; |
| 9 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerLevelParseFunction; | 9 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerLevelParseFunction; |
| 10 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerSourceParseFunction; | 10 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerSourceParseFunction; |
| 11 | +import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAreaParseFunction; | ||
| 11 | import com.mzt.logapi.starter.annotation.DiffLogField; | 12 | import com.mzt.logapi.starter.annotation.DiffLogField; |
| 12 | import io.swagger.v3.oas.annotations.media.Schema; | 13 | import io.swagger.v3.oas.annotations.media.Schema; |
| 13 | import jakarta.validation.constraints.Email; | 14 | import jakarta.validation.constraints.Email; |
| 14 | import jakarta.validation.constraints.NotEmpty; | 15 | import jakarta.validation.constraints.NotEmpty; |
| 16 | +import jakarta.validation.constraints.NotNull; | ||
| 15 | import jakarta.validation.constraints.Size; | 17 | import jakarta.validation.constraints.Size; |
| 16 | import lombok.Data; | 18 | import lombok.Data; |
| 17 | import org.springframework.format.annotation.DateTimeFormat; | 19 | import org.springframework.format.annotation.DateTimeFormat; |
| @@ -21,7 +23,7 @@ import java.time.LocalDateTime; | @@ -21,7 +23,7 @@ import java.time.LocalDateTime; | ||
| 21 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | 23 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 22 | import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; | 24 | import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; |
| 23 | 25 | ||
| 24 | -@Schema(description = "管理后台 - CRM 线索 创建/更新 Request VO") | 26 | +@Schema(description = "管理后台 - CRM 线索创建/更新 Request VO") |
| 25 | @Data | 27 | @Data |
| 26 | public class CrmClueSaveReqVO { | 28 | public class CrmClueSaveReqVO { |
| 27 | 29 | ||
| @@ -33,36 +35,53 @@ public class CrmClueSaveReqVO { | @@ -33,36 +35,53 @@ public class CrmClueSaveReqVO { | ||
| 33 | @NotEmpty(message = "线索名称不能为空") | 35 | @NotEmpty(message = "线索名称不能为空") |
| 34 | private String name; | 36 | private String name; |
| 35 | 37 | ||
| 38 | + @Schema(description = "最后跟进时间") | ||
| 39 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 40 | + @DiffLogField(name = "最后跟进时间") | ||
| 41 | + private LocalDateTime contactLastTime; | ||
| 42 | + | ||
| 36 | @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") | 43 | @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") |
| 37 | @DiffLogField(name = "下次联系时间") | 44 | @DiffLogField(name = "下次联系时间") |
| 38 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 45 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 39 | private LocalDateTime contactNextTime; | 46 | private LocalDateTime contactNextTime; |
| 40 | 47 | ||
| 41 | - @Schema(description = "电话", example = "18000000000") | ||
| 42 | - @DiffLogField(name = "电话") | ||
| 43 | - @Telephone | ||
| 44 | - private String telephone; | 48 | + @Schema(description = "负责人编号", example = "2048") |
| 49 | + @NotNull(message = "负责人编号不能为空") | ||
| 50 | + private Long ownerUserId; | ||
| 45 | 51 | ||
| 46 | @Schema(description = "手机号", example = "18000000000") | 52 | @Schema(description = "手机号", example = "18000000000") |
| 47 | @DiffLogField(name = "手机号") | 53 | @DiffLogField(name = "手机号") |
| 48 | @Mobile | 54 | @Mobile |
| 49 | private String mobile; | 55 | private String mobile; |
| 50 | 56 | ||
| 51 | - @Schema(description = "地址", example = "北京市海淀区") | ||
| 52 | - @DiffLogField(name = "地址") | ||
| 53 | - private String address; | 57 | + @Schema(description = "电话", example = "18000000000") |
| 58 | + @DiffLogField(name = "电话") | ||
| 59 | + @Telephone | ||
| 60 | + private String telephone; | ||
| 54 | 61 | ||
| 55 | - @Schema(description = "最后跟进时间") | ||
| 56 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 57 | - @DiffLogField(name = "最后跟进时间") | ||
| 58 | - private LocalDateTime contactLastTime; | 62 | + @Schema(description = "QQ", example = "123456789") |
| 63 | + @DiffLogField(name = "QQ") | ||
| 64 | + @Size(max = 20, message = "QQ长度不能超过 20 个字符") | ||
| 65 | + private String qq; | ||
| 59 | 66 | ||
| 60 | - @Schema(description = "负责人编号", example = "2048") | ||
| 61 | - private Long ownerUserId; | 67 | + @Schema(description = "微信", example = "123456789") |
| 68 | + @DiffLogField(name = "微信") | ||
| 69 | + @Size(max = 255, message = "微信长度不能超过 255 个字符") | ||
| 70 | + private String wechat; | ||
| 62 | 71 | ||
| 63 | - @Schema(description = "备注", example = "随便") | ||
| 64 | - @DiffLogField(name = "备注") | ||
| 65 | - private String remark; | 72 | + @Schema(description = "邮箱", example = "123456789@qq.com") |
| 73 | + @DiffLogField(name = "邮箱") | ||
| 74 | + @Email(message = "邮箱格式不正确") | ||
| 75 | + @Size(max = 255, message = "邮箱长度不能超过 255 个字符") | ||
| 76 | + private String email; | ||
| 77 | + | ||
| 78 | + @Schema(description = "地区编号", example = "20158") | ||
| 79 | + @DiffLogField(name = "地区编号", function = SysAreaParseFunction.NAME) | ||
| 80 | + private Integer areaId; | ||
| 81 | + | ||
| 82 | + @Schema(description = "详细地址", example = "北京市海淀区") | ||
| 83 | + @DiffLogField(name = "详细地址") | ||
| 84 | + private String detailAddress; | ||
| 66 | 85 | ||
| 67 | @Schema(description = "所属行业", example = "1") | 86 | @Schema(description = "所属行业", example = "1") |
| 68 | @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) | 87 | @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) |
| @@ -78,28 +97,13 @@ public class CrmClueSaveReqVO { | @@ -78,28 +97,13 @@ public class CrmClueSaveReqVO { | ||
| 78 | @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) | 97 | @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) |
| 79 | private Integer source; | 98 | private Integer source; |
| 80 | 99 | ||
| 81 | - @Schema(description = "网址", example = "https://www.baidu.com") | ||
| 82 | - @DiffLogField(name = "网址") | ||
| 83 | - private String website; | ||
| 84 | - | ||
| 85 | - @Schema(description = "QQ", example = "123456789") | ||
| 86 | - @DiffLogField(name = "QQ") | ||
| 87 | - @Size(max = 20, message = "QQ长度不能超过 20 个字符") | ||
| 88 | - private String qq; | ||
| 89 | - | ||
| 90 | - @Schema(description = "微信", example = "123456789") | ||
| 91 | - @DiffLogField(name = "微信") | ||
| 92 | - @Size(max = 255, message = "微信长度不能超过 255 个字符") | ||
| 93 | - private String wechat; | ||
| 94 | - | ||
| 95 | - @Schema(description = "邮箱", example = "123456789@qq.com") | ||
| 96 | - @DiffLogField(name = "邮箱") | ||
| 97 | - @Email(message = "邮箱格式不正确") | ||
| 98 | - @Size(max = 255, message = "邮箱长度不能超过 255 个字符") | ||
| 99 | - private String email; | ||
| 100 | - | ||
| 101 | @Schema(description = "客户描述", example = "任意文字") | 100 | @Schema(description = "客户描述", example = "任意文字") |
| 102 | @DiffLogField(name = "客户描述") | 101 | @DiffLogField(name = "客户描述") |
| 103 | @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") | 102 | @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") |
| 104 | private String description; | 103 | private String description; |
| 104 | + | ||
| 105 | + @Schema(description = "备注", example = "随便") | ||
| 106 | + @DiffLogField(name = "备注") | ||
| 107 | + private String remark; | ||
| 108 | + | ||
| 105 | } | 109 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTranslateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import jakarta.validation.constraints.NotEmpty; | ||
| 5 | -import lombok.Data; | ||
| 6 | - | ||
| 7 | -import java.util.Set; | ||
| 8 | - | ||
| 9 | -@Schema(description = "管理后台 - 线索转化为客户 Request VO") | ||
| 10 | -@Data | ||
| 11 | -public class CrmClueTranslateReqVO { | ||
| 12 | - | ||
| 13 | - @Schema(description = "线索编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1024, 1025]") | ||
| 14 | - @NotEmpty(message = "线索编号不能为空") | ||
| 15 | - private Set<Long> ids; | ||
| 16 | - | ||
| 17 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java
| @@ -2,24 +2,24 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact; | @@ -2,24 +2,24 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.lang.Assert; | 4 | import cn.hutool.core.lang.Assert; |
| 5 | -import cn.hutool.core.util.NumberUtil; | ||
| 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 9 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 9 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 10 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 10 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 11 | +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | ||
| 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 12 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 12 | import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*; | 13 | import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*; |
| 13 | -import cn.iocoder.yudao.module.crm.convert.contact.CrmContactConvert; | ||
| 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; | 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; |
| 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 16 | -import cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants; | ||
| 17 | import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; | 16 | import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; |
| 18 | import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; | 17 | import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; |
| 19 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | 18 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 19 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 20 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 20 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | 21 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 21 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 22 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 22 | -import com.google.common.collect.Lists; | ||
| 23 | import io.swagger.v3.oas.annotations.Operation; | 23 | import io.swagger.v3.oas.annotations.Operation; |
| 24 | import io.swagger.v3.oas.annotations.Parameter; | 24 | import io.swagger.v3.oas.annotations.Parameter; |
| 25 | import io.swagger.v3.oas.annotations.tags.Tag; | 25 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -37,12 +37,13 @@ import java.util.List; | @@ -37,12 +37,13 @@ import java.util.List; | ||
| 37 | import java.util.Map; | 37 | import java.util.Map; |
| 38 | import java.util.stream.Stream; | 38 | import java.util.stream.Stream; |
| 39 | 39 | ||
| 40 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 41 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 40 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 42 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | 41 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 43 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 42 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 43 | +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||
| 44 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 44 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 45 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 45 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 46 | +import static java.util.Collections.singletonList; | ||
| 46 | 47 | ||
| 47 | @Tag(name = "管理后台 - CRM 联系人") | 48 | @Tag(name = "管理后台 - CRM 联系人") |
| 48 | @RestController | 49 | @RestController |
| @@ -60,6 +61,8 @@ public class CrmContactController { | @@ -60,6 +61,8 @@ public class CrmContactController { | ||
| 60 | 61 | ||
| 61 | @Resource | 62 | @Resource |
| 62 | private AdminUserApi adminUserApi; | 63 | private AdminUserApi adminUserApi; |
| 64 | + @Resource | ||
| 65 | + private DeptApi deptApi; | ||
| 63 | 66 | ||
| 64 | @PostMapping("/create") | 67 | @PostMapping("/create") |
| 65 | @Operation(summary = "创建联系人") | 68 | @Operation(summary = "创建联系人") |
| @@ -92,36 +95,24 @@ public class CrmContactController { | @@ -92,36 +95,24 @@ public class CrmContactController { | ||
| 92 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") | 95 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") |
| 93 | public CommonResult<CrmContactRespVO> getContact(@RequestParam("id") Long id) { | 96 | public CommonResult<CrmContactRespVO> getContact(@RequestParam("id") Long id) { |
| 94 | CrmContactDO contact = contactService.getContact(id); | 97 | CrmContactDO contact = contactService.getContact(id); |
| 98 | + return success(buildContactDetail(contact)); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + private CrmContactRespVO buildContactDetail(CrmContactDO contact) { | ||
| 95 | if (contact == null) { | 102 | if (contact == null) { |
| 96 | - throw exception(ErrorCodeConstants.CONTACT_NOT_EXISTS); | 103 | + return null; |
| 97 | } | 104 | } |
| 98 | - // 1. 获取用户名 | ||
| 99 | - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(CollUtil.removeNull(Lists.newArrayList( | ||
| 100 | - NumberUtil.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | ||
| 101 | - // 2. 获取客户信息 | ||
| 102 | - List<CrmCustomerDO> customerList = customerService.getCustomerList( | ||
| 103 | - Collections.singletonList(contact.getCustomerId())); | ||
| 104 | - // 3. 直属上级 | ||
| 105 | - List<CrmContactDO> parentContactList = contactService.getContactListByIds( | ||
| 106 | - Collections.singletonList(contact.getParentId()), getLoginUserId()); | ||
| 107 | - return success(CrmContactConvert.INSTANCE.convert(contact, userMap, customerList, parentContactList)); | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - @GetMapping("/list-by-ids") | ||
| 111 | - @Operation(summary = "获得联系人列表") | ||
| 112 | - @Parameter(name = "ids", description = "编号", required = true, example = "[1024]") | ||
| 113 | - @PreAuthorize("@ss.hasPermission('crm:contact:query')") | ||
| 114 | - public CommonResult<List<CrmContactRespVO>> getContactListByIds(@RequestParam("ids") List<Long> ids) { | ||
| 115 | - return success(BeanUtils.toBean(contactService.getContactListByIds(ids, getLoginUserId()), CrmContactRespVO.class)); | 105 | + return buildContactDetailList(singletonList(contact)).get(0); |
| 116 | } | 106 | } |
| 117 | 107 | ||
| 118 | @GetMapping("/simple-all-list") | 108 | @GetMapping("/simple-all-list") |
| 119 | @Operation(summary = "获得联系人的精简列表") | 109 | @Operation(summary = "获得联系人的精简列表") |
| 120 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") | 110 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") |
| 121 | public CommonResult<List<CrmContactRespVO>> getSimpleContactList() { | 111 | public CommonResult<List<CrmContactRespVO>> getSimpleContactList() { |
| 122 | - List<CrmContactDO> list = contactService.getSimpleContactList(getLoginUserId()); | 112 | + List<CrmContactDO> list = contactService.getContactList(getLoginUserId()); |
| 123 | return success(convertList(list, contact -> // 只返回 id、name 字段 | 113 | return success(convertList(list, contact -> // 只返回 id、name 字段 |
| 124 | - new CrmContactRespVO().setId(contact.getId()).setName(contact.getName()))); | 114 | + new CrmContactRespVO().setId(contact.getId()).setName(contact.getName()) |
| 115 | + .setCustomerId(contact.getCustomerId()))); | ||
| 125 | } | 116 | } |
| 126 | 117 | ||
| 127 | @GetMapping("/page") | 118 | @GetMapping("/page") |
| @@ -129,7 +120,7 @@ public class CrmContactController { | @@ -129,7 +120,7 @@ public class CrmContactController { | ||
| 129 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") | 120 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") |
| 130 | public CommonResult<PageResult<CrmContactRespVO>> getContactPage(@Valid CrmContactPageReqVO pageVO) { | 121 | public CommonResult<PageResult<CrmContactRespVO>> getContactPage(@Valid CrmContactPageReqVO pageVO) { |
| 131 | PageResult<CrmContactDO> pageResult = contactService.getContactPage(pageVO, getLoginUserId()); | 122 | PageResult<CrmContactDO> pageResult = contactService.getContactPage(pageVO, getLoginUserId()); |
| 132 | - return success(buildContactDetailPage(pageResult)); | 123 | + return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); |
| 133 | } | 124 | } |
| 134 | 125 | ||
| 135 | @GetMapping("/page-by-customer") | 126 | @GetMapping("/page-by-customer") |
| @@ -137,7 +128,15 @@ public class CrmContactController { | @@ -137,7 +128,15 @@ public class CrmContactController { | ||
| 137 | public CommonResult<PageResult<CrmContactRespVO>> getContactPageByCustomer(@Valid CrmContactPageReqVO pageVO) { | 128 | public CommonResult<PageResult<CrmContactRespVO>> getContactPageByCustomer(@Valid CrmContactPageReqVO pageVO) { |
| 138 | Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); | 129 | Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); |
| 139 | PageResult<CrmContactDO> pageResult = contactService.getContactPageByCustomerId(pageVO); | 130 | PageResult<CrmContactDO> pageResult = contactService.getContactPageByCustomerId(pageVO); |
| 140 | - return success(buildContactDetailPage(pageResult)); | 131 | + return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); |
| 132 | + } | ||
| 133 | + | ||
| 134 | + @GetMapping("/page-by-business") | ||
| 135 | + @Operation(summary = "获得联系人分页,基于指定商机") | ||
| 136 | + public CommonResult<PageResult<CrmContactRespVO>> getContactPageByBusiness(@Valid CrmContactPageReqVO pageVO) { | ||
| 137 | + Assert.notNull(pageVO.getBusinessId(), "商机编号不能为空"); | ||
| 138 | + PageResult<CrmContactDO> pageResult = contactService.getContactPageByBusinessId(pageVO); | ||
| 139 | + return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); | ||
| 141 | } | 140 | } |
| 142 | 141 | ||
| 143 | @GetMapping("/export-excel") | 142 | @GetMapping("/export-excel") |
| @@ -147,32 +146,39 @@ public class CrmContactController { | @@ -147,32 +146,39 @@ public class CrmContactController { | ||
| 147 | public void exportContactExcel(@Valid CrmContactPageReqVO exportReqVO, | 146 | public void exportContactExcel(@Valid CrmContactPageReqVO exportReqVO, |
| 148 | HttpServletResponse response) throws IOException { | 147 | HttpServletResponse response) throws IOException { |
| 149 | exportReqVO.setPageNo(PAGE_SIZE_NONE); | 148 | exportReqVO.setPageNo(PAGE_SIZE_NONE); |
| 150 | - PageResult<CrmContactDO> pageResult = contactService.getContactPage(exportReqVO, getLoginUserId()); | ||
| 151 | - ExcelUtils.write(response, "联系人.xls", "数据", CrmContactRespVO.class, | ||
| 152 | - buildContactDetailPage(pageResult).getList()); | ||
| 153 | - } | ||
| 154 | - | ||
| 155 | - /** | ||
| 156 | - * 构建详细的联系人分页结果 | ||
| 157 | - * | ||
| 158 | - * @param pageResult 简单的联系人分页结果 | ||
| 159 | - * @return 详细的联系人分页结果 | ||
| 160 | - */ | ||
| 161 | - private PageResult<CrmContactRespVO> buildContactDetailPage(PageResult<CrmContactDO> pageResult) { | ||
| 162 | - List<CrmContactDO> contactList = pageResult.getList(); | 149 | + List<CrmContactDO> list = contactService.getContactPage(exportReqVO, getLoginUserId()).getList(); |
| 150 | + ExcelUtils.write(response, "联系人.xls", "数据", CrmContactRespVO.class, buildContactDetailList(list)); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + private List<CrmContactRespVO> buildContactDetailList(List<CrmContactDO> contactList) { | ||
| 163 | if (CollUtil.isEmpty(contactList)) { | 154 | if (CollUtil.isEmpty(contactList)) { |
| 164 | - return PageResult.empty(pageResult.getTotal()); | 155 | + return Collections.emptyList(); |
| 165 | } | 156 | } |
| 166 | - // 1. 获取客户列表 | ||
| 167 | - List<CrmCustomerDO> crmCustomerDOList = customerService.getCustomerList( | 157 | + // 1.1 获取客户列表 |
| 158 | + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap( | ||
| 168 | convertSet(contactList, CrmContactDO::getCustomerId)); | 159 | convertSet(contactList, CrmContactDO::getCustomerId)); |
| 169 | - // 2. 获取创建人、负责人列表 | 160 | + // 1.2 获取创建人、负责人列表 |
| 170 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList, | 161 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList, |
| 171 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | 162 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); |
| 172 | - // 3. 直属上级 | ||
| 173 | - List<CrmContactDO> parentContactList = contactService.getContactListByIds( | ||
| 174 | - convertSet(contactList, CrmContactDO::getParentId), getLoginUserId()); | ||
| 175 | - return CrmContactConvert.INSTANCE.convertPage(pageResult, userMap, crmCustomerDOList, parentContactList); | 163 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); |
| 164 | + // 1.3 直属上级 Map | ||
| 165 | + Map<Long, CrmContactDO> parentContactMap = contactService.getContactMap( | ||
| 166 | + convertSet(contactList, CrmContactDO::getParentId)); | ||
| 167 | + // 2. 转换成 VO | ||
| 168 | + return BeanUtils.toBean(contactList, CrmContactRespVO.class, contactVO -> { | ||
| 169 | + contactVO.setAreaName(AreaUtils.format(contactVO.getAreaId())); | ||
| 170 | + // 2.1 设置客户名称 | ||
| 171 | + MapUtils.findAndThen(customerMap, contactVO.getCustomerId(), customer -> contactVO.setCustomerName(customer.getName())); | ||
| 172 | + // 2.2 设置创建人、负责人名称 | ||
| 173 | + MapUtils.findAndThen(userMap, NumberUtils.parseLong(contactVO.getCreator()), | ||
| 174 | + user -> contactVO.setCreatorName(user.getNickname())); | ||
| 175 | + MapUtils.findAndThen(userMap, contactVO.getOwnerUserId(), user -> { | ||
| 176 | + contactVO.setOwnerUserName(user.getNickname()); | ||
| 177 | + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contactVO.setOwnerUserDeptName(dept.getName())); | ||
| 178 | + }); | ||
| 179 | + // 2.3 设置直属上级名称 | ||
| 180 | + findAndThen(parentContactMap, contactVO.getParentId(), contact -> contactVO.setParentName(contact.getName())); | ||
| 181 | + }); | ||
| 176 | } | 182 | } |
| 177 | 183 | ||
| 178 | @PutMapping("/transfer") | 184 | @PutMapping("/transfer") |
| @@ -183,7 +189,7 @@ public class CrmContactController { | @@ -183,7 +189,7 @@ public class CrmContactController { | ||
| 183 | return success(true); | 189 | return success(true); |
| 184 | } | 190 | } |
| 185 | 191 | ||
| 186 | - // ================== 关联/取关联系人 =================== | 192 | + // ================== 关联/取关商机 =================== |
| 187 | 193 | ||
| 188 | @PostMapping("/create-business-list") | 194 | @PostMapping("/create-business-list") |
| 189 | @Operation(summary = "创建联系人与商机的关联") | 195 | @Operation(summary = "创建联系人与商机的关联") |
| @@ -193,6 +199,15 @@ public class CrmContactController { | @@ -193,6 +199,15 @@ public class CrmContactController { | ||
| 193 | return success(true); | 199 | return success(true); |
| 194 | } | 200 | } |
| 195 | 201 | ||
| 202 | + | ||
| 203 | + @PostMapping("/create-business-list2") | ||
| 204 | + @Operation(summary = "创建联系人与商机的关联") | ||
| 205 | + @PreAuthorize("@ss.hasPermission('crm:contact:create-business')") | ||
| 206 | + public CommonResult<Boolean> createContactBusinessList2(@Valid @RequestBody CrmContactBusiness2ReqVO createReqVO) { | ||
| 207 | + contactBusinessLinkService.createContactBusinessList2(createReqVO); | ||
| 208 | + return success(true); | ||
| 209 | + } | ||
| 210 | + | ||
| 196 | @DeleteMapping("/delete-business-list") | 211 | @DeleteMapping("/delete-business-list") |
| 197 | @Operation(summary = "删除联系人与联系人的关联") | 212 | @Operation(summary = "删除联系人与联系人的关联") |
| 198 | @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") | 213 | @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") |
| @@ -201,4 +216,12 @@ public class CrmContactController { | @@ -201,4 +216,12 @@ public class CrmContactController { | ||
| 201 | return success(true); | 216 | return success(true); |
| 202 | } | 217 | } |
| 203 | 218 | ||
| 219 | + @DeleteMapping("/delete-business-list2") | ||
| 220 | + @Operation(summary = "删除联系人与联系人的关联") | ||
| 221 | + @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") | ||
| 222 | + public CommonResult<Boolean> deleteContactBusinessList(@Valid @RequestBody CrmContactBusiness2ReqVO deleteReqVO) { | ||
| 223 | + contactBusinessLinkService.deleteContactBusinessList2(deleteReqVO); | ||
| 224 | + return success(true); | ||
| 225 | + } | ||
| 226 | + | ||
| 204 | } | 227 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import jakarta.validation.constraints.NotEmpty; | ||
| 5 | +import jakarta.validation.constraints.NotNull; | ||
| 6 | +import lombok.Data; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 【商机关联联系人】用于关联,取消关联的操作 | ||
| 11 | +@Data | ||
| 12 | +public class CrmContactBusiness2ReqVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") | ||
| 15 | + @NotNull(message="商机不能为空") | ||
| 16 | + private Long businessId; | ||
| 17 | + | ||
| 18 | + @Schema(description = "联系人编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") | ||
| 19 | + @NotEmpty(message="联系人数组不能为空") | ||
| 20 | + private List<Long> contactIds; | ||
| 21 | + | ||
| 22 | +} | ||
| 0 | \ No newline at end of file | 23 | \ No newline at end of file |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java
| @@ -7,7 +7,7 @@ import lombok.Data; | @@ -7,7 +7,7 @@ import lombok.Data; | ||
| 7 | 7 | ||
| 8 | import java.util.List; | 8 | import java.util.List; |
| 9 | 9 | ||
| 10 | -@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 用于关联,取消关联的操作 | 10 | +@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 【联系人关联商机】用于关联,取消关联的操作 |
| 11 | @Data | 11 | @Data |
| 12 | public class CrmContactBusinessReqVO { | 12 | public class CrmContactBusinessReqVO { |
| 13 | 13 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java
| @@ -39,4 +39,7 @@ public class CrmContactPageReqVO extends PageParam { | @@ -39,4 +39,7 @@ public class CrmContactPageReqVO extends PageParam { | ||
| 39 | @InEnum(CrmSceneTypeEnum.class) | 39 | @InEnum(CrmSceneTypeEnum.class) |
| 40 | private Integer sceneType; // 场景类型,为 null 时则表示全部 | 40 | private Integer sceneType; // 场景类型,为 null 时则表示全部 |
| 41 | 41 | ||
| 42 | + @Schema(description = "商机编号", example = "10430") | ||
| 43 | + private Long businessId; | ||
| 44 | + | ||
| 42 | } | 45 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java
| @@ -20,29 +20,36 @@ public class CrmContactRespVO { | @@ -20,29 +20,36 @@ public class CrmContactRespVO { | ||
| 20 | @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") | 20 | @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") |
| 21 | private Long id; | 21 | private Long id; |
| 22 | 22 | ||
| 23 | - @Schema(description = "姓名", example = "芋艿") | ||
| 24 | - @ExcelProperty(value = "姓名", order = 1) | 23 | + @Schema(description = "联系人姓名", example = "芋艿") |
| 24 | + @ExcelProperty(value = "联系人姓名", order = 1) | ||
| 25 | private String name; | 25 | private String name; |
| 26 | 26 | ||
| 27 | @Schema(description = "客户编号", example = "10795") | 27 | @Schema(description = "客户编号", example = "10795") |
| 28 | private Long customerId; | 28 | private Long customerId; |
| 29 | + @ExcelProperty(value = "客户名称", order = 2) | ||
| 30 | + @Schema(description = "客户名字", example = "test") | ||
| 31 | + private String customerName; | ||
| 29 | 32 | ||
| 30 | - @Schema(description = "性别") | ||
| 31 | - @ExcelProperty(value = "性别", converter = DictConvert.class, order = 3) | ||
| 32 | - @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_SEX) | ||
| 33 | - private Integer sex; | 33 | + @Schema(description = "最后跟进时间") |
| 34 | + @ExcelProperty(value = "最后跟进时间", order = 6) | ||
| 35 | + private LocalDateTime contactLastTime; | ||
| 34 | 36 | ||
| 35 | - @Schema(description = "职位") | ||
| 36 | - @ExcelProperty(value = "职位", order = 3) | ||
| 37 | - private String post; | 37 | + @Schema(description = "最后跟进内容") |
| 38 | + @ExcelProperty(value = "最后跟进内容", order = 6) | ||
| 39 | + private String contactLastContent; | ||
| 38 | 40 | ||
| 39 | - @Schema(description = "是否关键决策人") | ||
| 40 | - @ExcelProperty(value = "是否关键决策人", converter = DictConvert.class, order = 3) | ||
| 41 | - @DictFormat(DictTypeConstants.BOOLEAN_STRING) | ||
| 42 | - private Boolean master; | 41 | + @Schema(description = "下次联系时间") |
| 42 | + @ExcelProperty(value = "下次联系时间", order = 6) | ||
| 43 | + private LocalDateTime contactNextTime; | ||
| 43 | 44 | ||
| 44 | - @Schema(description = "直属上级", example = "23457") | ||
| 45 | - private Long parentId; | 45 | + @Schema(description = "负责人编号") |
| 46 | + private Long ownerUserId; | ||
| 47 | + @Schema(description = "负责人名字", example = "25682") | ||
| 48 | + @ExcelProperty("负责人名字") | ||
| 49 | + private String ownerUserName; | ||
| 50 | + @Schema(description = "负责人部门") | ||
| 51 | + @ExcelProperty("负责人部门") | ||
| 52 | + private String ownerUserDeptName; | ||
| 46 | 53 | ||
| 47 | @Schema(description = "手机号", example = "1387171766") | 54 | @Schema(description = "手机号", example = "1387171766") |
| 48 | @ExcelProperty(value = "手机号", order = 4) | 55 | @ExcelProperty(value = "手机号", order = 4) |
| @@ -52,6 +59,10 @@ public class CrmContactRespVO { | @@ -52,6 +59,10 @@ public class CrmContactRespVO { | ||
| 52 | @ExcelProperty(value = "电话", order = 4) | 59 | @ExcelProperty(value = "电话", order = 4) |
| 53 | private String telephone; | 60 | private String telephone; |
| 54 | 61 | ||
| 62 | + @Schema(description = "电子邮箱", example = "1111@22.com") | ||
| 63 | + @ExcelProperty(value = "邮箱", order = 4) | ||
| 64 | + private String email; | ||
| 65 | + | ||
| 55 | @Schema(description = "QQ", example = "197272662") | 66 | @Schema(description = "QQ", example = "197272662") |
| 56 | @ExcelProperty(value = "QQ", order = 4) | 67 | @ExcelProperty(value = "QQ", order = 4) |
| 57 | private Long qq; | 68 | private Long qq; |
| @@ -60,53 +71,52 @@ public class CrmContactRespVO { | @@ -60,53 +71,52 @@ public class CrmContactRespVO { | ||
| 60 | @ExcelProperty(value = "微信", order = 4) | 71 | @ExcelProperty(value = "微信", order = 4) |
| 61 | private String wechat; | 72 | private String wechat; |
| 62 | 73 | ||
| 63 | - @Schema(description = "电子邮箱", example = "1111@22.com") | ||
| 64 | - @ExcelProperty(value = "邮箱", order = 4) | ||
| 65 | - private String email; | ||
| 66 | - | ||
| 67 | @Schema(description = "地区编号", example = "20158") | 74 | @Schema(description = "地区编号", example = "20158") |
| 68 | private Integer areaId; | 75 | private Integer areaId; |
| 76 | + @Schema(description = "地区名", example = "上海上海市浦东新区") | ||
| 77 | + @ExcelProperty(value = "地区", order = 5) | ||
| 78 | + private String areaName; | ||
| 69 | 79 | ||
| 70 | @Schema(description = "地址") | 80 | @Schema(description = "地址") |
| 71 | @ExcelProperty(value = "地址", order = 5) | 81 | @ExcelProperty(value = "地址", order = 5) |
| 72 | private String detailAddress; | 82 | private String detailAddress; |
| 73 | 83 | ||
| 74 | - @Schema(description = "备注", example = "你说的对") | ||
| 75 | - @ExcelProperty(value = "备注", order = 6) | ||
| 76 | - private String remark; | 84 | + @Schema(description = "性别") |
| 85 | + @ExcelProperty(value = "性别", converter = DictConvert.class, order = 3) | ||
| 86 | + @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_SEX) | ||
| 87 | + private Integer sex; | ||
| 77 | 88 | ||
| 78 | - @Schema(description = "负责人用户编号", example = "14334") | ||
| 79 | - private Long ownerUserId; | 89 | + @Schema(description = "是否关键决策人") |
| 90 | + @ExcelProperty(value = "是否关键决策人", converter = DictConvert.class, order = 3) | ||
| 91 | + @DictFormat(DictTypeConstants.BOOLEAN_STRING) | ||
| 92 | + private Boolean master; | ||
| 80 | 93 | ||
| 81 | - @Schema(description = "最后跟进时间") | ||
| 82 | - @ExcelProperty(value = "最后跟进时间", order = 6) | ||
| 83 | - private LocalDateTime contactLastTime; | 94 | + @Schema(description = "职位") |
| 95 | + @ExcelProperty(value = "职位", order = 3) | ||
| 96 | + private String post; | ||
| 84 | 97 | ||
| 85 | - @Schema(description = "下次联系时间") | ||
| 86 | - @ExcelProperty(value = "下次联系时间", order = 6) | ||
| 87 | - private LocalDateTime contactNextTime; | 98 | + @Schema(description = "直属上级", example = "23457") |
| 99 | + private Long parentId; | ||
| 100 | + @Schema(description = "直属上级名", example = "芋头") | ||
| 101 | + @ExcelProperty(value = "直属上级", order = 4) | ||
| 102 | + private String parentName; | ||
| 103 | + | ||
| 104 | + @Schema(description = "备注", example = "你说的对") | ||
| 105 | + @ExcelProperty(value = "备注", order = 6) | ||
| 106 | + private String remark; | ||
| 88 | 107 | ||
| 89 | @Schema(description = "创建人", example = "25682") | 108 | @Schema(description = "创建人", example = "25682") |
| 90 | private String creator; | 109 | private String creator; |
| 91 | - | ||
| 92 | @Schema(description = "创建人名字", example = "test") | 110 | @Schema(description = "创建人名字", example = "test") |
| 93 | @ExcelProperty(value = "创建人", order = 8) | 111 | @ExcelProperty(value = "创建人", order = 8) |
| 94 | private String creatorName; | 112 | private String creatorName; |
| 95 | 113 | ||
| 96 | - @ExcelProperty(value = "客户名称", order = 2) | ||
| 97 | - @Schema(description = "客户名字", example = "test") | ||
| 98 | - private String customerName; | 114 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 115 | + @ExcelProperty("创建时间") | ||
| 116 | + private LocalDateTime createTime; | ||
| 99 | 117 | ||
| 100 | - @Schema(description = "负责人", example = "test") | ||
| 101 | - @ExcelProperty(value = "负责人", order = 7) | ||
| 102 | - private String ownerUserName; | ||
| 103 | - | ||
| 104 | - @Schema(description = "直属上级名", example = "芋头") | ||
| 105 | - @ExcelProperty(value = "直属上级", order = 4) | ||
| 106 | - private String parentName; | ||
| 107 | - | ||
| 108 | - @Schema(description = "地区名", example = "上海上海市浦东新区") | ||
| 109 | - @ExcelProperty(value = "地区", order = 5) | ||
| 110 | - private String areaName; | 118 | + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 119 | + @ExcelProperty("更新时间") | ||
| 120 | + private LocalDateTime updateTime; | ||
| 111 | 121 | ||
| 112 | } | 122 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java
| @@ -13,7 +13,6 @@ import org.springframework.format.annotation.DateTimeFormat; | @@ -13,7 +13,6 @@ import org.springframework.format.annotation.DateTimeFormat; | ||
| 13 | import java.time.LocalDateTime; | 13 | import java.time.LocalDateTime; |
| 14 | 14 | ||
| 15 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; | 15 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; |
| 16 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 17 | 16 | ||
| 18 | @Schema(description = "管理后台 - CRM 联系人创建/更新 Request VO") | 17 | @Schema(description = "管理后台 - CRM 联系人创建/更新 Request VO") |
| 19 | @Data | 18 | @Data |
| @@ -28,24 +27,19 @@ public class CrmContactSaveReqVO { | @@ -28,24 +27,19 @@ public class CrmContactSaveReqVO { | ||
| 28 | private String name; | 27 | private String name; |
| 29 | 28 | ||
| 30 | @Schema(description = "客户编号", example = "10795") | 29 | @Schema(description = "客户编号", example = "10795") |
| 30 | + @NotNull(message = "客户编号不能为空") | ||
| 31 | @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) | 31 | @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) |
| 32 | private Long customerId; | 32 | private Long customerId; |
| 33 | 33 | ||
| 34 | - @Schema(description = "性别") | ||
| 35 | - @DiffLogField(name = "性别", function = SysSexParseFunction.NAME) | ||
| 36 | - private Integer sex; | ||
| 37 | - | ||
| 38 | - @Schema(description = "职位") | ||
| 39 | - @DiffLogField(name = "职位") | ||
| 40 | - private String post; | ||
| 41 | - | ||
| 42 | - @Schema(description = "是否关键决策人") | ||
| 43 | - @DiffLogField(name = "关键决策人", function = SysBooleanParseFunction.NAME) | ||
| 44 | - private Boolean master; | 34 | + @Schema(description = "下次联系时间") |
| 35 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) | ||
| 36 | + @DiffLogField(name = "下次联系时间") | ||
| 37 | + private LocalDateTime contactNextTime; | ||
| 45 | 38 | ||
| 46 | - @Schema(description = "直属上级", example = "23457") | ||
| 47 | - @DiffLogField(name = "直属上级", function = CrmContactParseFunction.NAME) | ||
| 48 | - private Long parentId; | 39 | + @Schema(description = "负责人用户编号", example = "14334") |
| 40 | + @NotNull(message = "负责人不能为空") | ||
| 41 | + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) | ||
| 42 | + private Long ownerUserId; | ||
| 49 | 43 | ||
| 50 | @Schema(description = "手机号", example = "1387171766") | 44 | @Schema(description = "手机号", example = "1387171766") |
| 51 | @Mobile | 45 | @Mobile |
| @@ -78,24 +72,25 @@ public class CrmContactSaveReqVO { | @@ -78,24 +72,25 @@ public class CrmContactSaveReqVO { | ||
| 78 | @DiffLogField(name = "地址") | 72 | @DiffLogField(name = "地址") |
| 79 | private String detailAddress; | 73 | private String detailAddress; |
| 80 | 74 | ||
| 81 | - @Schema(description = "备注", example = "你说的对") | ||
| 82 | - @DiffLogField(name = "备注") | ||
| 83 | - private String remark; | 75 | + @Schema(description = "性别") |
| 76 | + @DiffLogField(name = "性别", function = SysSexParseFunction.NAME) | ||
| 77 | + private Integer sex; | ||
| 84 | 78 | ||
| 85 | - @Schema(description = "负责人用户编号", example = "14334") | ||
| 86 | - @NotNull(message = "负责人不能为空") | ||
| 87 | - @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) | ||
| 88 | - private Long ownerUserId; | 79 | + @Schema(description = "是否关键决策人") |
| 80 | + @DiffLogField(name = "关键决策人", function = SysBooleanParseFunction.NAME) | ||
| 81 | + private Boolean master; | ||
| 82 | + | ||
| 83 | + @Schema(description = "职位") | ||
| 84 | + @DiffLogField(name = "职位") | ||
| 85 | + private String post; | ||
| 89 | 86 | ||
| 90 | - @Schema(description = "最后跟进时间") | ||
| 91 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 92 | - @DiffLogField(name = "最后跟进时间") | ||
| 93 | - private LocalDateTime contactLastTime; | 87 | + @Schema(description = "直属上级", example = "23457") |
| 88 | + @DiffLogField(name = "直属上级", function = CrmContactParseFunction.NAME) | ||
| 89 | + private Long parentId; | ||
| 94 | 90 | ||
| 95 | - @Schema(description = "下次联系时间") | ||
| 96 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) | ||
| 97 | - @DiffLogField(name = "下次联系时间") | ||
| 98 | - private LocalDateTime contactNextTime; | 91 | + @Schema(description = "备注", example = "你说的对") |
| 92 | + @DiffLogField(name = "备注") | ||
| 93 | + private String remark; | ||
| 99 | 94 | ||
| 100 | @Schema(description = "关联商机 ID", example = "122233") | 95 | @Schema(description = "关联商机 ID", example = "122233") |
| 101 | private Long businessId; // 注意:该字段用于在【商机】详情界面「新建联系人」时,自动进行关联 | 96 | private Long businessId; // 注意:该字段用于在【商机】详情界面「新建联系人」时,自动进行关联 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contract; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 5 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigRespVO; | ||
| 6 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigSaveReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; | ||
| 8 | +import cn.iocoder.yudao.module.crm.service.contract.CrmContractConfigService; | ||
| 9 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 10 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 11 | +import jakarta.annotation.Resource; | ||
| 12 | +import jakarta.validation.Valid; | ||
| 13 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 14 | +import org.springframework.validation.annotation.Validated; | ||
| 15 | +import org.springframework.web.bind.annotation.*; | ||
| 16 | + | ||
| 17 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 18 | + | ||
| 19 | +@Tag(name = "管理后台 - CRM 合同配置") | ||
| 20 | +@RestController | ||
| 21 | +@RequestMapping("/crm/contract-config") | ||
| 22 | +@Validated | ||
| 23 | +public class CrmContractConfigController { | ||
| 24 | + | ||
| 25 | + @Resource | ||
| 26 | + private CrmContractConfigService contractConfigService; | ||
| 27 | + | ||
| 28 | + @GetMapping("/get") | ||
| 29 | + @Operation(summary = "获取合同配置") | ||
| 30 | + @PreAuthorize("@ss.hasPermission('crm:contract-config:query')") | ||
| 31 | + public CommonResult<CrmContractConfigRespVO> getCustomerPoolConfig() { | ||
| 32 | + CrmContractConfigDO config = contractConfigService.getContractConfig(); | ||
| 33 | + return success(BeanUtils.toBean(config, CrmContractConfigRespVO.class)); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @PutMapping("/save") | ||
| 37 | + @Operation(summary = "更新合同配置") | ||
| 38 | + @PreAuthorize("@ss.hasPermission('crm:contract-config:update')") | ||
| 39 | + public CommonResult<Boolean> saveCustomerPoolConfig(@Valid @RequestBody CrmContractConfigSaveReqVO updateReqVO) { | ||
| 40 | + contractConfigService.saveContractConfig(updateReqVO); | ||
| 41 | + return success(true); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
| @@ -3,16 +3,17 @@ package cn.iocoder.yudao.module.crm.controller.admin.contract; | @@ -3,16 +3,17 @@ package cn.iocoder.yudao.module.crm.controller.admin.contract; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.lang.Assert; | 4 | import cn.hutool.core.lang.Assert; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 9 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 10 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 9 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 11 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 10 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 12 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 11 | -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO; | ||
| 12 | -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO; | ||
| 13 | -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO; | ||
| 14 | -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO; | ||
| 15 | -import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert; | 13 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO; |
| 14 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; | ||
| 15 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO; | ||
| 16 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; | ||
| 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; | 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; |
| 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; | 18 | import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; |
| 18 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; | 19 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| @@ -24,6 +25,9 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; | @@ -24,6 +25,9 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; | ||
| 24 | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; | 25 | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; |
| 25 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | 26 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 26 | import cn.iocoder.yudao.module.crm.service.product.CrmProductService; | 27 | import cn.iocoder.yudao.module.crm.service.product.CrmProductService; |
| 28 | +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; | ||
| 29 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 30 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 27 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | 31 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 28 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 32 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 29 | import io.swagger.v3.oas.annotations.Operation; | 33 | import io.swagger.v3.oas.annotations.Operation; |
| @@ -37,6 +41,7 @@ import org.springframework.validation.annotation.Validated; | @@ -37,6 +41,7 @@ import org.springframework.validation.annotation.Validated; | ||
| 37 | import org.springframework.web.bind.annotation.*; | 41 | import org.springframework.web.bind.annotation.*; |
| 38 | 42 | ||
| 39 | import java.io.IOException; | 43 | import java.io.IOException; |
| 44 | +import java.math.BigDecimal; | ||
| 40 | import java.util.Collections; | 45 | import java.util.Collections; |
| 41 | import java.util.List; | 46 | import java.util.List; |
| 42 | import java.util.Map; | 47 | import java.util.Map; |
| @@ -44,6 +49,7 @@ import java.util.stream.Stream; | @@ -44,6 +49,7 @@ import java.util.stream.Stream; | ||
| 44 | 49 | ||
| 45 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 50 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 46 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 51 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 52 | +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||
| 47 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 53 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 48 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 54 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 49 | import static java.util.Collections.singletonList; | 55 | import static java.util.Collections.singletonList; |
| @@ -65,7 +71,12 @@ public class CrmContractController { | @@ -65,7 +71,12 @@ public class CrmContractController { | ||
| 65 | @Resource | 71 | @Resource |
| 66 | private CrmProductService productService; | 72 | private CrmProductService productService; |
| 67 | @Resource | 73 | @Resource |
| 74 | + private CrmReceivableService receivableService; | ||
| 75 | + | ||
| 76 | + @Resource | ||
| 68 | private AdminUserApi adminUserApi; | 77 | private AdminUserApi adminUserApi; |
| 78 | + @Resource | ||
| 79 | + private DeptApi deptApi; | ||
| 69 | 80 | ||
| 70 | @PostMapping("/create") | 81 | @PostMapping("/create") |
| 71 | @Operation(summary = "创建合同") | 82 | @Operation(summary = "创建合同") |
| @@ -96,15 +107,24 @@ public class CrmContractController { | @@ -96,15 +107,24 @@ public class CrmContractController { | ||
| 96 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 107 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 97 | @PreAuthorize("@ss.hasPermission('crm:contract:query')") | 108 | @PreAuthorize("@ss.hasPermission('crm:contract:query')") |
| 98 | public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) { | 109 | public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) { |
| 99 | - // 1. 查询合同 | ||
| 100 | CrmContractDO contract = contractService.getContract(id); | 110 | CrmContractDO contract = contractService.getContract(id); |
| 111 | + return success(buildContractDetail(contract)); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + private CrmContractRespVO buildContractDetail(CrmContractDO contract) { | ||
| 101 | if (contract == null) { | 115 | if (contract == null) { |
| 102 | - return success(null); | 116 | + return null; |
| 103 | } | 117 | } |
| 104 | - | ||
| 105 | - // 2. 拼接合同信息 | ||
| 106 | - List<CrmContractRespVO> respVOList = buildContractDetailList(singletonList(contract)); | ||
| 107 | - return success(respVOList.get(0)); | 118 | + CrmContractRespVO contractVO = buildContractDetailList(singletonList(contract)).get(0); |
| 119 | + // 拼接产品项 | ||
| 120 | + List<CrmContractProductDO> businessProducts = contractService.getContractProductListByContractId(contractVO.getId()); | ||
| 121 | + Map<Long, CrmProductDO> productMap = productService.getProductMap( | ||
| 122 | + convertSet(businessProducts, CrmContractProductDO::getProductId)); | ||
| 123 | + contractVO.setProducts(BeanUtils.toBean(businessProducts, CrmContractRespVO.Product.class, businessProductVO -> | ||
| 124 | + MapUtils.findAndThen(productMap, businessProductVO.getProductId(), | ||
| 125 | + product -> businessProductVO.setProductName(product.getName()) | ||
| 126 | + .setProductNo(product.getNo()).setProductUnit(product.getUnit())))); | ||
| 127 | + return contractVO; | ||
| 108 | } | 128 | } |
| 109 | 129 | ||
| 110 | @GetMapping("/page") | 130 | @GetMapping("/page") |
| @@ -123,6 +143,14 @@ public class CrmContractController { | @@ -123,6 +143,14 @@ public class CrmContractController { | ||
| 123 | return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); | 143 | return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); |
| 124 | } | 144 | } |
| 125 | 145 | ||
| 146 | + @GetMapping("/page-by-business") | ||
| 147 | + @Operation(summary = "获得合同分页,基于指定商机") | ||
| 148 | + public CommonResult<PageResult<CrmContractRespVO>> getContractPageByBusiness(@Valid CrmContractPageReqVO pageVO) { | ||
| 149 | + Assert.notNull(pageVO.getBusinessId(), "商机编号不能为空"); | ||
| 150 | + PageResult<CrmContractDO> pageResult = contractService.getContractPageByBusinessId(pageVO); | ||
| 151 | + return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); | ||
| 152 | + } | ||
| 153 | + | ||
| 126 | @GetMapping("/export-excel") | 154 | @GetMapping("/export-excel") |
| 127 | @Operation(summary = "导出合同 Excel") | 155 | @Operation(summary = "导出合同 Excel") |
| 128 | @PreAuthorize("@ss.hasPermission('crm:contract:export')") | 156 | @PreAuthorize("@ss.hasPermission('crm:contract:export')") |
| @@ -151,37 +179,78 @@ public class CrmContractController { | @@ -151,37 +179,78 @@ public class CrmContractController { | ||
| 151 | return success(true); | 179 | return success(true); |
| 152 | } | 180 | } |
| 153 | 181 | ||
| 154 | - /** | ||
| 155 | - * 构建详细的合同结果 | ||
| 156 | - * | ||
| 157 | - * @param contractList 原始合同信息 | ||
| 158 | - * @return 细的合同结果 | ||
| 159 | - */ | ||
| 160 | private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) { | 182 | private List<CrmContractRespVO> buildContractDetailList(List<CrmContractDO> contractList) { |
| 161 | if (CollUtil.isEmpty(contractList)) { | 183 | if (CollUtil.isEmpty(contractList)) { |
| 162 | return Collections.emptyList(); | 184 | return Collections.emptyList(); |
| 163 | } | 185 | } |
| 164 | - // 1. 获取客户列表 | ||
| 165 | - List<CrmCustomerDO> customerList = customerService.getCustomerList( | 186 | + // 1.1 获取客户列表 |
| 187 | + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap( | ||
| 166 | convertSet(contractList, CrmContractDO::getCustomerId)); | 188 | convertSet(contractList, CrmContractDO::getCustomerId)); |
| 167 | - // 2. 获取创建人、负责人列表 | 189 | + // 1.2 获取创建人、负责人列表 |
| 168 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList, | 190 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList, |
| 169 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | 191 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); |
| 170 | - // 3. 获取联系人 | ||
| 171 | - Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactListByIds(convertSet(contractList, | ||
| 172 | - CrmContractDO::getContactId)), CrmContactDO::getId); | ||
| 173 | - // 4. 获取商机 | ||
| 174 | - Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList, | ||
| 175 | - CrmContractDO::getBusinessId)), CrmBusinessDO::getId); | ||
| 176 | - // 5. 获取合同关联的商品 | ||
| 177 | - Map<Long, CrmContractProductDO> contractProductMap = null; | ||
| 178 | - List<CrmProductDO> productList = null; | ||
| 179 | - if (contractList.size() == 1) { | ||
| 180 | - List<CrmContractProductDO> contractProductList = contractService.getContractProductListByContractId(contractList.get(0).getId()); | ||
| 181 | - contractProductMap = convertMap(contractProductList, CrmContractProductDO::getProductId); | ||
| 182 | - productList = productService.getProductListByIds(convertSet(contractProductList, CrmContractProductDO::getProductId)); | 192 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); |
| 193 | + // 1.3 获取联系人 | ||
| 194 | + Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactList(convertSet(contractList, | ||
| 195 | + CrmContractDO::getSignContactId)), CrmContactDO::getId); | ||
| 196 | + // 1.4 获取商机 | ||
| 197 | + Map<Long, CrmBusinessDO> businessMap = businessService.getBusinessMap( | ||
| 198 | + convertSet(contractList, CrmContractDO::getBusinessId)); | ||
| 199 | + // 1.5 获得已回款金额 | ||
| 200 | + Map<Long, BigDecimal> receivablePriceMap = receivableService.getReceivablePriceMapByContractId( | ||
| 201 | + convertSet(contractList, CrmContractDO::getId)); | ||
| 202 | + // 2. 拼接数据 | ||
| 203 | + return BeanUtils.toBean(contractList, CrmContractRespVO.class, contractVO -> { | ||
| 204 | + // 2.1 设置客户信息 | ||
| 205 | + findAndThen(customerMap, contractVO.getCustomerId(), customer -> contractVO.setCustomerName(customer.getName())); | ||
| 206 | + // 2.2 设置用户信息 | ||
| 207 | + findAndThen(userMap, Long.parseLong(contractVO.getCreator()), user -> contractVO.setCreatorName(user.getNickname())); | ||
| 208 | + MapUtils.findAndThen(userMap, contractVO.getOwnerUserId(), user -> { | ||
| 209 | + contractVO.setOwnerUserName(user.getNickname()); | ||
| 210 | + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contractVO.setOwnerUserDeptName(dept.getName())); | ||
| 211 | + }); | ||
| 212 | + findAndThen(userMap, contractVO.getSignUserId(), user -> contractVO.setSignUserName(user.getNickname())); | ||
| 213 | + // 2.3 设置联系人信息 | ||
| 214 | + findAndThen(contactMap, contractVO.getSignContactId(), contact -> contractVO.setSignContactName(contact.getName())); | ||
| 215 | + // 2.4 设置商机信息 | ||
| 216 | + findAndThen(businessMap, contractVO.getBusinessId(), business -> contractVO.setBusinessName(business.getName())); | ||
| 217 | + // 2.5 设置已回款金额 | ||
| 218 | + contractVO.setTotalReceivablePrice(receivablePriceMap.getOrDefault(contractVO.getId(), BigDecimal.ZERO)); | ||
| 219 | + }); | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + @GetMapping("/audit-count") | ||
| 223 | + @Operation(summary = "获得待审核合同数量") | ||
| 224 | + @PreAuthorize("@ss.hasPermission('crm:contract:query')") | ||
| 225 | + public CommonResult<Long> getAuditContractCount() { | ||
| 226 | + return success(contractService.getAuditContractCount(getLoginUserId())); | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + @GetMapping("/remind-count") | ||
| 230 | + @Operation(summary = "获得即将到期(提醒)的合同数量") | ||
| 231 | + @PreAuthorize("@ss.hasPermission('crm:contract:query')") | ||
| 232 | + public CommonResult<Long> getRemindContractCount() { | ||
| 233 | + return success(contractService.getRemindContractCount(getLoginUserId())); | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + @GetMapping("/simple-list") | ||
| 237 | + @Operation(summary = "获得合同精简列表", description = "只包含的合同,主要用于前端的下拉选项") | ||
| 238 | + @Parameter(name = "customerId", description = "客户编号", required = true) | ||
| 239 | + @PreAuthorize("@ss.hasPermission('crm:contract:query')") | ||
| 240 | + public CommonResult<List<CrmContractRespVO>> getContractSimpleList(@RequestParam("customerId") Long customerId) { | ||
| 241 | + CrmContractPageReqVO pageReqVO = new CrmContractPageReqVO().setCustomerId(customerId); | ||
| 242 | + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); // 不分页 | ||
| 243 | + PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageReqVO); | ||
| 244 | + if (CollUtil.isEmpty(pageResult.getList())) { | ||
| 245 | + return success(Collections.emptyList()); | ||
| 183 | } | 246 | } |
| 184 | - return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap, contractProductMap, productList); | 247 | + // 拼接数据 |
| 248 | + Map<Long, BigDecimal> receivablePriceMap = receivableService.getReceivablePriceMapByContractId( | ||
| 249 | + convertSet(pageResult.getList(), CrmContractDO::getId)); | ||
| 250 | + return success(convertList(pageResult.getList(), contract -> new CrmContractRespVO() // 只返回 id、name 等精简字段 | ||
| 251 | + .setId(contract.getId()).setName(contract.getName()).setAuditStatus(contract.getAuditStatus()) | ||
| 252 | + .setTotalPrice(contract.getTotalPrice()) | ||
| 253 | + .setTotalReceivablePrice(receivablePriceMap.getOrDefault(contract.getId(), BigDecimal.ZERO)))); | ||
| 185 | } | 254 | } |
| 186 | 255 | ||
| 187 | } | 256 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +@Schema(description = "管理后台 - CRM 合同配置 Response VO") | ||
| 7 | +@Data | ||
| 8 | +public class CrmContractConfigRespVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "是否开启提前提醒", example = "true") | ||
| 11 | + private Boolean notifyEnabled; | ||
| 12 | + | ||
| 13 | + @Schema(description = "提前提醒天数", example = "2") | ||
| 14 | + private Integer notifyDays; | ||
| 15 | + | ||
| 16 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.BooleanUtil; | ||
| 4 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| 5 | +import com.mzt.logapi.starter.annotation.DiffLogField; | ||
| 6 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 7 | +import jakarta.validation.constraints.AssertTrue; | ||
| 8 | +import lombok.Data; | ||
| 9 | + | ||
| 10 | +import java.util.Objects; | ||
| 11 | + | ||
| 12 | +@Schema(description = "管理后台 - CRM 合同配置 Request VO") | ||
| 13 | +@Data | ||
| 14 | +public class CrmContractConfigSaveReqVO { | ||
| 15 | + | ||
| 16 | + @Schema(description = "是否开启提前提醒", example = "true") | ||
| 17 | + @DiffLogField(name = "是否开启提前提醒") | ||
| 18 | + private Boolean notifyEnabled; | ||
| 19 | + | ||
| 20 | + @Schema(description = "提前提醒天数", example = "2") | ||
| 21 | + @DiffLogField(name = "提前提醒天数") | ||
| 22 | + private Integer notifyDays; | ||
| 23 | + | ||
| 24 | + @AssertTrue(message = "提前提醒天数不能为空") | ||
| 25 | + @JsonIgnore | ||
| 26 | + public boolean isNotifyDaysValid() { | ||
| 27 | + if (!BooleanUtil.isTrue(getNotifyEnabled())) { | ||
| 28 | + return true; | ||
| 29 | + } | ||
| 30 | + return Objects.nonNull(getNotifyDays()); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractPageReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; |
| 2 | 2 | ||
| 3 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | 3 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| 4 | import com.alibaba.excel.annotation.ExcelProperty; | 4 | import com.alibaba.excel.annotation.ExcelProperty; |
| @@ -6,13 +6,11 @@ import io.swagger.v3.oas.annotations.media.Schema; | @@ -6,13 +6,11 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | import lombok.AllArgsConstructor; | 6 | import lombok.AllArgsConstructor; |
| 7 | import lombok.Data; | 7 | import lombok.Data; |
| 8 | import lombok.NoArgsConstructor; | 8 | import lombok.NoArgsConstructor; |
| 9 | -import org.springframework.format.annotation.DateTimeFormat; | ||
| 10 | 9 | ||
| 10 | +import java.math.BigDecimal; | ||
| 11 | import java.time.LocalDateTime; | 11 | import java.time.LocalDateTime; |
| 12 | import java.util.List; | 12 | import java.util.List; |
| 13 | 13 | ||
| 14 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 15 | - | ||
| 16 | @Schema(description = "管理后台 - CRM 合同 Response VO") | 14 | @Schema(description = "管理后台 - CRM 合同 Response VO") |
| 17 | @Data | 15 | @Data |
| 18 | @ExcelIgnoreUnannotated | 16 | @ExcelIgnoreUnannotated |
| @@ -26,6 +24,10 @@ public class CrmContractRespVO { | @@ -26,6 +24,10 @@ public class CrmContractRespVO { | ||
| 26 | @ExcelProperty("合同名称") | 24 | @ExcelProperty("合同名称") |
| 27 | private String name; | 25 | private String name; |
| 28 | 26 | ||
| 27 | + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101") | ||
| 28 | + @ExcelProperty("合同编号") | ||
| 29 | + private String no; | ||
| 30 | + | ||
| 29 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") | 31 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") |
| 30 | @ExcelProperty("客户编号") | 32 | @ExcelProperty("客户编号") |
| 31 | private Long customerId; | 33 | private Long customerId; |
| @@ -40,72 +42,74 @@ public class CrmContractRespVO { | @@ -40,72 +42,74 @@ public class CrmContractRespVO { | ||
| 40 | @ExcelProperty("商机名称") | 42 | @ExcelProperty("商机名称") |
| 41 | private String businessName; | 43 | private String businessName; |
| 42 | 44 | ||
| 45 | + @Schema(description = "最后跟进时间") | ||
| 46 | + @ExcelProperty("最后跟进时间") | ||
| 47 | + private LocalDateTime contactLastTime; | ||
| 48 | + | ||
| 49 | + @Schema(description = "负责人的用户编号", example = "25682") | ||
| 50 | + @ExcelProperty("负责人的用户编号") | ||
| 51 | + private Long ownerUserId; | ||
| 52 | + @Schema(description = "负责人名字", example = "25682") | ||
| 53 | + @ExcelProperty("负责人名字") | ||
| 54 | + private String ownerUserName; | ||
| 55 | + @Schema(description = "负责人部门") | ||
| 56 | + @ExcelProperty("负责人部门") | ||
| 57 | + private String ownerUserDeptName; | ||
| 58 | + | ||
| 43 | @Schema(description = "工作流编号", example = "1043") | 59 | @Schema(description = "工作流编号", example = "1043") |
| 44 | @ExcelProperty("工作流编号") | 60 | @ExcelProperty("工作流编号") |
| 45 | - private Long processInstanceId; | 61 | + private String processInstanceId; |
| 62 | + | ||
| 63 | + @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 64 | + @ExcelProperty("审批状态") | ||
| 65 | + private Integer auditStatus; | ||
| 46 | 66 | ||
| 47 | @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) | 67 | @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) |
| 48 | @ExcelProperty("下单日期") | 68 | @ExcelProperty("下单日期") |
| 49 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 50 | private LocalDateTime orderDate; | 69 | private LocalDateTime orderDate; |
| 51 | 70 | ||
| 52 | - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144") | ||
| 53 | - @ExcelProperty("负责人的用户编号") | ||
| 54 | - private Long ownerUserId; | ||
| 55 | - | ||
| 56 | - // TODO @芋艿:未来应该支持自动生成; | ||
| 57 | - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101") | ||
| 58 | - @ExcelProperty("合同编号") | ||
| 59 | - private String no; | ||
| 60 | - | ||
| 61 | @Schema(description = "开始时间") | 71 | @Schema(description = "开始时间") |
| 62 | @ExcelProperty("开始时间") | 72 | @ExcelProperty("开始时间") |
| 63 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 64 | private LocalDateTime startTime; | 73 | private LocalDateTime startTime; |
| 65 | 74 | ||
| 66 | @Schema(description = "结束时间") | 75 | @Schema(description = "结束时间") |
| 67 | @ExcelProperty("结束时间") | 76 | @ExcelProperty("结束时间") |
| 68 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 69 | private LocalDateTime endTime; | 77 | private LocalDateTime endTime; |
| 70 | 78 | ||
| 71 | - @Schema(description = "合同金额", example = "5617") | ||
| 72 | - @ExcelProperty("合同金额") | ||
| 73 | - private Integer price; | 79 | + @Schema(description = "产品总金额", example = "19510") |
| 80 | + @ExcelProperty("产品总金额") | ||
| 81 | + private BigDecimal totalProductPrice; | ||
| 74 | 82 | ||
| 75 | @Schema(description = "整单折扣") | 83 | @Schema(description = "整单折扣") |
| 76 | @ExcelProperty("整单折扣") | 84 | @ExcelProperty("整单折扣") |
| 77 | - private Integer discountPercent; | 85 | + private BigDecimal discountPercent; |
| 78 | 86 | ||
| 79 | - @Schema(description = "产品总金额", example = "19510") | ||
| 80 | - @ExcelProperty("产品总金额") | ||
| 81 | - private Integer productPrice; | 87 | + @Schema(description = "合同金额", example = "5617") |
| 88 | + @ExcelProperty("合同金额") | ||
| 89 | + private BigDecimal totalPrice; | ||
| 90 | + | ||
| 91 | + @Schema(description = "已回款金额", example = "5617") | ||
| 92 | + @ExcelProperty("已回款金额") | ||
| 93 | + private BigDecimal totalReceivablePrice; | ||
| 82 | 94 | ||
| 83 | - @Schema(description = "联系人编号", example = "18546") | ||
| 84 | - @ExcelProperty("联系人编号") | ||
| 85 | - private Long contactId; | ||
| 86 | - @Schema(description = "联系人编号", example = "18546") | ||
| 87 | - @ExcelProperty("联系人编号") | ||
| 88 | - private String contactName; | 95 | + @Schema(description = "客户签约人编号", example = "18546") |
| 96 | + private Long signContactId; | ||
| 97 | + @Schema(description = "客户签约人", example = "小豆") | ||
| 98 | + @ExcelProperty("客户签约人") | ||
| 99 | + private String signContactName; | ||
| 89 | 100 | ||
| 90 | @Schema(description = "公司签约人", example = "14036") | 101 | @Schema(description = "公司签约人", example = "14036") |
| 91 | - @ExcelProperty("公司签约人") | ||
| 92 | private Long signUserId; | 102 | private Long signUserId; |
| 93 | - @Schema(description = "公司签约人", example = "14036") | 103 | + @Schema(description = "公司签约人", example = "小明") |
| 94 | @ExcelProperty("公司签约人") | 104 | @ExcelProperty("公司签约人") |
| 95 | private String signUserName; | 105 | private String signUserName; |
| 96 | 106 | ||
| 97 | - @Schema(description = "最后跟进时间") | ||
| 98 | - @ExcelProperty("最后跟进时间") | ||
| 99 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 100 | - private LocalDateTime contactLastTime; | ||
| 101 | - | ||
| 102 | @Schema(description = "备注", example = "你猜") | 107 | @Schema(description = "备注", example = "你猜") |
| 103 | @ExcelProperty("备注") | 108 | @ExcelProperty("备注") |
| 104 | private String remark; | 109 | private String remark; |
| 105 | 110 | ||
| 106 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 111 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 107 | @ExcelProperty("创建时间") | 112 | @ExcelProperty("创建时间") |
| 108 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 109 | private LocalDateTime createTime; | 113 | private LocalDateTime createTime; |
| 110 | 114 | ||
| 111 | @Schema(description = "创建人", example = "25682") | 115 | @Schema(description = "创建人", example = "25682") |
| @@ -118,47 +122,40 @@ public class CrmContractRespVO { | @@ -118,47 +122,40 @@ public class CrmContractRespVO { | ||
| 118 | 122 | ||
| 119 | @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) | 123 | @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 120 | @ExcelProperty("更新时间") | 124 | @ExcelProperty("更新时间") |
| 121 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 122 | private LocalDateTime updateTime; | 125 | private LocalDateTime updateTime; |
| 123 | 126 | ||
| 124 | - @Schema(description = "负责人", example = "test") | ||
| 125 | - @ExcelProperty("负责人") | ||
| 126 | - private String ownerUserName; | ||
| 127 | - | ||
| 128 | - @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 129 | - @ExcelProperty("审批状态") | ||
| 130 | - private Integer auditStatus; | ||
| 131 | - | ||
| 132 | @Schema(description = "产品列表") | 127 | @Schema(description = "产品列表") |
| 133 | - private List<CrmContractProductItemRespVO> productItems; | 128 | + private List<Product> products; |
| 134 | 129 | ||
| 135 | - // TODO @puhui999:可以直接叫 Item | ||
| 136 | @Schema(description = "产品列表") | 130 | @Schema(description = "产品列表") |
| 137 | @Data | 131 | @Data |
| 138 | @NoArgsConstructor | 132 | @NoArgsConstructor |
| 139 | @AllArgsConstructor | 133 | @AllArgsConstructor |
| 140 | - public static class CrmContractProductItemRespVO { | 134 | + public static class Product { |
| 141 | 135 | ||
| 142 | - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") | 136 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") |
| 143 | private Long id; | 137 | private Long id; |
| 144 | 138 | ||
| 145 | - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是产品") | ||
| 146 | - private String name; | ||
| 147 | - | ||
| 148 | - @Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "N881") | ||
| 149 | - private String no; | 139 | + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") |
| 140 | + private Long productId; | ||
| 141 | + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 142 | + private String productName; | ||
| 143 | + @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") | ||
| 144 | + private String productNo; | ||
| 145 | + @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | ||
| 146 | + private Integer productUnit; | ||
| 150 | 147 | ||
| 151 | - @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | ||
| 152 | - private Integer unit; | 148 | + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") |
| 149 | + private BigDecimal productPrice; | ||
| 153 | 150 | ||
| 154 | - @Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") | ||
| 155 | - private Integer price; | 151 | + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") |
| 152 | + private BigDecimal contractPrice; | ||
| 156 | 153 | ||
| 157 | - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") | ||
| 158 | - private Integer count; | 154 | + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") |
| 155 | + private BigDecimal count; | ||
| 159 | 156 | ||
| 160 | - @Schema(description = "产品折扣", example = "99") | ||
| 161 | - private Integer discountPercent; | 157 | + @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") |
| 158 | + private BigDecimal totalPrice; | ||
| 162 | 159 | ||
| 163 | } | 160 | } |
| 164 | 161 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractSaveReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmBusinessParseFunction; | 3 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmBusinessParseFunction; |
| 4 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmContactParseFunction; | 4 | import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmContactParseFunction; |
| @@ -12,6 +12,7 @@ import lombok.Data; | @@ -12,6 +12,7 @@ import lombok.Data; | ||
| 12 | import lombok.NoArgsConstructor; | 12 | import lombok.NoArgsConstructor; |
| 13 | import org.springframework.format.annotation.DateTimeFormat; | 13 | import org.springframework.format.annotation.DateTimeFormat; |
| 14 | 14 | ||
| 15 | +import java.math.BigDecimal; | ||
| 15 | import java.time.LocalDateTime; | 16 | import java.time.LocalDateTime; |
| 16 | import java.util.List; | 17 | import java.util.List; |
| 17 | 18 | ||
| @@ -38,22 +39,16 @@ public class CrmContractSaveReqVO { | @@ -38,22 +39,16 @@ public class CrmContractSaveReqVO { | ||
| 38 | @DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME) | 39 | @DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME) |
| 39 | private Long businessId; | 40 | private Long businessId; |
| 40 | 41 | ||
| 41 | - @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 42 | - @DiffLogField(name = "下单日期") | ||
| 43 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 44 | - @NotNull(message = "下单日期不能为空") | ||
| 45 | - private LocalDateTime orderDate; | ||
| 46 | - | ||
| 47 | @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144") | 42 | @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144") |
| 48 | @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) | 43 | @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) |
| 49 | @NotNull(message = "负责人不能为空") | 44 | @NotNull(message = "负责人不能为空") |
| 50 | private Long ownerUserId; | 45 | private Long ownerUserId; |
| 51 | 46 | ||
| 52 | - // TODO @芋艿:未来应该支持自动生成; | ||
| 53 | - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101") | ||
| 54 | - @DiffLogField(name = "合同编号") | ||
| 55 | - @NotNull(message = "合同编号不能为空") | ||
| 56 | - private String no; | 47 | + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) |
| 48 | + @DiffLogField(name = "下单日期") | ||
| 49 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 50 | + @NotNull(message = "下单日期不能为空") | ||
| 51 | + private LocalDateTime orderDate; | ||
| 57 | 52 | ||
| 58 | @Schema(description = "开始时间") | 53 | @Schema(description = "开始时间") |
| 59 | @DiffLogField(name = "开始时间") | 54 | @DiffLogField(name = "开始时间") |
| @@ -65,21 +60,18 @@ public class CrmContractSaveReqVO { | @@ -65,21 +60,18 @@ public class CrmContractSaveReqVO { | ||
| 65 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 60 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 66 | private LocalDateTime endTime; | 61 | private LocalDateTime endTime; |
| 67 | 62 | ||
| 68 | - @Schema(description = "合同金额", example = "5617") | ||
| 69 | - @DiffLogField(name = "合同金额") | ||
| 70 | - private Integer price; | ||
| 71 | - | ||
| 72 | - @Schema(description = "整单折扣") | 63 | + @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00") |
| 73 | @DiffLogField(name = "整单折扣") | 64 | @DiffLogField(name = "整单折扣") |
| 74 | - private Integer discountPercent; | 65 | + @NotNull(message = "整单折扣不能为空") |
| 66 | + private BigDecimal discountPercent; | ||
| 75 | 67 | ||
| 76 | - @Schema(description = "产品总金额", example = "19510") | ||
| 77 | - @DiffLogField(name = "产品总金额") | ||
| 78 | - private Integer productPrice; | 68 | + @Schema(description = "合同金额", example = "5617") |
| 69 | + @DiffLogField(name = "合同金额") | ||
| 70 | + private BigDecimal totalPrice; | ||
| 79 | 71 | ||
| 80 | - @Schema(description = "联系人编号", example = "18546") | ||
| 81 | - @DiffLogField(name = "联系人", function = CrmContactParseFunction.NAME) | ||
| 82 | - private Long contactId; | 72 | + @Schema(description = "客户签约人编号", example = "18546") |
| 73 | + @DiffLogField(name = "客户签约人", function = CrmContactParseFunction.NAME) | ||
| 74 | + private Long signContactId; | ||
| 83 | 75 | ||
| 84 | @Schema(description = "公司签约人", example = "14036") | 76 | @Schema(description = "公司签约人", example = "14036") |
| 85 | @DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME) | 77 | @DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME) |
| @@ -89,27 +81,31 @@ public class CrmContractSaveReqVO { | @@ -89,27 +81,31 @@ public class CrmContractSaveReqVO { | ||
| 89 | @DiffLogField(name = "备注") | 81 | @DiffLogField(name = "备注") |
| 90 | private String remark; | 82 | private String remark; |
| 91 | 83 | ||
| 92 | - | ||
| 93 | @Schema(description = "产品列表") | 84 | @Schema(description = "产品列表") |
| 94 | - private List<CrmContractProductItem> productItems; | 85 | + private List<Product> products; |
| 95 | 86 | ||
| 96 | @Schema(description = "产品列表") | 87 | @Schema(description = "产品列表") |
| 97 | @Data | 88 | @Data |
| 98 | @NoArgsConstructor | 89 | @NoArgsConstructor |
| 99 | @AllArgsConstructor | 90 | @AllArgsConstructor |
| 100 | - public static class CrmContractProductItem { | 91 | + public static class Product { |
| 101 | 92 | ||
| 102 | - @Schema(description = "产品编号", example = "20529") | 93 | + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") |
| 103 | @NotNull(message = "产品编号不能为空") | 94 | @NotNull(message = "产品编号不能为空") |
| 104 | - private Long id; | 95 | + private Long productId; |
| 96 | + | ||
| 97 | + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") | ||
| 98 | + @NotNull(message = "产品单价不能为空") | ||
| 99 | + private BigDecimal productPrice; | ||
| 100 | + | ||
| 101 | + @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") | ||
| 102 | + @NotNull(message = "合同价格不能为空") | ||
| 103 | + private BigDecimal contractPrice; | ||
| 105 | 104 | ||
| 106 | @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") | 105 | @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") |
| 107 | @NotNull(message = "产品数量不能为空") | 106 | @NotNull(message = "产品数量不能为空") |
| 108 | private Integer count; | 107 | private Integer count; |
| 109 | 108 | ||
| 110 | - @Schema(description = "产品折扣") | ||
| 111 | - private Integer discountPercent; | ||
| 112 | - | ||
| 113 | } | 109 | } |
| 114 | 110 | ||
| 115 | } | 111 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractTransferReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 3 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 4 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | 4 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.http deleted
| 1 | -### 请求 /transfer | ||
| 2 | -PUT {{baseUrl}}/crm/customer/transfer | ||
| 3 | -Content-Type: application/-id: {{adminTenentId}}json | ||
| 4 | -Authorization: Bearer {{token}} | ||
| 5 | -tenant | ||
| 6 | - | ||
| 7 | -{ | ||
| 8 | - "id": 10, | ||
| 9 | - "newOwnerUserId": 127 | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -### 自定义日志记录结果 | ||
| 13 | -### 操作日志 ===> OperateLogV2CreateReqBO(traceId=, userId=1, userType=2, module=CRM-客户, name=客户转移, bizId=10, content=把客户【张三】的负责人从【芋道源码(15612345678)】变更为了【tttt】, requestMethod=PUT, requestUrl=/admin-api/crm/customer/transfer, userIp=127.0.0.1, userAgent=Apache-HttpClient/4.5.14 (Java/17.0.9)) | ||
| 14 | - | ||
| 15 | -### diff 日志 | ||
| 16 | -### | 操作日志 ===> OperateLogV2CreateReqBO(traceId=, userId=1, userType=2, module=CRM-客户, name=更新客户, bizId=11, content=更新了客户【所属行业】从【H 住宿和餐饮业】修改为【D 电力、热力、燃气及水生产和供应业】;【客户等级】从【C (非优先客户)】修改为【A (重点客户)】;【客户来源】从【线上咨询】修改为【预约上门】, requestMethod=PUT, requestUrl=/admin-api/crm/customer/update, userIp=0:0:0:0:0:0:0:1, userAgent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36) |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
| @@ -2,48 +2,55 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; | @@ -2,48 +2,55 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.map.MapUtil; | 4 | import cn.hutool.core.map.MapUtil; |
| 5 | -import cn.hutool.core.util.ObjUtil; | 5 | +import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 9 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 8 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | 10 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 11 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||
| 9 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 12 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 13 | +import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn; | ||
| 10 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 14 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 15 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 16 | +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | ||
| 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 17 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 12 | -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*; | ||
| 13 | -import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; | 18 | +import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; |
| 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 19 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; | 20 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; |
| 16 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService; | 21 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService; |
| 17 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | 22 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 18 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; | 23 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| 19 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | 24 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| 25 | +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; | ||
| 20 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | 26 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 21 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 27 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 22 | import io.swagger.v3.oas.annotations.Operation; | 28 | import io.swagger.v3.oas.annotations.Operation; |
| 23 | import io.swagger.v3.oas.annotations.Parameter; | 29 | import io.swagger.v3.oas.annotations.Parameter; |
| 30 | +import io.swagger.v3.oas.annotations.Parameters; | ||
| 24 | import io.swagger.v3.oas.annotations.tags.Tag; | 31 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 25 | import jakarta.annotation.Resource; | 32 | import jakarta.annotation.Resource; |
| 26 | import jakarta.servlet.http.HttpServletResponse; | 33 | import jakarta.servlet.http.HttpServletResponse; |
| 27 | import jakarta.validation.Valid; | 34 | import jakarta.validation.Valid; |
| 28 | -import org.mapstruct.ap.internal.util.Collections; | ||
| 29 | import org.springframework.security.access.prepost.PreAuthorize; | 35 | import org.springframework.security.access.prepost.PreAuthorize; |
| 30 | import org.springframework.validation.annotation.Validated; | 36 | import org.springframework.validation.annotation.Validated; |
| 31 | import org.springframework.web.bind.annotation.*; | 37 | import org.springframework.web.bind.annotation.*; |
| 32 | 38 | ||
| 33 | import java.io.IOException; | 39 | import java.io.IOException; |
| 34 | import java.time.LocalDateTime; | 40 | import java.time.LocalDateTime; |
| 41 | +import java.util.ArrayList; | ||
| 35 | import java.util.Arrays; | 42 | import java.util.Arrays; |
| 36 | import java.util.List; | 43 | import java.util.List; |
| 37 | import java.util.Map; | 44 | import java.util.Map; |
| 38 | import java.util.stream.Stream; | 45 | import java.util.stream.Stream; |
| 39 | 46 | ||
| 40 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 41 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 47 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 42 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | 48 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 43 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 49 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 44 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 50 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 45 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 51 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 46 | -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED; | 52 | +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; |
| 53 | +import static java.util.Collections.singletonList; | ||
| 47 | 54 | ||
| 48 | @Tag(name = "管理后台 - CRM 客户") | 55 | @Tag(name = "管理后台 - CRM 客户") |
| 49 | @RestController | 56 | @RestController |
| @@ -55,10 +62,13 @@ public class CrmCustomerController { | @@ -55,10 +62,13 @@ public class CrmCustomerController { | ||
| 55 | private CrmCustomerService customerService; | 62 | private CrmCustomerService customerService; |
| 56 | @Resource | 63 | @Resource |
| 57 | private CrmCustomerPoolConfigService customerPoolConfigService; | 64 | private CrmCustomerPoolConfigService customerPoolConfigService; |
| 65 | + | ||
| 58 | @Resource | 66 | @Resource |
| 59 | private DeptApi deptApi; | 67 | private DeptApi deptApi; |
| 60 | @Resource | 68 | @Resource |
| 61 | private AdminUserApi adminUserApi; | 69 | private AdminUserApi adminUserApi; |
| 70 | + @Resource | ||
| 71 | + private DictDataApi dictDataApi; | ||
| 62 | 72 | ||
| 63 | @PostMapping("/create") | 73 | @PostMapping("/create") |
| 64 | @Operation(summary = "创建客户") | 74 | @Operation(summary = "创建客户") |
| @@ -75,6 +85,18 @@ public class CrmCustomerController { | @@ -75,6 +85,18 @@ public class CrmCustomerController { | ||
| 75 | return success(true); | 85 | return success(true); |
| 76 | } | 86 | } |
| 77 | 87 | ||
| 88 | + @PutMapping("/update-deal-status") | ||
| 89 | + @Operation(summary = "更新客户的成交状态") | ||
| 90 | + @Parameters({ | ||
| 91 | + @Parameter(name = "id", description = "客户编号", required = true), | ||
| 92 | + @Parameter(name = "dealStatus", description = "成交状态", required = true) | ||
| 93 | + }) | ||
| 94 | + public CommonResult<Boolean> updateCustomerDealStatus(@RequestParam("id") Long id, | ||
| 95 | + @RequestParam("dealStatus") Boolean dealStatus) { | ||
| 96 | + customerService.updateCustomerDealStatus(id, dealStatus); | ||
| 97 | + return success(true); | ||
| 98 | + } | ||
| 99 | + | ||
| 78 | @DeleteMapping("/delete") | 100 | @DeleteMapping("/delete") |
| 79 | @Operation(summary = "删除客户") | 101 | @Operation(summary = "删除客户") |
| 80 | @Parameter(name = "id", description = "客户编号", required = true) | 102 | @Parameter(name = "id", description = "客户编号", required = true) |
| @@ -91,94 +113,126 @@ public class CrmCustomerController { | @@ -91,94 +113,126 @@ public class CrmCustomerController { | ||
| 91 | public CommonResult<CrmCustomerRespVO> getCustomer(@RequestParam("id") Long id) { | 113 | public CommonResult<CrmCustomerRespVO> getCustomer(@RequestParam("id") Long id) { |
| 92 | // 1. 获取客户 | 114 | // 1. 获取客户 |
| 93 | CrmCustomerDO customer = customerService.getCustomer(id); | 115 | CrmCustomerDO customer = customerService.getCustomer(id); |
| 116 | + // 2. 拼接数据 | ||
| 117 | + return success(buildCustomerDetail(customer)); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + public CrmCustomerRespVO buildCustomerDetail(CrmCustomerDO customer) { | ||
| 94 | if (customer == null) { | 121 | if (customer == null) { |
| 95 | - return success(null); | 122 | + return null; |
| 96 | } | 123 | } |
| 97 | - // 2. 拼接数据 | ||
| 98 | - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 99 | - Collections.asSet(Long.valueOf(customer.getCreator()), customer.getOwnerUserId())); | ||
| 100 | - Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||
| 101 | - return success(CrmCustomerConvert.INSTANCE.convert(customer, userMap, deptMap)); | 124 | + return buildCustomerDetailList(singletonList(customer)).get(0); |
| 102 | } | 125 | } |
| 103 | 126 | ||
| 104 | @GetMapping("/page") | 127 | @GetMapping("/page") |
| 105 | @Operation(summary = "获得客户分页") | 128 | @Operation(summary = "获得客户分页") |
| 106 | @PreAuthorize("@ss.hasPermission('crm:customer:query')") | 129 | @PreAuthorize("@ss.hasPermission('crm:customer:query')") |
| 107 | public CommonResult<PageResult<CrmCustomerRespVO>> getCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { | 130 | public CommonResult<PageResult<CrmCustomerRespVO>> getCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { |
| 131 | + customerService.autoPutCustomerPool(); | ||
| 108 | // 1. 查询客户分页 | 132 | // 1. 查询客户分页 |
| 109 | PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(pageVO, getLoginUserId()); | 133 | PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(pageVO, getLoginUserId()); |
| 110 | if (CollUtil.isEmpty(pageResult.getList())) { | 134 | if (CollUtil.isEmpty(pageResult.getList())) { |
| 111 | return success(PageResult.empty(pageResult.getTotal())); | 135 | return success(PageResult.empty(pageResult.getTotal())); |
| 112 | } | 136 | } |
| 113 | - | ||
| 114 | // 2. 拼接数据 | 137 | // 2. 拼接数据 |
| 115 | - Map<Long, Long> poolDayMap = Boolean.TRUE.equals(pageVO.getPool()) ? null : | ||
| 116 | - getPoolDayMap(pageResult.getList()); // 客户界面,需要查看距离进入公海的时间 | ||
| 117 | - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 118 | - convertSetByFlatMap(pageResult.getList(), user -> Stream.of(Long.parseLong(user.getCreator()), user.getOwnerUserId()))); | 138 | + return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal())); |
| 139 | + } | ||
| 140 | + | ||
| 141 | + public List<CrmCustomerRespVO> buildCustomerDetailList(List<CrmCustomerDO> list) { | ||
| 142 | + if (CollUtil.isEmpty(list)) { | ||
| 143 | + return java.util.Collections.emptyList(); | ||
| 144 | + } | ||
| 145 | + // 1.1 获取创建人、负责人列表 | ||
| 146 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(list, | ||
| 147 | + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | ||
| 119 | Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | 148 | Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); |
| 120 | - return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap, poolDayMap)); | 149 | + // 1.2 获取距离进入公海的时间 |
| 150 | + Map<Long, Long> poolDayMap = getPoolDayMap(list); | ||
| 151 | + // 2. 转换成 VO | ||
| 152 | + return BeanUtils.toBean(list, CrmCustomerRespVO.class, customerVO -> { | ||
| 153 | + customerVO.setAreaName(AreaUtils.format(customerVO.getAreaId())); | ||
| 154 | + // 2.1 设置创建人、负责人名称 | ||
| 155 | + MapUtils.findAndThen(userMap, NumberUtils.parseLong(customerVO.getCreator()), | ||
| 156 | + user -> customerVO.setCreatorName(user.getNickname())); | ||
| 157 | + MapUtils.findAndThen(userMap, customerVO.getOwnerUserId(), user -> { | ||
| 158 | + customerVO.setOwnerUserName(user.getNickname()); | ||
| 159 | + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> customerVO.setOwnerUserDeptName(dept.getName())); | ||
| 160 | + }); | ||
| 161 | + // 2.2 设置距离进入公海的时间 | ||
| 162 | + if (customerVO.getOwnerUserId() != null) { | ||
| 163 | + customerVO.setPoolDay(poolDayMap.get(customerVO.getId())); | ||
| 164 | + } | ||
| 165 | + }); | ||
| 121 | } | 166 | } |
| 122 | 167 | ||
| 123 | - @GetMapping("/put-in-pool-remind-page") | 168 | + @GetMapping("/put-pool-remind-page") |
| 124 | @Operation(summary = "获得待进入公海客户分页") | 169 | @Operation(summary = "获得待进入公海客户分页") |
| 125 | @PreAuthorize("@ss.hasPermission('crm:customer:query')") | 170 | @PreAuthorize("@ss.hasPermission('crm:customer:query')") |
| 126 | - public CommonResult<PageResult<CrmCustomerRespVO>> getPutInPoolRemindCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { | ||
| 127 | - // 获取公海配置 TODO @dbh52:合并到 getPutInPoolRemindCustomerPage 会更合适哈; | ||
| 128 | - CrmCustomerPoolConfigDO poolConfigDO = customerPoolConfigService.getCustomerPoolConfig(); | ||
| 129 | - if (ObjUtil.isNull(poolConfigDO) | ||
| 130 | - || Boolean.FALSE.equals(poolConfigDO.getEnabled()) | ||
| 131 | - || Boolean.FALSE.equals(poolConfigDO.getNotifyEnabled()) | ||
| 132 | - ) { // TODO @dbh52:这个括号,一般不换行,在 java 这里; | ||
| 133 | - throw exception(CUSTOMER_POOL_CONFIG_NOT_EXISTS_OR_DISABLED); | ||
| 134 | - } | ||
| 135 | - | 171 | + public CommonResult<PageResult<CrmCustomerRespVO>> getPutPoolRemindCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { |
| 136 | // 1. 查询客户分页 | 172 | // 1. 查询客户分页 |
| 137 | - PageResult<CrmCustomerDO> pageResult = customerService.getPutInPoolRemindCustomerPage(pageVO, poolConfigDO, getLoginUserId()); | ||
| 138 | - if (CollUtil.isEmpty(pageResult.getList())) { | ||
| 139 | - return success(PageResult.empty(pageResult.getTotal())); | ||
| 140 | - } | ||
| 141 | - | 173 | + PageResult<CrmCustomerDO> pageResult = customerService.getPutPoolRemindCustomerPage(pageVO, getLoginUserId()); |
| 142 | // 2. 拼接数据 | 174 | // 2. 拼接数据 |
| 143 | - // TODO @芋艿:合并 getCustomerPage 和 getPutInPoolRemindCustomerPage 的后置处理; | ||
| 144 | - Map<Long, Long> poolDayMap = getPoolDayMap(pageResult.getList()); // 客户界面,需要查看距离进入公海的时间 | ||
| 145 | - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 146 | - convertSetByFlatMap(pageResult.getList(), user -> Stream.of(Long.parseLong(user.getCreator()), user.getOwnerUserId()))); | ||
| 147 | - Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||
| 148 | - return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap, poolDayMap)); | 175 | + return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal())); |
| 176 | + } | ||
| 177 | + | ||
| 178 | + @GetMapping("/put-pool-remind-count") | ||
| 179 | + @Operation(summary = "获得待进入公海客户数量") | ||
| 180 | + @PreAuthorize("@ss.hasPermission('crm:customer:query')") | ||
| 181 | + public CommonResult<Long> getPutPoolRemindCustomerCount() { | ||
| 182 | + return success(customerService.getPutPoolRemindCustomerCount(getLoginUserId())); | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + @GetMapping("/today-contact-count") | ||
| 186 | + @Operation(summary = "获得今日需联系客户数量") | ||
| 187 | + @PreAuthorize("@ss.hasPermission('crm:customer:query')") | ||
| 188 | + public CommonResult<Long> getTodayContactCustomerCount() { | ||
| 189 | + return success(customerService.getTodayContactCustomerCount(getLoginUserId())); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + @GetMapping("/follow-count") | ||
| 193 | + @Operation(summary = "获得分配给我、待跟进的线索数量的客户数量") | ||
| 194 | + @PreAuthorize("@ss.hasPermission('crm:customer:query')") | ||
| 195 | + public CommonResult<Long> getFollowCustomerCount() { | ||
| 196 | + return success(customerService.getFollowCustomerCount(getLoginUserId())); | ||
| 149 | } | 197 | } |
| 150 | 198 | ||
| 151 | /** | 199 | /** |
| 152 | - * 获取距离进入公海的时间 | 200 | + * 获取距离进入公海的时间 Map |
| 153 | * | 201 | * |
| 154 | - * @param customerList 客户列表 | ||
| 155 | - * @return Map<key 客户编号, value 距离进入公海的时间> | 202 | + * @param list 客户列表 |
| 203 | + * @return key 客户编号, value 距离进入公海的时间 | ||
| 156 | */ | 204 | */ |
| 157 | - private Map<Long, Long> getPoolDayMap(List<CrmCustomerDO> customerList) { | 205 | + private Map<Long, Long> getPoolDayMap(List<CrmCustomerDO> list) { |
| 158 | CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); | 206 | CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); |
| 159 | if (poolConfig == null || !poolConfig.getEnabled()) { | 207 | if (poolConfig == null || !poolConfig.getEnabled()) { |
| 160 | return MapUtil.empty(); | 208 | return MapUtil.empty(); |
| 161 | } | 209 | } |
| 162 | - return convertMap(customerList, CrmCustomerDO::getId, customer -> { | ||
| 163 | - // 1.1 未成交放入公海天数 | ||
| 164 | - long dealExpireDay = 0; | ||
| 165 | - if (!customer.getDealStatus()) { | ||
| 166 | - dealExpireDay = poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime()); | 210 | + list = CollectionUtils.filterList(list, customer -> { |
| 211 | + // 特殊:如果没负责人,则说明已经在公海,不用计算 | ||
| 212 | + if (customer.getOwnerUserId() == null) { | ||
| 213 | + return false; | ||
| 167 | } | 214 | } |
| 215 | + // 已成交 or 已锁定,不进入公海 | ||
| 216 | + return !customer.getDealStatus() && !customer.getLockStatus(); | ||
| 217 | + }); | ||
| 218 | + return convertMap(list, CrmCustomerDO::getId, customer -> { | ||
| 219 | + // 1.1 未成交放入公海天数 | ||
| 220 | + long dealExpireDay = poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getOwnerTime()); | ||
| 168 | // 1.2 未跟进放入公海天数 | 221 | // 1.2 未跟进放入公海天数 |
| 169 | - LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime()); | ||
| 170 | - long contactExpireDay = poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime); | ||
| 171 | - if (contactExpireDay < 0) { | ||
| 172 | - contactExpireDay = 0; | 222 | + LocalDateTime lastTime = customer.getOwnerTime(); |
| 223 | + if (customer.getContactLastTime() != null && customer.getContactLastTime().isAfter(lastTime)) { | ||
| 224 | + lastTime = customer.getContactLastTime(); | ||
| 173 | } | 225 | } |
| 226 | + long contactExpireDay = poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime); | ||
| 174 | // 2. 返回最小的天数 | 227 | // 2. 返回最小的天数 |
| 175 | - return Math.min(dealExpireDay, contactExpireDay); | 228 | + long poolDay = Math.min(dealExpireDay, contactExpireDay); |
| 229 | + return poolDay > 0 ? poolDay : 0; | ||
| 176 | }); | 230 | }); |
| 177 | } | 231 | } |
| 178 | 232 | ||
| 179 | - @GetMapping(value = "/list-all-simple") | 233 | + @GetMapping(value = "/simple-list") |
| 180 | @Operation(summary = "获取客户精简信息列表", description = "只包含有读权限的客户,主要用于前端的下拉选项") | 234 | @Operation(summary = "获取客户精简信息列表", description = "只包含有读权限的客户,主要用于前端的下拉选项") |
| 181 | - public CommonResult<List<CrmCustomerRespVO>> getSimpleDeptList() { | 235 | + public CommonResult<List<CrmCustomerRespVO>> getCustomerSimpleList() { |
| 182 | CrmCustomerPageReqVO reqVO = new CrmCustomerPageReqVO(); | 236 | CrmCustomerPageReqVO reqVO = new CrmCustomerPageReqVO(); |
| 183 | reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 | 237 | reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 |
| 184 | List<CrmCustomerDO> list = customerService.getCustomerPage(reqVO, getLoginUserId()).getList(); | 238 | List<CrmCustomerDO> list = customerService.getCustomerPage(reqVO, getLoginUserId()).getList(); |
| @@ -186,7 +240,6 @@ public class CrmCustomerController { | @@ -186,7 +240,6 @@ public class CrmCustomerController { | ||
| 186 | new CrmCustomerRespVO().setId(customer.getId()).setName(customer.getName()))); | 240 | new CrmCustomerRespVO().setId(customer.getId()).setName(customer.getName()))); |
| 187 | } | 241 | } |
| 188 | 242 | ||
| 189 | - // TODO @puhui999:公海的导出,前端可以接下 | ||
| 190 | @GetMapping("/export-excel") | 243 | @GetMapping("/export-excel") |
| 191 | @Operation(summary = "导出客户 Excel") | 244 | @Operation(summary = "导出客户 Excel") |
| 192 | @PreAuthorize("@ss.hasPermission('crm:customer:export')") | 245 | @PreAuthorize("@ss.hasPermission('crm:customer:export')") |
| @@ -197,7 +250,7 @@ public class CrmCustomerController { | @@ -197,7 +250,7 @@ public class CrmCustomerController { | ||
| 197 | List<CrmCustomerDO> list = customerService.getCustomerPage(pageVO, getLoginUserId()).getList(); | 250 | List<CrmCustomerDO> list = customerService.getCustomerPage(pageVO, getLoginUserId()).getList(); |
| 198 | // 导出 Excel | 251 | // 导出 Excel |
| 199 | ExcelUtils.write(response, "客户.xls", "数据", CrmCustomerRespVO.class, | 252 | ExcelUtils.write(response, "客户.xls", "数据", CrmCustomerRespVO.class, |
| 200 | - BeanUtils.toBean(list, CrmCustomerRespVO.class)); | 253 | + buildCustomerDetailList(list)); |
| 201 | } | 254 | } |
| 202 | 255 | ||
| 203 | @GetMapping("/get-import-template") | 256 | @GetMapping("/get-import-template") |
| @@ -205,15 +258,33 @@ public class CrmCustomerController { | @@ -205,15 +258,33 @@ public class CrmCustomerController { | ||
| 205 | public void importTemplate(HttpServletResponse response) throws IOException { | 258 | public void importTemplate(HttpServletResponse response) throws IOException { |
| 206 | // 手动创建导出 demo | 259 | // 手动创建导出 demo |
| 207 | List<CrmCustomerImportExcelVO> list = Arrays.asList( | 260 | List<CrmCustomerImportExcelVO> list = Arrays.asList( |
| 208 | - CrmCustomerImportExcelVO.builder().name("芋道").industryId(1).level(1).source(1).mobile("15601691300").telephone("") | ||
| 209 | - .website("https://doc.iocoder.cn/").qq("").wechat("").email("yunai@iocoder.cn").description("").remark("") | ||
| 210 | - .areaId(null).detailAddress("").build(), | ||
| 211 | - CrmCustomerImportExcelVO.builder().name("源码").industryId(1).level(1).source(1).mobile("15601691300").telephone("") | ||
| 212 | - .website("https://doc.iocoder.cn/").qq("").wechat("").email("yunai@iocoder.cn").description("").remark("") | ||
| 213 | - .areaId(null).detailAddress("").build() | 261 | + CrmCustomerImportExcelVO.builder().name("芋道").industryId(1).level(1).source(1) |
| 262 | + .mobile("15601691300").telephone("").qq("").wechat("").email("yunai@iocoder.cn") | ||
| 263 | + .areaId(null).detailAddress("").remark("").build(), | ||
| 264 | + CrmCustomerImportExcelVO.builder().name("源码").industryId(1).level(1).source(1) | ||
| 265 | + .mobile("15601691300").telephone("").qq("").wechat("").email("yunai@iocoder.cn") | ||
| 266 | + .areaId(null).detailAddress("").remark("").build() | ||
| 214 | ); | 267 | ); |
| 215 | // 输出 | 268 | // 输出 |
| 216 | - ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list); | 269 | + ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list, builderSelectMap()); |
| 270 | + } | ||
| 271 | + | ||
| 272 | + private List<KeyValue<ExcelColumn, List<String>>> builderSelectMap() { | ||
| 273 | + List<KeyValue<ExcelColumn, List<String>>> selectMap = new ArrayList<>(); | ||
| 274 | + // 获取地区下拉数据 | ||
| 275 | + // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? | ||
| 276 | + Area area = AreaUtils.parseArea(Area.ID_CHINA); | ||
| 277 | + selectMap.add(new KeyValue<>(ExcelColumn.G, AreaUtils.getAreaNodePathList(area.getChildren()))); | ||
| 278 | + // 获取客户所属行业 | ||
| 279 | + List<String> customerIndustries = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); | ||
| 280 | + selectMap.add(new KeyValue<>(ExcelColumn.I, customerIndustries)); | ||
| 281 | + // 获取客户等级 | ||
| 282 | + List<String> customerLevels = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); | ||
| 283 | + selectMap.add(new KeyValue<>(ExcelColumn.J, customerLevels)); | ||
| 284 | + // 获取客户来源 | ||
| 285 | + List<String> customerSources = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); | ||
| 286 | + selectMap.add(new KeyValue<>(ExcelColumn.K, customerSources)); | ||
| 287 | + return selectMap; | ||
| 217 | } | 288 | } |
| 218 | 289 | ||
| 219 | @PostMapping("/import") | 290 | @PostMapping("/import") |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java
| @@ -3,10 +3,11 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; | @@ -3,10 +3,11 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; | 8 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; |
| 7 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigRespVO; | 9 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigRespVO; |
| 8 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; | 10 | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; |
| 9 | -import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerLimitConfigConvert; | ||
| 10 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; | 11 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; |
| 11 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerLimitConfigService; | 12 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerLimitConfigService; |
| 12 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; | 13 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| @@ -71,11 +72,14 @@ public class CrmCustomerLimitConfigController { | @@ -71,11 +72,14 @@ public class CrmCustomerLimitConfigController { | ||
| 71 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 72 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 72 | @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:query')") | 73 | @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:query')") |
| 73 | public CommonResult<CrmCustomerLimitConfigRespVO> getCustomerLimitConfig(@RequestParam("id") Long id) { | 74 | public CommonResult<CrmCustomerLimitConfigRespVO> getCustomerLimitConfig(@RequestParam("id") Long id) { |
| 74 | - CrmCustomerLimitConfigDO customerLimitConfig = customerLimitConfigService.getCustomerLimitConfig(id); | 75 | + CrmCustomerLimitConfigDO limitConfig = customerLimitConfigService.getCustomerLimitConfig(id); |
| 75 | // 拼接数据 | 76 | // 拼接数据 |
| 76 | - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(customerLimitConfig.getUserIds()); | ||
| 77 | - Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(customerLimitConfig.getDeptIds()); | ||
| 78 | - return success(CrmCustomerLimitConfigConvert.INSTANCE.convert(customerLimitConfig, userMap, deptMap)); | 77 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(limitConfig.getUserIds()); |
| 78 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(limitConfig.getDeptIds()); | ||
| 79 | + return success(BeanUtils.toBean(limitConfig, CrmCustomerLimitConfigRespVO.class, configVO -> { | ||
| 80 | + configVO.setUsers(CollectionUtils.convertList(configVO.getUserIds(), userMap::get)); | ||
| 81 | + configVO.setDepts(CollectionUtils.convertList(configVO.getDeptIds(), deptMap::get)); | ||
| 82 | + })); | ||
| 79 | } | 83 | } |
| 80 | 84 | ||
| 81 | @GetMapping("/page") | 85 | @GetMapping("/page") |
| @@ -91,7 +95,10 @@ public class CrmCustomerLimitConfigController { | @@ -91,7 +95,10 @@ public class CrmCustomerLimitConfigController { | ||
| 91 | convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getUserIds, Collection::stream)); | 95 | convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getUserIds, Collection::stream)); |
| 92 | Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( | 96 | Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( |
| 93 | convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getDeptIds, Collection::stream)); | 97 | convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getDeptIds, Collection::stream)); |
| 94 | - return success(CrmCustomerLimitConfigConvert.INSTANCE.convertPage(pageResult, userMap, deptMap)); | 98 | + return success(BeanUtils.toBean(pageResult, CrmCustomerLimitConfigRespVO.class, configVO -> { |
| 99 | + configVO.setUsers(CollectionUtils.convertList(configVO.getUserIds(), userMap::get)); | ||
| 100 | + configVO.setDepts(CollectionUtils.convertList(configVO.getDeptIds(), deptMap::get)); | ||
| 101 | + })); | ||
| 95 | } | 102 | } |
| 96 | 103 | ||
| 97 | } | 104 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerDistributeReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import jakarta.validation.constraints.NotEmpty; | 4 | import jakarta.validation.constraints.NotEmpty; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerImportExcelVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | +import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; | ||
| 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | 5 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| 5 | import com.alibaba.excel.annotation.ExcelProperty; | 6 | import com.alibaba.excel.annotation.ExcelProperty; |
| 6 | import lombok.AllArgsConstructor; | 7 | import lombok.AllArgsConstructor; |
| @@ -24,28 +25,12 @@ public class CrmCustomerImportExcelVO { | @@ -24,28 +25,12 @@ public class CrmCustomerImportExcelVO { | ||
| 24 | @ExcelProperty("客户名称") | 25 | @ExcelProperty("客户名称") |
| 25 | private String name; | 26 | private String name; |
| 26 | 27 | ||
| 27 | - // TODO @puhui999:industryId、level、source 字段,可以研究下怎么搞下拉框 | ||
| 28 | - @ExcelProperty(value = "所属行业", converter = DictConvert.class) | ||
| 29 | - @DictFormat(CRM_CUSTOMER_INDUSTRY) | ||
| 30 | - private Integer industryId; | ||
| 31 | - | ||
| 32 | - @ExcelProperty(value = "客户等级", converter = DictConvert.class) | ||
| 33 | - @DictFormat(CRM_CUSTOMER_LEVEL) | ||
| 34 | - private Integer level; | ||
| 35 | - | ||
| 36 | - @ExcelProperty(value = "客户来源", converter = DictConvert.class) | ||
| 37 | - @DictFormat(CRM_CUSTOMER_SOURCE) | ||
| 38 | - private Integer source; | ||
| 39 | - | ||
| 40 | @ExcelProperty("手机") | 28 | @ExcelProperty("手机") |
| 41 | private String mobile; | 29 | private String mobile; |
| 42 | 30 | ||
| 43 | @ExcelProperty("电话") | 31 | @ExcelProperty("电话") |
| 44 | private String telephone; | 32 | private String telephone; |
| 45 | 33 | ||
| 46 | - @ExcelProperty("网址") | ||
| 47 | - private String website; | ||
| 48 | - | ||
| 49 | @ExcelProperty("QQ") | 34 | @ExcelProperty("QQ") |
| 50 | private String qq; | 35 | private String qq; |
| 51 | 36 | ||
| @@ -55,17 +40,25 @@ public class CrmCustomerImportExcelVO { | @@ -55,17 +40,25 @@ public class CrmCustomerImportExcelVO { | ||
| 55 | @ExcelProperty("邮箱") | 40 | @ExcelProperty("邮箱") |
| 56 | private String email; | 41 | private String email; |
| 57 | 42 | ||
| 58 | - @ExcelProperty("客户描述") | ||
| 59 | - private String description; | ||
| 60 | - | ||
| 61 | - @ExcelProperty("备注") | ||
| 62 | - private String remark; | ||
| 63 | - | ||
| 64 | - // TODO @puhui999:需要选择省市区,需要研究下,怎么搞合理点; | ||
| 65 | - @ExcelProperty("地区编号") | 43 | + @ExcelProperty(value = "地区", converter = AreaConvert.class) |
| 66 | private Integer areaId; | 44 | private Integer areaId; |
| 67 | 45 | ||
| 68 | @ExcelProperty("详细地址") | 46 | @ExcelProperty("详细地址") |
| 69 | private String detailAddress; | 47 | private String detailAddress; |
| 70 | 48 | ||
| 49 | + @ExcelProperty(value = "所属行业", converter = DictConvert.class) | ||
| 50 | + @DictFormat(CRM_CUSTOMER_INDUSTRY) | ||
| 51 | + private Integer industryId; | ||
| 52 | + | ||
| 53 | + @ExcelProperty(value = "客户等级", converter = DictConvert.class) | ||
| 54 | + @DictFormat(CRM_CUSTOMER_LEVEL) | ||
| 55 | + private Integer level; | ||
| 56 | + | ||
| 57 | + @ExcelProperty(value = "客户来源", converter = DictConvert.class) | ||
| 58 | + @DictFormat(CRM_CUSTOMER_SOURCE) | ||
| 59 | + private Integer source; | ||
| 60 | + | ||
| 61 | + @ExcelProperty("备注") | ||
| 62 | + private String remark; | ||
| 63 | + | ||
| 71 | } | 64 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerImportReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import jakarta.validation.constraints.NotNull; | 4 | import jakarta.validation.constraints.NotNull; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerImportRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Builder; | 4 | import lombok.Builder; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerLockReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Data; | 4 | import lombok.Data; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerPageReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 4 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| @@ -14,6 +14,19 @@ import lombok.ToString; | @@ -14,6 +14,19 @@ import lombok.ToString; | ||
| 14 | @ToString(callSuper = true) | 14 | @ToString(callSuper = true) |
| 15 | public class CrmCustomerPageReqVO extends PageParam { | 15 | public class CrmCustomerPageReqVO extends PageParam { |
| 16 | 16 | ||
| 17 | + /** | ||
| 18 | + * 联系状态 - 今日需联系 | ||
| 19 | + */ | ||
| 20 | + public static final int CONTACT_TODAY = 1; | ||
| 21 | + /** | ||
| 22 | + * 联系状态 - 已逾期 | ||
| 23 | + */ | ||
| 24 | + public static final int CONTACT_EXPIRED = 2; | ||
| 25 | + /** | ||
| 26 | + * 联系状态 - 已联系 | ||
| 27 | + */ | ||
| 28 | + public static final int CONTACT_ALREADY = 3; | ||
| 29 | + | ||
| 17 | @Schema(description = "客户名称", example = "赵六") | 30 | @Schema(description = "客户名称", example = "赵六") |
| 18 | private String name; | 31 | private String name; |
| 19 | 32 | ||
| @@ -36,4 +49,10 @@ public class CrmCustomerPageReqVO extends PageParam { | @@ -36,4 +49,10 @@ public class CrmCustomerPageReqVO extends PageParam { | ||
| 36 | @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | 49 | @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") |
| 37 | private Boolean pool; // null 则表示为不是公海数据 | 50 | private Boolean pool; // null 则表示为不是公海数据 |
| 38 | 51 | ||
| 52 | + @Schema(description = "联系状态", example = "1") | ||
| 53 | + private Integer contactStatus; // backlog 查询条件 | ||
| 54 | + | ||
| 55 | + @Schema(description = "跟进状态", example = "true") | ||
| 56 | + private Boolean followUpStatus; | ||
| 57 | + | ||
| 39 | } | 58 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; |
| @@ -7,12 +7,9 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | @@ -7,12 +7,9 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | ||
| 7 | import com.alibaba.excel.annotation.ExcelProperty; | 7 | import com.alibaba.excel.annotation.ExcelProperty; |
| 8 | import io.swagger.v3.oas.annotations.media.Schema; | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | import lombok.Data; | 9 | import lombok.Data; |
| 10 | -import org.springframework.format.annotation.DateTimeFormat; | ||
| 11 | 10 | ||
| 12 | import java.time.LocalDateTime; | 11 | import java.time.LocalDateTime; |
| 13 | 12 | ||
| 14 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 15 | - | ||
| 16 | @Schema(description = "管理后台 - CRM 客户 Response VO") | 13 | @Schema(description = "管理后台 - CRM 客户 Response VO") |
| 17 | @Data | 14 | @Data |
| 18 | @ExcelIgnoreUnannotated | 15 | @ExcelIgnoreUnannotated |
| @@ -31,6 +28,28 @@ public class CrmCustomerRespVO { | @@ -31,6 +28,28 @@ public class CrmCustomerRespVO { | ||
| 31 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) | 28 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) |
| 32 | private Boolean followUpStatus; | 29 | private Boolean followUpStatus; |
| 33 | 30 | ||
| 31 | + @Schema(description = "最后跟进时间") | ||
| 32 | + @ExcelProperty("最后跟进时间") | ||
| 33 | + private LocalDateTime contactLastTime; | ||
| 34 | + | ||
| 35 | + @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗") | ||
| 36 | + @ExcelProperty("最后跟进内容") | ||
| 37 | + private String contactLastContent; | ||
| 38 | + | ||
| 39 | + @Schema(description = "下次联系时间") | ||
| 40 | + @ExcelProperty("下次联系时间") | ||
| 41 | + private LocalDateTime contactNextTime; | ||
| 42 | + | ||
| 43 | + @Schema(description = "负责人的用户编号", example = "25682") | ||
| 44 | + @ExcelProperty("负责人的用户编号") | ||
| 45 | + private Long ownerUserId; | ||
| 46 | + @Schema(description = "负责人名字", example = "25682") | ||
| 47 | + @ExcelProperty("负责人名字") | ||
| 48 | + private String ownerUserName; | ||
| 49 | + @Schema(description = "负责人部门") | ||
| 50 | + @ExcelProperty("负责人部门") | ||
| 51 | + private String ownerUserDeptName; | ||
| 52 | + | ||
| 34 | @Schema(description = "锁定状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | 53 | @Schema(description = "锁定状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") |
| 35 | @ExcelProperty(value = "锁定状态", converter = DictConvert.class) | 54 | @ExcelProperty(value = "锁定状态", converter = DictConvert.class) |
| 36 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) | 55 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) |
| @@ -41,63 +60,26 @@ public class CrmCustomerRespVO { | @@ -41,63 +60,26 @@ public class CrmCustomerRespVO { | ||
| 41 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) | 60 | @DictFormat(DictTypeConstants.BOOLEAN_STRING) |
| 42 | private Boolean dealStatus; | 61 | private Boolean dealStatus; |
| 43 | 62 | ||
| 44 | - @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||
| 45 | - @ExcelProperty(value = "所属行业", converter = DictConvert.class) | ||
| 46 | - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY) | ||
| 47 | - private Integer industryId; | ||
| 48 | - | ||
| 49 | - @Schema(description = "客户等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||
| 50 | - @ExcelProperty(value = "客户等级", converter = DictConvert.class) | ||
| 51 | - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL) | ||
| 52 | - private Integer level; | ||
| 53 | - | ||
| 54 | - @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||
| 55 | - @ExcelProperty(value = "客户来源", converter = DictConvert.class) | ||
| 56 | - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) | ||
| 57 | - private Integer source; | ||
| 58 | - | ||
| 59 | - @Schema(description = "负责人的用户编号", example = "25682") | 63 | + @Schema(description = "手机", example = "25682") |
| 60 | @ExcelProperty("手机") | 64 | @ExcelProperty("手机") |
| 61 | private String mobile; | 65 | private String mobile; |
| 62 | 66 | ||
| 63 | - @Schema(description = "负责人的用户编号", example = "25682") | 67 | + @Schema(description = "电话", example = "25682") |
| 64 | @ExcelProperty("电话") | 68 | @ExcelProperty("电话") |
| 65 | private String telephone; | 69 | private String telephone; |
| 66 | 70 | ||
| 67 | - @Schema(description = "负责人的用户编号", example = "25682") | ||
| 68 | - @ExcelProperty("网址") | ||
| 69 | - private String website; | ||
| 70 | - | ||
| 71 | - @Schema(description = "负责人的用户编号", example = "25682") | 71 | + @Schema(description = "QQ", example = "25682") |
| 72 | @ExcelProperty("QQ") | 72 | @ExcelProperty("QQ") |
| 73 | private String qq; | 73 | private String qq; |
| 74 | 74 | ||
| 75 | - @Schema(description = "负责人的用户编号", example = "25682") | 75 | + @Schema(description = "wechat", example = "25682") |
| 76 | @ExcelProperty("wechat") | 76 | @ExcelProperty("wechat") |
| 77 | private String wechat; | 77 | private String wechat; |
| 78 | 78 | ||
| 79 | - @Schema(description = "负责人的用户编号", example = "25682") | 79 | + @Schema(description = "email", example = "25682") |
| 80 | @ExcelProperty("email") | 80 | @ExcelProperty("email") |
| 81 | private String email; | 81 | private String email; |
| 82 | 82 | ||
| 83 | - @Schema(description = "负责人的用户编号", example = "25682") | ||
| 84 | - @ExcelProperty("客户描述") | ||
| 85 | - private String description; | ||
| 86 | - | ||
| 87 | - @Schema(description = "负责人的用户编号", example = "25682") | ||
| 88 | - @ExcelProperty("备注") | ||
| 89 | - private String remark; | ||
| 90 | - | ||
| 91 | - @Schema(description = "负责人的用户编号", example = "25682") | ||
| 92 | - @ExcelProperty("负责人的用户编号") | ||
| 93 | - private Long ownerUserId; | ||
| 94 | - @Schema(description = "负责人名字", example = "25682") | ||
| 95 | - @ExcelProperty("负责人名字") | ||
| 96 | - private String ownerUserName; | ||
| 97 | - @Schema(description = "负责人部门") | ||
| 98 | - @ExcelProperty("负责人部门") | ||
| 99 | - private String ownerUserDeptName; | ||
| 100 | - | ||
| 101 | @Schema(description = "地区编号", example = "1024") | 83 | @Schema(description = "地区编号", example = "1024") |
| 102 | @ExcelProperty("地区编号") | 84 | @ExcelProperty("地区编号") |
| 103 | private Integer areaId; | 85 | private Integer areaId; |
| @@ -108,14 +90,24 @@ public class CrmCustomerRespVO { | @@ -108,14 +90,24 @@ public class CrmCustomerRespVO { | ||
| 108 | @ExcelProperty("详细地址") | 90 | @ExcelProperty("详细地址") |
| 109 | private String detailAddress; | 91 | private String detailAddress; |
| 110 | 92 | ||
| 111 | - @Schema(description = "最后跟进时间") | ||
| 112 | - @ExcelProperty("最后跟进时间") | ||
| 113 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 114 | - private LocalDateTime contactLastTime; | 93 | + @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") |
| 94 | + @ExcelProperty(value = "所属行业", converter = DictConvert.class) | ||
| 95 | + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY) | ||
| 96 | + private Integer industryId; | ||
| 115 | 97 | ||
| 116 | - @Schema(description = "下次联系时间") | ||
| 117 | - @ExcelProperty("下次联系时间") | ||
| 118 | - private LocalDateTime contactNextTime; | 98 | + @Schema(description = "客户等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") |
| 99 | + @ExcelProperty(value = "客户等级", converter = DictConvert.class) | ||
| 100 | + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL) | ||
| 101 | + private Integer level; | ||
| 102 | + | ||
| 103 | + @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||
| 104 | + @ExcelProperty(value = "客户来源", converter = DictConvert.class) | ||
| 105 | + @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) | ||
| 106 | + private Integer source; | ||
| 107 | + | ||
| 108 | + @Schema(description = "负责人的用户编号", example = "25682") | ||
| 109 | + @ExcelProperty("备注") | ||
| 110 | + private String remark; | ||
| 119 | 111 | ||
| 120 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 112 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 121 | @ExcelProperty("创建时间") | 113 | @ExcelProperty("创建时间") |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerSaveReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 3 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 4 | import cn.iocoder.yudao.framework.common.validation.Mobile; | 4 | import cn.iocoder.yudao.framework.common.validation.Mobile; |
| @@ -13,6 +13,7 @@ import com.mzt.logapi.starter.annotation.DiffLogField; | @@ -13,6 +13,7 @@ import com.mzt.logapi.starter.annotation.DiffLogField; | ||
| 13 | import io.swagger.v3.oas.annotations.media.Schema; | 13 | import io.swagger.v3.oas.annotations.media.Schema; |
| 14 | import jakarta.validation.constraints.Email; | 14 | import jakarta.validation.constraints.Email; |
| 15 | import jakarta.validation.constraints.NotEmpty; | 15 | import jakarta.validation.constraints.NotEmpty; |
| 16 | +import jakarta.validation.constraints.NotNull; | ||
| 16 | import jakarta.validation.constraints.Size; | 17 | import jakarta.validation.constraints.Size; |
| 17 | import lombok.Data; | 18 | import lombok.Data; |
| 18 | import org.springframework.format.annotation.DateTimeFormat; | 19 | import org.springframework.format.annotation.DateTimeFormat; |
| @@ -34,19 +35,14 @@ public class CrmCustomerSaveReqVO { | @@ -34,19 +35,14 @@ public class CrmCustomerSaveReqVO { | ||
| 34 | @NotEmpty(message = "客户名称不能为空") | 35 | @NotEmpty(message = "客户名称不能为空") |
| 35 | private String name; | 36 | private String name; |
| 36 | 37 | ||
| 37 | - @Schema(description = "所属行业", example = "1") | ||
| 38 | - @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) | ||
| 39 | - @DictFormat(CRM_CUSTOMER_INDUSTRY) | ||
| 40 | - private Integer industryId; | ||
| 41 | - | ||
| 42 | - @Schema(description = "客户等级", example = "2") | ||
| 43 | - @DiffLogField(name = "客户等级", function = CrmCustomerLevelParseFunction.NAME) | ||
| 44 | - @InEnum(CrmCustomerLevelEnum.class) | ||
| 45 | - private Integer level; | 38 | + @Schema(description = "下次联系时间") |
| 39 | + @DiffLogField(name = "下次联系时间") | ||
| 40 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 41 | + private LocalDateTime contactNextTime; | ||
| 46 | 42 | ||
| 47 | - @Schema(description = "客户来源", example = "3") | ||
| 48 | - @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) | ||
| 49 | - private Integer source; | 43 | + @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") |
| 44 | + @NotNull(message = "负责人的用户编号不能为空") | ||
| 45 | + private Long ownerUserId; | ||
| 50 | 46 | ||
| 51 | @Schema(description = "手机", example = "18000000000") | 47 | @Schema(description = "手机", example = "18000000000") |
| 52 | @DiffLogField(name = "手机") | 48 | @DiffLogField(name = "手机") |
| @@ -58,10 +54,6 @@ public class CrmCustomerSaveReqVO { | @@ -58,10 +54,6 @@ public class CrmCustomerSaveReqVO { | ||
| 58 | @Telephone | 54 | @Telephone |
| 59 | private String telephone; | 55 | private String telephone; |
| 60 | 56 | ||
| 61 | - @Schema(description = "网址", example = "https://www.baidu.com") | ||
| 62 | - @DiffLogField(name = "网址") | ||
| 63 | - private String website; | ||
| 64 | - | ||
| 65 | @Schema(description = "QQ", example = "123456789") | 57 | @Schema(description = "QQ", example = "123456789") |
| 66 | @DiffLogField(name = "QQ") | 58 | @DiffLogField(name = "QQ") |
| 67 | @Size(max = 20, message = "QQ长度不能超过 20 个字符") | 59 | @Size(max = 20, message = "QQ长度不能超过 20 个字符") |
| @@ -78,15 +70,6 @@ public class CrmCustomerSaveReqVO { | @@ -78,15 +70,6 @@ public class CrmCustomerSaveReqVO { | ||
| 78 | @Size(max = 255, message = "邮箱长度不能超过 255 个字符") | 70 | @Size(max = 255, message = "邮箱长度不能超过 255 个字符") |
| 79 | private String email; | 71 | private String email; |
| 80 | 72 | ||
| 81 | - @Schema(description = "客户描述", example = "任意文字") | ||
| 82 | - @DiffLogField(name = "客户描述") | ||
| 83 | - @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") | ||
| 84 | - private String description; | ||
| 85 | - | ||
| 86 | - @Schema(description = "备注", example = "随便") | ||
| 87 | - @DiffLogField(name = "备注") | ||
| 88 | - private String remark; | ||
| 89 | - | ||
| 90 | @Schema(description = "地区编号", example = "20158") | 73 | @Schema(description = "地区编号", example = "20158") |
| 91 | @DiffLogField(name = "地区编号", function = SysAreaParseFunction.NAME) | 74 | @DiffLogField(name = "地区编号", function = SysAreaParseFunction.NAME) |
| 92 | private Integer areaId; | 75 | private Integer areaId; |
| @@ -95,12 +78,22 @@ public class CrmCustomerSaveReqVO { | @@ -95,12 +78,22 @@ public class CrmCustomerSaveReqVO { | ||
| 95 | @DiffLogField(name = "详细地址") | 78 | @DiffLogField(name = "详细地址") |
| 96 | private String detailAddress; | 79 | private String detailAddress; |
| 97 | 80 | ||
| 98 | - @Schema(description = "下次联系时间") | ||
| 99 | - @DiffLogField(name = "下次联系时间") | ||
| 100 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 101 | - private LocalDateTime contactNextTime; | 81 | + @Schema(description = "所属行业", example = "1") |
| 82 | + @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) | ||
| 83 | + @DictFormat(CRM_CUSTOMER_INDUSTRY) | ||
| 84 | + private Integer industryId; | ||
| 102 | 85 | ||
| 103 | - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | ||
| 104 | - private Long ownerUserId; | 86 | + @Schema(description = "客户等级", example = "2") |
| 87 | + @DiffLogField(name = "客户等级", function = CrmCustomerLevelParseFunction.NAME) | ||
| 88 | + @InEnum(CrmCustomerLevelEnum.class) | ||
| 89 | + private Integer level; | ||
| 90 | + | ||
| 91 | + @Schema(description = "客户来源", example = "3") | ||
| 92 | + @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) | ||
| 93 | + private Integer source; | ||
| 94 | + | ||
| 95 | + @Schema(description = "备注", example = "随便") | ||
| 96 | + @DiffLogField(name = "备注") | ||
| 97 | + private String remark; | ||
| 105 | 98 | ||
| 106 | } | 99 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | 3 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| 4 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java
| @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | 5 | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; |
| 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 7 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; | ||
| 7 | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; | 8 | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; |
| 8 | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordRespVO; | 9 | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordRespVO; |
| 9 | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; | 10 | import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; |
| @@ -13,6 +14,8 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; | @@ -13,6 +14,8 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; | ||
| 13 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; | 14 | import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; |
| 14 | import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; | 15 | import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; |
| 15 | import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; | 16 | import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; |
| 17 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 18 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 16 | import io.swagger.v3.oas.annotations.Operation; | 19 | import io.swagger.v3.oas.annotations.Operation; |
| 17 | import io.swagger.v3.oas.annotations.Parameter; | 20 | import io.swagger.v3.oas.annotations.Parameter; |
| 18 | import io.swagger.v3.oas.annotations.tags.Tag; | 21 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -26,7 +29,7 @@ import java.util.ArrayList; | @@ -26,7 +29,7 @@ import java.util.ArrayList; | ||
| 26 | import java.util.Map; | 29 | import java.util.Map; |
| 27 | 30 | ||
| 28 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 31 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 29 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | 32 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 30 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; | 33 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; |
| 31 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 34 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 32 | 35 | ||
| @@ -44,6 +47,9 @@ public class CrmFollowUpRecordController { | @@ -44,6 +47,9 @@ public class CrmFollowUpRecordController { | ||
| 44 | @Resource | 47 | @Resource |
| 45 | private CrmBusinessService businessService; | 48 | private CrmBusinessService businessService; |
| 46 | 49 | ||
| 50 | + @Resource | ||
| 51 | + private AdminUserApi adminUserApi; | ||
| 52 | + | ||
| 47 | @PostMapping("/create") | 53 | @PostMapping("/create") |
| 48 | @Operation(summary = "创建跟进记录") | 54 | @Operation(summary = "创建跟进记录") |
| 49 | @PreAuthorize("@ss.hasPermission('crm:follow-up-record:create')") | 55 | @PreAuthorize("@ss.hasPermission('crm:follow-up-record:create')") |
| @@ -74,17 +80,24 @@ public class CrmFollowUpRecordController { | @@ -74,17 +80,24 @@ public class CrmFollowUpRecordController { | ||
| 74 | @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") | 80 | @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") |
| 75 | public CommonResult<PageResult<CrmFollowUpRecordRespVO>> getFollowUpRecordPage(@Valid CrmFollowUpRecordPageReqVO pageReqVO) { | 81 | public CommonResult<PageResult<CrmFollowUpRecordRespVO>> getFollowUpRecordPage(@Valid CrmFollowUpRecordPageReqVO pageReqVO) { |
| 76 | PageResult<CrmFollowUpRecordDO> pageResult = followUpRecordService.getFollowUpRecordPage(pageReqVO); | 82 | PageResult<CrmFollowUpRecordDO> pageResult = followUpRecordService.getFollowUpRecordPage(pageReqVO); |
| 77 | - /// 拼接数据 | ||
| 78 | - Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactListByIds( | ||
| 79 | - convertSetByFlatMap(pageResult.getList(), item -> item.getContactIds().stream())), CrmContactDO::getId); | ||
| 80 | - Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList( | ||
| 81 | - convertSetByFlatMap(pageResult.getList(), item -> item.getBusinessIds().stream())), CrmBusinessDO::getId); | 83 | + // 1.1 查询联系人和商机 |
| 84 | + Map<Long, CrmContactDO> contactMap = contactService.getContactMap( | ||
| 85 | + convertSetByFlatMap(pageResult.getList(), item -> item.getContactIds().stream())); | ||
| 86 | + Map<Long, CrmBusinessDO> businessMap = businessService.getBusinessMap( | ||
| 87 | + convertSetByFlatMap(pageResult.getList(), item -> item.getBusinessIds().stream())); | ||
| 88 | + // 1.2 查询用户 | ||
| 89 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 90 | + convertSet(pageResult.getList(), item -> Long.valueOf(item.getCreator()))); | ||
| 91 | + // 2. 拼接数据 | ||
| 82 | PageResult<CrmFollowUpRecordRespVO> voPageResult = BeanUtils.toBean(pageResult, CrmFollowUpRecordRespVO.class, record -> { | 92 | PageResult<CrmFollowUpRecordRespVO> voPageResult = BeanUtils.toBean(pageResult, CrmFollowUpRecordRespVO.class, record -> { |
| 83 | - record.setContactNames(new ArrayList<>()).setBusinessNames(new ArrayList<>()); | ||
| 84 | - record.getContactIds().forEach(id -> MapUtils.findAndThen(contactMap, id, | ||
| 85 | - contact -> record.getContactNames().add(contact.getName()))); | ||
| 86 | - record.getContactIds().forEach(id -> MapUtils.findAndThen(businessMap, id, | ||
| 87 | - business -> record.getBusinessNames().add(business.getName()))); | 93 | + // 2.1 设置联系人和商机信息 |
| 94 | + record.setBusinesses(new ArrayList<>()).setContacts(new ArrayList<>()); | ||
| 95 | + record.getContactIds().forEach(id -> MapUtils.findAndThen(contactMap, id, contact -> | ||
| 96 | + record.getContacts().add(new CrmBusinessRespVO().setId(contact.getId()).setName(contact.getName())))); | ||
| 97 | + record.getContactIds().forEach(id -> MapUtils.findAndThen(businessMap, id, business -> | ||
| 98 | + record.getBusinesses().add(new CrmBusinessRespVO().setId(business.getId()).setName(business.getName())))); | ||
| 99 | + // 2.2 设置用户信息 | ||
| 100 | + MapUtils.findAndThen(userMap, Long.valueOf(record.getCreator()), user -> record.setCreatorName(user.getNickname())); | ||
| 88 | }); | 101 | }); |
| 89 | return success(voPageResult); | 102 | return success(voPageResult); |
| 90 | } | 103 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; | ||
| 4 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | 5 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| 6 | +import com.alibaba.excel.annotation.ExcelProperty; | ||
| 5 | import io.swagger.v3.oas.annotations.media.Schema; | 7 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | import lombok.Data; | 8 | import lombok.Data; |
| 7 | 9 | ||
| @@ -36,19 +38,26 @@ public class CrmFollowUpRecordRespVO { | @@ -36,19 +38,26 @@ public class CrmFollowUpRecordRespVO { | ||
| 36 | 38 | ||
| 37 | @Schema(description = "关联的商机编号数组") | 39 | @Schema(description = "关联的商机编号数组") |
| 38 | private List<Long> businessIds; | 40 | private List<Long> businessIds; |
| 39 | - @Schema(description = "关联的商机名称数组") | ||
| 40 | - private List<String> businessNames; | 41 | + @Schema(description = "关联的商机数组") |
| 42 | + private List<CrmBusinessRespVO> businesses; | ||
| 41 | 43 | ||
| 42 | @Schema(description = "关联的联系人编号数组") | 44 | @Schema(description = "关联的联系人编号数组") |
| 43 | private List<Long> contactIds; | 45 | private List<Long> contactIds; |
| 44 | @Schema(description = "关联的联系人名称数组") | 46 | @Schema(description = "关联的联系人名称数组") |
| 45 | - private List<String> contactNames; | 47 | + private List<CrmBusinessRespVO> contacts; |
| 46 | 48 | ||
| 47 | @Schema(description = "图片") | 49 | @Schema(description = "图片") |
| 48 | private List<String> picUrls; | 50 | private List<String> picUrls; |
| 49 | @Schema(description = "附件") | 51 | @Schema(description = "附件") |
| 50 | private List<String> fileUrls; | 52 | private List<String> fileUrls; |
| 51 | 53 | ||
| 54 | + @Schema(description = "创建人", example = "1024") | ||
| 55 | + @ExcelProperty("创建人") | ||
| 56 | + private String creator; | ||
| 57 | + @Schema(description = "创建人名字", example = "芋道源码") | ||
| 58 | + @ExcelProperty("创建人名字") | ||
| 59 | + private String creatorName; | ||
| 60 | + | ||
| 52 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 61 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 53 | private LocalDateTime createTime; | 62 | private LocalDateTime createTime; |
| 54 | 63 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java
| @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 6 | import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogPageReqVO; | 6 | import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogPageReqVO; |
| 7 | -import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogV2RespVO; | 7 | +import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogRespVO; |
| 8 | import cn.iocoder.yudao.module.crm.enums.LogRecordConstants; | 8 | import cn.iocoder.yudao.module.crm.enums.LogRecordConstants; |
| 9 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | 9 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| 10 | import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; | 10 | import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; |
| @@ -41,7 +41,7 @@ public class CrmOperateLogController { | @@ -41,7 +41,7 @@ public class CrmOperateLogController { | ||
| 41 | private static final Map<Integer, String> BIZ_TYPE_MAP = new HashMap<>(); | 41 | private static final Map<Integer, String> BIZ_TYPE_MAP = new HashMap<>(); |
| 42 | 42 | ||
| 43 | static { | 43 | static { |
| 44 | - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_LEADS.getType(), CRM_LEADS_TYPE); | 44 | + BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CLUE.getType(), CRM_CLUE_TYPE); |
| 45 | BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CUSTOMER.getType(), CRM_CUSTOMER_TYPE); | 45 | BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CUSTOMER.getType(), CRM_CUSTOMER_TYPE); |
| 46 | BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CONTACT.getType(), CRM_CONTACT_TYPE); | 46 | BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CONTACT.getType(), CRM_CONTACT_TYPE); |
| 47 | BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_BUSINESS.getType(), CRM_BUSINESS_TYPE); | 47 | BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_BUSINESS.getType(), CRM_BUSINESS_TYPE); |
| @@ -54,11 +54,11 @@ public class CrmOperateLogController { | @@ -54,11 +54,11 @@ public class CrmOperateLogController { | ||
| 54 | @GetMapping("/page") | 54 | @GetMapping("/page") |
| 55 | @Operation(summary = "获得操作日志") | 55 | @Operation(summary = "获得操作日志") |
| 56 | @PreAuthorize("@ss.hasPermission('crm:operate-log:query')") | 56 | @PreAuthorize("@ss.hasPermission('crm:operate-log:query')") |
| 57 | - public CommonResult<PageResult<CrmOperateLogV2RespVO>> getCustomerOperateLog(@Valid CrmOperateLogPageReqVO pageReqVO) { | 57 | + public CommonResult<PageResult<CrmOperateLogRespVO>> getCustomerOperateLog(@Valid CrmOperateLogPageReqVO pageReqVO) { |
| 58 | OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO(); | 58 | OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO(); |
| 59 | reqDTO.setPageSize(PAGE_SIZE_NONE); // 默认不分页,需要分页需注释 | 59 | reqDTO.setPageSize(PAGE_SIZE_NONE); // 默认不分页,需要分页需注释 |
| 60 | reqDTO.setBizType(BIZ_TYPE_MAP.get(pageReqVO.getBizType())).setBizId(pageReqVO.getBizId()); | 60 | reqDTO.setBizType(BIZ_TYPE_MAP.get(pageReqVO.getBizType())).setBizId(pageReqVO.getBizId()); |
| 61 | - return success(BeanUtils.toBean(operateLogApi.getOperateLogPage(reqDTO), CrmOperateLogV2RespVO.class)); | 61 | + return success(BeanUtils.toBean(operateLogApi.getOperateLogPage(reqDTO), CrmOperateLogRespVO.class)); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | } | 64 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogV2RespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java
| @@ -6,10 +6,10 @@ import lombok.Data; | @@ -6,10 +6,10 @@ import lombok.Data; | ||
| 6 | 6 | ||
| 7 | import java.time.LocalDateTime; | 7 | import java.time.LocalDateTime; |
| 8 | 8 | ||
| 9 | -@Schema(description = "管理后台 - CRM 跟进 Response VO") | 9 | +@Schema(description = "管理后台 - CRM 操作日志 Response VO") |
| 10 | @Data | 10 | @Data |
| 11 | @ExcelIgnoreUnannotated | 11 | @ExcelIgnoreUnannotated |
| 12 | -public class CrmOperateLogV2RespVO { | 12 | +public class CrmOperateLogRespVO { |
| 13 | 13 | ||
| 14 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") | 14 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") |
| 15 | private Long id; | 15 | private Long id; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java
| @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.crm.controller.admin.permission; | @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.crm.controller.admin.permission; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 5 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 6 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 7 | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionCreateReqVO; | 8 | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionCreateReqVO; |
| 8 | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; | 9 | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; |
| 9 | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; | 10 | import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; |
| 10 | -import cn.iocoder.yudao.module.crm.convert.permission.CrmPermissionConvert; | ||
| 11 | import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; | 11 | import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; |
| 12 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | 12 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| 13 | import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; | 13 | import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; |
| @@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | @@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 19 | import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; | 19 | import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; |
| 20 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | 20 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 21 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 21 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 22 | +import com.google.common.collect.Multimaps; | ||
| 22 | import io.swagger.v3.oas.annotations.Operation; | 23 | import io.swagger.v3.oas.annotations.Operation; |
| 23 | import io.swagger.v3.oas.annotations.Parameter; | 24 | import io.swagger.v3.oas.annotations.Parameter; |
| 24 | import io.swagger.v3.oas.annotations.Parameters; | 25 | import io.swagger.v3.oas.annotations.Parameters; |
| @@ -29,11 +30,16 @@ import org.springframework.security.access.prepost.PreAuthorize; | @@ -29,11 +30,16 @@ import org.springframework.security.access.prepost.PreAuthorize; | ||
| 29 | import org.springframework.validation.annotation.Validated; | 30 | import org.springframework.validation.annotation.Validated; |
| 30 | import org.springframework.web.bind.annotation.*; | 31 | import org.springframework.web.bind.annotation.*; |
| 31 | 32 | ||
| 32 | -import java.util.*; | 33 | +import java.util.Collection; |
| 34 | +import java.util.Collections; | ||
| 35 | +import java.util.List; | ||
| 36 | +import java.util.Map; | ||
| 33 | import java.util.stream.Stream; | 37 | import java.util.stream.Stream; |
| 34 | 38 | ||
| 35 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 39 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 36 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 40 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 41 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; | ||
| 42 | +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||
| 37 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 43 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 38 | 44 | ||
| 39 | @Tag(name = "管理后台 - CRM 数据权限") | 45 | @Tag(name = "管理后台 - CRM 数据权限") |
| @@ -98,18 +104,32 @@ public class CrmPermissionController { | @@ -98,18 +104,32 @@ public class CrmPermissionController { | ||
| 98 | @PreAuthorize("@ss.hasPermission('crm:permission:query')") | 104 | @PreAuthorize("@ss.hasPermission('crm:permission:query')") |
| 99 | public CommonResult<List<CrmPermissionRespVO>> getPermissionList(@RequestParam("bizType") Integer bizType, | 105 | public CommonResult<List<CrmPermissionRespVO>> getPermissionList(@RequestParam("bizType") Integer bizType, |
| 100 | @RequestParam("bizId") Long bizId) { | 106 | @RequestParam("bizId") Long bizId) { |
| 101 | - List<CrmPermissionDO> permission = permissionService.getPermissionListByBiz(bizType, bizId); | ||
| 102 | - if (CollUtil.isEmpty(permission)) { | 107 | + List<CrmPermissionDO> permissions = permissionService.getPermissionListByBiz(bizType, bizId); |
| 108 | + if (CollUtil.isEmpty(permissions)) { | ||
| 103 | return success(Collections.emptyList()); | 109 | return success(Collections.emptyList()); |
| 104 | } | 110 | } |
| 105 | 111 | ||
| 112 | + // 查询相关数据 | ||
| 113 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 114 | + convertSet(permissions, CrmPermissionDO::getUserId)); | ||
| 115 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||
| 116 | + Map<Long, PostRespDTO> postMap = postApi.getPostMap( | ||
| 117 | + convertSetByFlatMap(userMap.values(), AdminUserRespDTO::getPostIds, | ||
| 118 | + item -> item != null ? item.stream() : Stream.empty())); | ||
| 106 | // 拼接数据 | 119 | // 拼接数据 |
| 107 | - List<AdminUserRespDTO> userList = adminUserApi.getUserList(convertSet(permission, CrmPermissionDO::getUserId)); | ||
| 108 | - Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userList, AdminUserRespDTO::getDeptId)); | ||
| 109 | - Set<Long> postIds = CollectionUtils.convertSetByFlatMap(userList, AdminUserRespDTO::getPostIds, | ||
| 110 | - item -> item != null ? item.stream() : Stream.empty()); | ||
| 111 | - Map<Long, PostRespDTO> postMap = postApi.getPostMap(postIds); | ||
| 112 | - return success(CrmPermissionConvert.INSTANCE.convert(permission, userList, deptMap, postMap)); | 120 | + return success(CollectionUtils.convertList(BeanUtils.toBean(permissions, CrmPermissionRespVO.class), item -> { |
| 121 | + findAndThen(userMap, item.getUserId(), user -> { | ||
| 122 | + item.setNickname(user.getNickname()); | ||
| 123 | + findAndThen(deptMap, user.getDeptId(), deptRespDTO -> item.setDeptName(deptRespDTO.getName())); | ||
| 124 | + if (CollUtil.isEmpty(user.getPostIds())) { | ||
| 125 | + item.setPostNames(Collections.emptySet()); | ||
| 126 | + return; | ||
| 127 | + } | ||
| 128 | + List<PostRespDTO> postList = MapUtils.getList(Multimaps.forMap(postMap), user.getPostIds()); | ||
| 129 | + item.setPostNames(CollectionUtils.convertSet(postList, PostRespDTO::getName)); | ||
| 130 | + }); | ||
| 131 | + return item; | ||
| 132 | + })); | ||
| 113 | } | 133 | } |
| 114 | 134 | ||
| 115 | } | 135 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.product; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.product; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageParam; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | 8 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; |
| 9 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 8 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 10 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 9 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 10 | import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; | 12 | import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; |
| 11 | import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductRespVO; | 13 | import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductRespVO; |
| 12 | import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; | 14 | import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; |
| 13 | -import cn.iocoder.yudao.module.crm.convert.product.CrmProductConvert; | ||
| 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; | 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; |
| 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; | 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; |
| 16 | import cn.iocoder.yudao.module.crm.service.product.CrmProductCategoryService; | 17 | import cn.iocoder.yudao.module.crm.service.product.CrmProductCategoryService; |
| @@ -34,10 +35,9 @@ import java.util.Map; | @@ -34,10 +35,9 @@ import java.util.Map; | ||
| 34 | import java.util.stream.Stream; | 35 | import java.util.stream.Stream; |
| 35 | 36 | ||
| 36 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 37 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 37 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 38 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; | 38 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 39 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 39 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 40 | -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 40 | +import static java.util.Collections.singletonList; |
| 41 | 41 | ||
| 42 | @Tag(name = "管理后台 - CRM 产品") | 42 | @Tag(name = "管理后台 - CRM 产品") |
| 43 | @RestController | 43 | @RestController |
| @@ -49,6 +49,7 @@ public class CrmProductController { | @@ -49,6 +49,7 @@ public class CrmProductController { | ||
| 49 | private CrmProductService productService; | 49 | private CrmProductService productService; |
| 50 | @Resource | 50 | @Resource |
| 51 | private CrmProductCategoryService productCategoryService; | 51 | private CrmProductCategoryService productCategoryService; |
| 52 | + | ||
| 52 | @Resource | 53 | @Resource |
| 53 | private AdminUserApi adminUserApi; | 54 | private AdminUserApi adminUserApi; |
| 54 | 55 | ||
| @@ -82,21 +83,30 @@ public class CrmProductController { | @@ -82,21 +83,30 @@ public class CrmProductController { | ||
| 82 | @PreAuthorize("@ss.hasPermission('crm:product:query')") | 83 | @PreAuthorize("@ss.hasPermission('crm:product:query')") |
| 83 | public CommonResult<CrmProductRespVO> getProduct(@RequestParam("id") Long id) { | 84 | public CommonResult<CrmProductRespVO> getProduct(@RequestParam("id") Long id) { |
| 84 | CrmProductDO product = productService.getProduct(id); | 85 | CrmProductDO product = productService.getProduct(id); |
| 86 | + return success(buildProductDetail(product)); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + private CrmProductRespVO buildProductDetail(CrmProductDO product) { | ||
| 85 | if (product == null) { | 90 | if (product == null) { |
| 86 | - return success(null); | 91 | + return null; |
| 87 | } | 92 | } |
| 88 | - Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | ||
| 89 | - SetUtils.asSet(Long.valueOf(product.getCreator()), product.getOwnerUserId())); | ||
| 90 | - CrmProductCategoryDO category = productCategoryService.getProductCategory(product.getCategoryId()); | ||
| 91 | - return success(CrmProductConvert.INSTANCE.convert(product, userMap, category)); | 93 | + return buildProductDetailList(singletonList(product)).get(0); |
| 94 | + } | ||
| 95 | + | ||
| 96 | + @GetMapping("/simple-list") | ||
| 97 | + @Operation(summary = "获得产品精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") | ||
| 98 | + public CommonResult<List<CrmProductRespVO>> getProductSimpleList() { | ||
| 99 | + List<CrmProductDO> list = productService.getProductListByStatus(CommonStatusEnum.ENABLE.getStatus()); | ||
| 100 | + return success(convertList(list, product -> new CrmProductRespVO().setId(product.getId()).setName(product.getName()) | ||
| 101 | + .setUnit(product.getUnit()).setNo(product.getNo()).setPrice(product.getPrice()))); | ||
| 92 | } | 102 | } |
| 93 | 103 | ||
| 94 | @GetMapping("/page") | 104 | @GetMapping("/page") |
| 95 | @Operation(summary = "获得产品分页") | 105 | @Operation(summary = "获得产品分页") |
| 96 | @PreAuthorize("@ss.hasPermission('crm:product:query')") | 106 | @PreAuthorize("@ss.hasPermission('crm:product:query')") |
| 97 | public CommonResult<PageResult<CrmProductRespVO>> getProductPage(@Valid CrmProductPageReqVO pageVO) { | 107 | public CommonResult<PageResult<CrmProductRespVO>> getProductPage(@Valid CrmProductPageReqVO pageVO) { |
| 98 | - PageResult<CrmProductDO> pageResult = productService.getProductPage(pageVO, getLoginUserId()); | ||
| 99 | - return success(new PageResult<>(getProductDetailList(pageResult.getList()), pageResult.getTotal())); | 108 | + PageResult<CrmProductDO> pageResult = productService.getProductPage(pageVO); |
| 109 | + return success(new PageResult<>(buildProductDetailList(pageResult.getList()), pageResult.getTotal())); | ||
| 100 | } | 110 | } |
| 101 | 111 | ||
| 102 | @GetMapping("/export-excel") | 112 | @GetMapping("/export-excel") |
| @@ -106,21 +116,30 @@ public class CrmProductController { | @@ -106,21 +116,30 @@ public class CrmProductController { | ||
| 106 | public void exportProductExcel(@Valid CrmProductPageReqVO exportReqVO, | 116 | public void exportProductExcel(@Valid CrmProductPageReqVO exportReqVO, |
| 107 | HttpServletResponse response) throws IOException { | 117 | HttpServletResponse response) throws IOException { |
| 108 | exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | 118 | exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); |
| 109 | - List<CrmProductDO> list = productService.getProductPage(exportReqVO, getLoginUserId()).getList(); | 119 | + List<CrmProductDO> list = productService.getProductPage(exportReqVO).getList(); |
| 110 | // 导出 Excel | 120 | // 导出 Excel |
| 111 | ExcelUtils.write(response, "产品.xls", "数据", CrmProductRespVO.class, | 121 | ExcelUtils.write(response, "产品.xls", "数据", CrmProductRespVO.class, |
| 112 | - getProductDetailList(list)); | 122 | + buildProductDetailList(list)); |
| 113 | } | 123 | } |
| 114 | 124 | ||
| 115 | - private List<CrmProductRespVO> getProductDetailList(List<CrmProductDO> list) { | 125 | + private List<CrmProductRespVO> buildProductDetailList(List<CrmProductDO> list) { |
| 116 | if (CollUtil.isEmpty(list)) { | 126 | if (CollUtil.isEmpty(list)) { |
| 117 | return Collections.emptyList(); | 127 | return Collections.emptyList(); |
| 118 | } | 128 | } |
| 129 | + // 1.1 获得用户信息 | ||
| 119 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | 130 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| 120 | convertSetByFlatMap(list, user -> Stream.of(Long.valueOf(user.getCreator()), user.getOwnerUserId()))); | 131 | convertSetByFlatMap(list, user -> Stream.of(Long.valueOf(user.getCreator()), user.getOwnerUserId()))); |
| 121 | - List<CrmProductCategoryDO> productCategoryList = productCategoryService.getProductCategoryList( | 132 | + // 1.2 获得分类信息 |
| 133 | + Map<Long, CrmProductCategoryDO> categoryMap = productCategoryService.getProductCategoryMap( | ||
| 122 | convertSet(list, CrmProductDO::getCategoryId)); | 134 | convertSet(list, CrmProductDO::getCategoryId)); |
| 123 | - return CrmProductConvert.INSTANCE.convertList(list, userMap, productCategoryList); | 135 | + // 2. 拼接数据 |
| 136 | + return BeanUtils.toBean(list, CrmProductRespVO.class, productVO -> { | ||
| 137 | + // 2.1 设置用户信息 | ||
| 138 | + MapUtils.findAndThen(userMap, productVO.getOwnerUserId(), user -> productVO.setOwnerUserName(user.getNickname())); | ||
| 139 | + MapUtils.findAndThen(userMap, Long.valueOf(productVO.getCreator()), user -> productVO.setCreatorName(user.getNickname())); | ||
| 140 | + // 2.2 设置分类名称 | ||
| 141 | + MapUtils.findAndThen(categoryMap, productVO.getCategoryId(), category -> productVO.setCategoryName(category.getName())); | ||
| 142 | + }); | ||
| 124 | } | 143 | } |
| 125 | 144 | ||
| 126 | } | 145 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java
| @@ -8,6 +8,7 @@ import com.alibaba.excel.annotation.ExcelProperty; | @@ -8,6 +8,7 @@ import com.alibaba.excel.annotation.ExcelProperty; | ||
| 8 | import io.swagger.v3.oas.annotations.media.Schema; | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | import lombok.Data; | 9 | import lombok.Data; |
| 10 | 10 | ||
| 11 | +import java.math.BigDecimal; | ||
| 11 | import java.time.LocalDateTime; | 12 | import java.time.LocalDateTime; |
| 12 | 13 | ||
| 13 | @Schema(description = "管理后台 - CRM 产品 Response VO") | 14 | @Schema(description = "管理后台 - CRM 产品 Response VO") |
| @@ -34,7 +35,7 @@ public class CrmProductRespVO { | @@ -34,7 +35,7 @@ public class CrmProductRespVO { | ||
| 34 | 35 | ||
| 35 | @Schema(description = "价格, 单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") | 36 | @Schema(description = "价格, 单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") |
| 36 | @ExcelProperty("价格,单位:分") | 37 | @ExcelProperty("价格,单位:分") |
| 37 | - private Long price; | 38 | + private BigDecimal price; |
| 38 | 39 | ||
| 39 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") | 40 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") |
| 40 | @ExcelProperty(value = "单位", converter = DictConvert.class) | 41 | @ExcelProperty(value = "单位", converter = DictConvert.class) |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java
| @@ -7,6 +7,8 @@ import io.swagger.v3.oas.annotations.media.Schema; | @@ -7,6 +7,8 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 7 | import jakarta.validation.constraints.NotNull; | 7 | import jakarta.validation.constraints.NotNull; |
| 8 | import lombok.Data; | 8 | import lombok.Data; |
| 9 | 9 | ||
| 10 | +import java.math.BigDecimal; | ||
| 11 | + | ||
| 10 | @Schema(description = "管理后台 - CRM 产品创建/修改 Request VO") | 12 | @Schema(description = "管理后台 - CRM 产品创建/修改 Request VO") |
| 11 | @Data | 13 | @Data |
| 12 | public class CrmProductSaveReqVO { | 14 | public class CrmProductSaveReqVO { |
| @@ -28,10 +30,10 @@ public class CrmProductSaveReqVO { | @@ -28,10 +30,10 @@ public class CrmProductSaveReqVO { | ||
| 28 | @DiffLogField(name = "单位", function = CrmProductUnitParseFunction.NAME) | 30 | @DiffLogField(name = "单位", function = CrmProductUnitParseFunction.NAME) |
| 29 | private Integer unit; | 31 | private Integer unit; |
| 30 | 32 | ||
| 31 | - @Schema(description = "价格, 单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") | 33 | + @Schema(description = "价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") |
| 32 | @NotNull(message = "价格不能为空") | 34 | @NotNull(message = "价格不能为空") |
| 33 | @DiffLogField(name = "价格") | 35 | @DiffLogField(name = "价格") |
| 34 | - private Long price; | 36 | + private BigDecimal price; |
| 35 | 37 | ||
| 36 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") | 38 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") |
| 37 | @NotNull(message = "状态不能为空") | 39 | @NotNull(message = "状态不能为空") |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java
| @@ -4,20 +4,23 @@ import cn.hutool.core.collection.CollUtil; | @@ -4,20 +4,23 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.lang.Assert; | 4 | import cn.hutool.core.lang.Assert; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 9 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 8 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 10 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 9 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 10 | -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableCreateReqVO; | 12 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; |
| 11 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; | 13 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; |
| 12 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; | 14 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; |
| 13 | -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableUpdateReqVO; | ||
| 14 | -import cn.iocoder.yudao.module.crm.convert.receivable.CrmReceivableConvert; | 15 | +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; |
| 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; | 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; | 18 | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; |
| 18 | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; | 19 | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; |
| 19 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | 20 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 20 | import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; | 21 | import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; |
| 22 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 23 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 21 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | 24 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 22 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 25 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 23 | import io.swagger.v3.oas.annotations.Operation; | 26 | import io.swagger.v3.oas.annotations.Operation; |
| @@ -31,14 +34,15 @@ import org.springframework.validation.annotation.Validated; | @@ -31,14 +34,15 @@ import org.springframework.validation.annotation.Validated; | ||
| 31 | import org.springframework.web.bind.annotation.*; | 34 | import org.springframework.web.bind.annotation.*; |
| 32 | 35 | ||
| 33 | import java.io.IOException; | 36 | import java.io.IOException; |
| 37 | +import java.util.Collections; | ||
| 34 | import java.util.List; | 38 | import java.util.List; |
| 35 | import java.util.Map; | 39 | import java.util.Map; |
| 36 | import java.util.stream.Stream; | 40 | import java.util.stream.Stream; |
| 37 | 41 | ||
| 38 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 42 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 39 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | 43 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 40 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; | ||
| 41 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 44 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 45 | +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||
| 42 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 46 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 43 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 47 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 44 | 48 | ||
| @@ -57,18 +61,20 @@ public class CrmReceivableController { | @@ -57,18 +61,20 @@ public class CrmReceivableController { | ||
| 57 | 61 | ||
| 58 | @Resource | 62 | @Resource |
| 59 | private AdminUserApi adminUserApi; | 63 | private AdminUserApi adminUserApi; |
| 64 | + @Resource | ||
| 65 | + private DeptApi deptApi; | ||
| 60 | 66 | ||
| 61 | @PostMapping("/create") | 67 | @PostMapping("/create") |
| 62 | @Operation(summary = "创建回款") | 68 | @Operation(summary = "创建回款") |
| 63 | @PreAuthorize("@ss.hasPermission('crm:receivable:create')") | 69 | @PreAuthorize("@ss.hasPermission('crm:receivable:create')") |
| 64 | - public CommonResult<Long> createReceivable(@Valid @RequestBody CrmReceivableCreateReqVO createReqVO) { | ||
| 65 | - return success(receivableService.createReceivable(createReqVO, getLoginUserId())); | 70 | + public CommonResult<Long> createReceivable(@Valid @RequestBody CrmReceivableSaveReqVO createReqVO) { |
| 71 | + return success(receivableService.createReceivable(createReqVO)); | ||
| 66 | } | 72 | } |
| 67 | 73 | ||
| 68 | @PutMapping("/update") | 74 | @PutMapping("/update") |
| 69 | @Operation(summary = "更新回款") | 75 | @Operation(summary = "更新回款") |
| 70 | @PreAuthorize("@ss.hasPermission('crm:receivable:update')") | 76 | @PreAuthorize("@ss.hasPermission('crm:receivable:update')") |
| 71 | - public CommonResult<Boolean> updateReceivable(@Valid @RequestBody CrmReceivableUpdateReqVO updateReqVO) { | 77 | + public CommonResult<Boolean> updateReceivable(@Valid @RequestBody CrmReceivableSaveReqVO updateReqVO) { |
| 72 | receivableService.updateReceivable(updateReqVO); | 78 | receivableService.updateReceivable(updateReqVO); |
| 73 | return success(true); | 79 | return success(true); |
| 74 | } | 80 | } |
| @@ -88,7 +94,14 @@ public class CrmReceivableController { | @@ -88,7 +94,14 @@ public class CrmReceivableController { | ||
| 88 | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") | 94 | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") |
| 89 | public CommonResult<CrmReceivableRespVO> getReceivable(@RequestParam("id") Long id) { | 95 | public CommonResult<CrmReceivableRespVO> getReceivable(@RequestParam("id") Long id) { |
| 90 | CrmReceivableDO receivable = receivableService.getReceivable(id); | 96 | CrmReceivableDO receivable = receivableService.getReceivable(id); |
| 91 | - return success(CrmReceivableConvert.INSTANCE.convert(receivable)); | 97 | + return success(buildReceivableDetail(receivable)); |
| 98 | + } | ||
| 99 | + | ||
| 100 | + private CrmReceivableRespVO buildReceivableDetail(CrmReceivableDO receivable) { | ||
| 101 | + if (receivable == null) { | ||
| 102 | + return null; | ||
| 103 | + } | ||
| 104 | + return buildReceivableDetailList(Collections.singletonList(receivable)).get(0); | ||
| 92 | } | 105 | } |
| 93 | 106 | ||
| 94 | @GetMapping("/page") | 107 | @GetMapping("/page") |
| @@ -96,7 +109,7 @@ public class CrmReceivableController { | @@ -96,7 +109,7 @@ public class CrmReceivableController { | ||
| 96 | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") | 109 | @PreAuthorize("@ss.hasPermission('crm:receivable:query')") |
| 97 | public CommonResult<PageResult<CrmReceivableRespVO>> getReceivablePage(@Valid CrmReceivablePageReqVO pageReqVO) { | 110 | public CommonResult<PageResult<CrmReceivableRespVO>> getReceivablePage(@Valid CrmReceivablePageReqVO pageReqVO) { |
| 98 | PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePage(pageReqVO, getLoginUserId()); | 111 | PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePage(pageReqVO, getLoginUserId()); |
| 99 | - return success(buildReceivableDetailPage(pageResult)); | 112 | + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); |
| 100 | } | 113 | } |
| 101 | 114 | ||
| 102 | @GetMapping("/page-by-customer") | 115 | @GetMapping("/page-by-customer") |
| @@ -104,10 +117,9 @@ public class CrmReceivableController { | @@ -104,10 +117,9 @@ public class CrmReceivableController { | ||
| 104 | public CommonResult<PageResult<CrmReceivableRespVO>> getReceivablePageByCustomer(@Valid CrmReceivablePageReqVO pageReqVO) { | 117 | public CommonResult<PageResult<CrmReceivableRespVO>> getReceivablePageByCustomer(@Valid CrmReceivablePageReqVO pageReqVO) { |
| 105 | Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); | 118 | Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); |
| 106 | PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePageByCustomerId(pageReqVO); | 119 | PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePageByCustomerId(pageReqVO); |
| 107 | - return success(buildReceivableDetailPage(pageResult)); | 120 | + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); |
| 108 | } | 121 | } |
| 109 | 122 | ||
| 110 | - // TODO 芋艿:后面在优化导出 | ||
| 111 | @GetMapping("/export-excel") | 123 | @GetMapping("/export-excel") |
| 112 | @Operation(summary = "导出回款 Excel") | 124 | @Operation(summary = "导出回款 Excel") |
| 113 | @PreAuthorize("@ss.hasPermission('crm:receivable:export')") | 125 | @PreAuthorize("@ss.hasPermission('crm:receivable:export')") |
| @@ -115,33 +127,56 @@ public class CrmReceivableController { | @@ -115,33 +127,56 @@ public class CrmReceivableController { | ||
| 115 | public void exportReceivableExcel(@Valid CrmReceivablePageReqVO exportReqVO, | 127 | public void exportReceivableExcel(@Valid CrmReceivablePageReqVO exportReqVO, |
| 116 | HttpServletResponse response) throws IOException { | 128 | HttpServletResponse response) throws IOException { |
| 117 | exportReqVO.setPageSize(PAGE_SIZE_NONE); | 129 | exportReqVO.setPageSize(PAGE_SIZE_NONE); |
| 118 | - PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePage(exportReqVO, getLoginUserId()); | 130 | + List<CrmReceivableDO> list = receivableService.getReceivablePage(exportReqVO, getLoginUserId()).getList(); |
| 119 | // 导出 Excel | 131 | // 导出 Excel |
| 120 | ExcelUtils.write(response, "回款.xls", "数据", CrmReceivableRespVO.class, | 132 | ExcelUtils.write(response, "回款.xls", "数据", CrmReceivableRespVO.class, |
| 121 | - buildReceivableDetailPage(pageResult).getList()); | 133 | + buildReceivableDetailList(list)); |
| 122 | } | 134 | } |
| 123 | 135 | ||
| 124 | - /** | ||
| 125 | - * 构建详细的回款分页结果 | ||
| 126 | - * | ||
| 127 | - * @param pageResult 简单的回款分页结果 | ||
| 128 | - * @return 详细的回款分页结果 | ||
| 129 | - */ | ||
| 130 | - private PageResult<CrmReceivableRespVO> buildReceivableDetailPage(PageResult<CrmReceivableDO> pageResult) { | ||
| 131 | - List<CrmReceivableDO> receivableList = pageResult.getList(); | 136 | + private List<CrmReceivableRespVO> buildReceivableDetailList(List<CrmReceivableDO> receivableList) { |
| 132 | if (CollUtil.isEmpty(receivableList)) { | 137 | if (CollUtil.isEmpty(receivableList)) { |
| 133 | - return PageResult.empty(pageResult.getTotal()); | 138 | + return Collections.emptyList(); |
| 134 | } | 139 | } |
| 135 | - // 1. 获取客户列表 | ||
| 136 | - List<CrmCustomerDO> customerList = customerService.getCustomerList( | 140 | + // 1.1 获取客户列表 |
| 141 | + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap( | ||
| 137 | convertSet(receivableList, CrmReceivableDO::getCustomerId)); | 142 | convertSet(receivableList, CrmReceivableDO::getCustomerId)); |
| 138 | - // 2. 获取创建人、负责人列表 | 143 | + // 1.2 获取创建人、负责人列表 |
| 139 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(receivableList, | 144 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(receivableList, |
| 140 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | 145 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); |
| 141 | - // 3. 获得合同列表 | ||
| 142 | - List<CrmContractDO> contractList = contractService.getContractList( | 146 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); |
| 147 | + // 1.3 获得合同列表 | ||
| 148 | + Map<Long, CrmContractDO> contractMap = contractService.getContractMap( | ||
| 143 | convertSet(receivableList, CrmReceivableDO::getContractId)); | 149 | convertSet(receivableList, CrmReceivableDO::getContractId)); |
| 144 | - return CrmReceivableConvert.INSTANCE.convertPage(pageResult, userMap, customerList, contractList); | 150 | + // 2. 拼接结果 |
| 151 | + return BeanUtils.toBean(receivableList, CrmReceivableRespVO.class, (receivableVO) -> { | ||
| 152 | + // 2.1 拼接客户名称 | ||
| 153 | + findAndThen(customerMap, receivableVO.getCustomerId(), customer -> receivableVO.setCustomerName(customer.getName())); | ||
| 154 | + // 2.2 拼接负责人、创建人名称 | ||
| 155 | + MapUtils.findAndThen(userMap, NumberUtils.parseLong(receivableVO.getCreator()), | ||
| 156 | + user -> receivableVO.setCreatorName(user.getNickname())); | ||
| 157 | + MapUtils.findAndThen(userMap, receivableVO.getOwnerUserId(), user -> { | ||
| 158 | + receivableVO.setOwnerUserName(user.getNickname()); | ||
| 159 | + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> receivableVO.setOwnerUserDeptName(dept.getName())); | ||
| 160 | + }); | ||
| 161 | + // 2.3 拼接合同信息 | ||
| 162 | + findAndThen(contractMap, receivableVO.getContractId(), contract -> | ||
| 163 | + receivableVO.setContract(BeanUtils.toBean(contract, CrmContractRespVO.class))); | ||
| 164 | + }); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + @PutMapping("/submit") | ||
| 168 | + @Operation(summary = "提交回款审批") | ||
| 169 | + @PreAuthorize("@ss.hasPermission('crm:receivable:update')") | ||
| 170 | + public CommonResult<Boolean> submitContract(@RequestParam("id") Long id) { | ||
| 171 | + receivableService.submitReceivable(id, getLoginUserId()); | ||
| 172 | + return success(true); | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + @GetMapping("/audit-count") | ||
| 176 | + @Operation(summary = "获得待审核回款数量") | ||
| 177 | + @PreAuthorize("@ss.hasPermission('crm:receivable:query')") | ||
| 178 | + public CommonResult<Long> getAuditReceivableCount() { | ||
| 179 | + return success(receivableService.getAuditReceivableCount(getLoginUserId())); | ||
| 145 | } | 180 | } |
| 146 | 181 | ||
| 147 | } | 182 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java
| @@ -5,13 +5,13 @@ import cn.hutool.core.lang.Assert; | @@ -5,13 +5,13 @@ import cn.hutool.core.lang.Assert; | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 8 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 8 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | 9 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 9 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | 10 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 10 | -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanCreateReqVO; | ||
| 11 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; | 11 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; |
| 12 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanRespVO; | 12 | import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanRespVO; |
| 13 | -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanUpdateReqVO; | ||
| 14 | -import cn.iocoder.yudao.module.crm.convert.receivable.CrmReceivablePlanConvert; | 13 | +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanSaveReqVO; |
| 14 | +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; | ||
| 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; | 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 16 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; | 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; |
| @@ -24,24 +24,25 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | @@ -24,24 +24,25 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 24 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 24 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 25 | import io.swagger.v3.oas.annotations.Operation; | 25 | import io.swagger.v3.oas.annotations.Operation; |
| 26 | import io.swagger.v3.oas.annotations.Parameter; | 26 | import io.swagger.v3.oas.annotations.Parameter; |
| 27 | +import io.swagger.v3.oas.annotations.Parameters; | ||
| 27 | import io.swagger.v3.oas.annotations.tags.Tag; | 28 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 28 | import jakarta.annotation.Resource; | 29 | import jakarta.annotation.Resource; |
| 29 | import jakarta.servlet.http.HttpServletResponse; | 30 | import jakarta.servlet.http.HttpServletResponse; |
| 30 | import jakarta.validation.Valid; | 31 | import jakarta.validation.Valid; |
| 31 | -import org.springframework.context.annotation.Lazy; | ||
| 32 | import org.springframework.security.access.prepost.PreAuthorize; | 32 | import org.springframework.security.access.prepost.PreAuthorize; |
| 33 | import org.springframework.validation.annotation.Validated; | 33 | import org.springframework.validation.annotation.Validated; |
| 34 | import org.springframework.web.bind.annotation.*; | 34 | import org.springframework.web.bind.annotation.*; |
| 35 | 35 | ||
| 36 | import java.io.IOException; | 36 | import java.io.IOException; |
| 37 | +import java.util.Collections; | ||
| 37 | import java.util.List; | 38 | import java.util.List; |
| 38 | import java.util.Map; | 39 | import java.util.Map; |
| 39 | import java.util.stream.Stream; | 40 | import java.util.stream.Stream; |
| 40 | 41 | ||
| 41 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 42 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 42 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | 43 | import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; |
| 43 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; | ||
| 44 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 44 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 45 | +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||
| 45 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | 46 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 46 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 47 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 47 | 48 | ||
| @@ -56,7 +57,6 @@ public class CrmReceivablePlanController { | @@ -56,7 +57,6 @@ public class CrmReceivablePlanController { | ||
| 56 | @Resource | 57 | @Resource |
| 57 | private CrmReceivableService receivableService; | 58 | private CrmReceivableService receivableService; |
| 58 | @Resource | 59 | @Resource |
| 59 | - @Lazy | ||
| 60 | private CrmContractService contractService; | 60 | private CrmContractService contractService; |
| 61 | @Resource | 61 | @Resource |
| 62 | private CrmCustomerService customerService; | 62 | private CrmCustomerService customerService; |
| @@ -67,14 +67,14 @@ public class CrmReceivablePlanController { | @@ -67,14 +67,14 @@ public class CrmReceivablePlanController { | ||
| 67 | @PostMapping("/create") | 67 | @PostMapping("/create") |
| 68 | @Operation(summary = "创建回款计划") | 68 | @Operation(summary = "创建回款计划") |
| 69 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:create')") | 69 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:create')") |
| 70 | - public CommonResult<Long> createReceivablePlan(@Valid @RequestBody CrmReceivablePlanCreateReqVO createReqVO) { | ||
| 71 | - return success(receivablePlanService.createReceivablePlan(createReqVO, getLoginUserId())); | 70 | + public CommonResult<Long> createReceivablePlan(@Valid @RequestBody CrmReceivablePlanSaveReqVO createReqVO) { |
| 71 | + return success(receivablePlanService.createReceivablePlan(createReqVO)); | ||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | @PutMapping("/update") | 74 | @PutMapping("/update") |
| 75 | @Operation(summary = "更新回款计划") | 75 | @Operation(summary = "更新回款计划") |
| 76 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:update')") | 76 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:update')") |
| 77 | - public CommonResult<Boolean> updateReceivablePlan(@Valid @RequestBody CrmReceivablePlanUpdateReqVO updateReqVO) { | 77 | + public CommonResult<Boolean> updateReceivablePlan(@Valid @RequestBody CrmReceivablePlanSaveReqVO updateReqVO) { |
| 78 | receivablePlanService.updateReceivablePlan(updateReqVO); | 78 | receivablePlanService.updateReceivablePlan(updateReqVO); |
| 79 | return success(true); | 79 | return success(true); |
| 80 | } | 80 | } |
| @@ -94,7 +94,14 @@ public class CrmReceivablePlanController { | @@ -94,7 +94,14 @@ public class CrmReceivablePlanController { | ||
| 94 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") | 94 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") |
| 95 | public CommonResult<CrmReceivablePlanRespVO> getReceivablePlan(@RequestParam("id") Long id) { | 95 | public CommonResult<CrmReceivablePlanRespVO> getReceivablePlan(@RequestParam("id") Long id) { |
| 96 | CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(id); | 96 | CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(id); |
| 97 | - return success(CrmReceivablePlanConvert.INSTANCE.convert(receivablePlan)); | 97 | + return success(buildReceivablePlanDetail(receivablePlan)); |
| 98 | + } | ||
| 99 | + | ||
| 100 | + private CrmReceivablePlanRespVO buildReceivablePlanDetail(CrmReceivablePlanDO receivablePlan) { | ||
| 101 | + if (receivablePlan == null) { | ||
| 102 | + return null; | ||
| 103 | + } | ||
| 104 | + return buildReceivableDetailList(Collections.singletonList(receivablePlan)).get(0); | ||
| 98 | } | 105 | } |
| 99 | 106 | ||
| 100 | @GetMapping("/page") | 107 | @GetMapping("/page") |
| @@ -102,7 +109,7 @@ public class CrmReceivablePlanController { | @@ -102,7 +109,7 @@ public class CrmReceivablePlanController { | ||
| 102 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") | 109 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") |
| 103 | public CommonResult<PageResult<CrmReceivablePlanRespVO>> getReceivablePlanPage(@Valid CrmReceivablePlanPageReqVO pageReqVO) { | 110 | public CommonResult<PageResult<CrmReceivablePlanRespVO>> getReceivablePlanPage(@Valid CrmReceivablePlanPageReqVO pageReqVO) { |
| 104 | PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPage(pageReqVO, getLoginUserId()); | 111 | PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPage(pageReqVO, getLoginUserId()); |
| 105 | - return success(convertDetailReceivablePlanPage(pageResult)); | 112 | + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); |
| 106 | } | 113 | } |
| 107 | 114 | ||
| 108 | @GetMapping("/page-by-customer") | 115 | @GetMapping("/page-by-customer") |
| @@ -110,10 +117,9 @@ public class CrmReceivablePlanController { | @@ -110,10 +117,9 @@ public class CrmReceivablePlanController { | ||
| 110 | public CommonResult<PageResult<CrmReceivablePlanRespVO>> getReceivablePlanPageByCustomer(@Valid CrmReceivablePlanPageReqVO pageReqVO) { | 117 | public CommonResult<PageResult<CrmReceivablePlanRespVO>> getReceivablePlanPageByCustomer(@Valid CrmReceivablePlanPageReqVO pageReqVO) { |
| 111 | Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); | 118 | Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); |
| 112 | PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO); | 119 | PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO); |
| 113 | - return success(convertDetailReceivablePlanPage(pageResult)); | 120 | + return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); |
| 114 | } | 121 | } |
| 115 | 122 | ||
| 116 | - // TODO 芋艿:后面在优化导出 | ||
| 117 | @GetMapping("/export-excel") | 123 | @GetMapping("/export-excel") |
| 118 | @Operation(summary = "导出回款计划 Excel") | 124 | @Operation(summary = "导出回款计划 Excel") |
| 119 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:export')") | 125 | @PreAuthorize("@ss.hasPermission('crm:receivable-plan:export')") |
| @@ -121,36 +127,64 @@ public class CrmReceivablePlanController { | @@ -121,36 +127,64 @@ public class CrmReceivablePlanController { | ||
| 121 | public void exportReceivablePlanExcel(@Valid CrmReceivablePlanPageReqVO exportReqVO, | 127 | public void exportReceivablePlanExcel(@Valid CrmReceivablePlanPageReqVO exportReqVO, |
| 122 | HttpServletResponse response) throws IOException { | 128 | HttpServletResponse response) throws IOException { |
| 123 | exportReqVO.setPageSize(PAGE_SIZE_NONE); | 129 | exportReqVO.setPageSize(PAGE_SIZE_NONE); |
| 124 | - PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPage(exportReqVO, getLoginUserId()); | 130 | + List<CrmReceivablePlanDO> list = receivablePlanService.getReceivablePlanPage(exportReqVO, getLoginUserId()).getList(); |
| 125 | // 导出 Excel | 131 | // 导出 Excel |
| 126 | ExcelUtils.write(response, "回款计划.xls", "数据", CrmReceivablePlanRespVO.class, | 132 | ExcelUtils.write(response, "回款计划.xls", "数据", CrmReceivablePlanRespVO.class, |
| 127 | - convertDetailReceivablePlanPage(pageResult).getList()); | 133 | + buildReceivableDetailList(list)); |
| 128 | } | 134 | } |
| 129 | 135 | ||
| 130 | - /** | ||
| 131 | - * 构建详细的回款计划分页结果 | ||
| 132 | - * | ||
| 133 | - * @param pageResult 简单的回款计划分页结果 | ||
| 134 | - * @return 详细的回款计划分页结果 | ||
| 135 | - */ | ||
| 136 | - private PageResult<CrmReceivablePlanRespVO> convertDetailReceivablePlanPage(PageResult<CrmReceivablePlanDO> pageResult) { | ||
| 137 | - List<CrmReceivablePlanDO> receivablePlanList = pageResult.getList(); | 136 | + private List<CrmReceivablePlanRespVO> buildReceivableDetailList(List<CrmReceivablePlanDO> receivablePlanList) { |
| 138 | if (CollUtil.isEmpty(receivablePlanList)) { | 137 | if (CollUtil.isEmpty(receivablePlanList)) { |
| 139 | - return PageResult.empty(pageResult.getTotal()); | 138 | + return Collections.emptyList(); |
| 140 | } | 139 | } |
| 141 | - // 1. 获取客户列表 | ||
| 142 | - List<CrmCustomerDO> customerList = customerService.getCustomerList( | 140 | + // 1.1 获取客户 Map |
| 141 | + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap( | ||
| 143 | convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId)); | 142 | convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId)); |
| 144 | - // 2. 获取创建人、负责人列表 | 143 | + // 1.2 获取创建人、负责人列表 |
| 145 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(receivablePlanList, | 144 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(receivablePlanList, |
| 146 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); | 145 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); |
| 147 | - // 3. 获得合同列表 | ||
| 148 | - List<CrmContractDO> contractList = contractService.getContractList( | 146 | + // 1.3 获得合同 Map |
| 147 | + Map<Long, CrmContractDO> contractMap = contractService.getContractMap( | ||
| 149 | convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId)); | 148 | convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId)); |
| 150 | - // 4. 获得还款列表 | ||
| 151 | - List<CrmReceivableDO> receivableList = receivableService.getReceivableList( | 149 | + // 1.4 获得回款 Map |
| 150 | + Map<Long, CrmReceivableDO> receivableMap = receivableService.getReceivableMap( | ||
| 152 | convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId)); | 151 | convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId)); |
| 153 | - return CrmReceivablePlanConvert.INSTANCE.convertPage(pageResult, userMap, customerList, contractList, receivableList); | 152 | + // 2. 拼接数据 |
| 153 | + return BeanUtils.toBean(receivablePlanList, CrmReceivablePlanRespVO.class, (receivablePlanVO) -> { | ||
| 154 | + // 2.1 拼接客户信息 | ||
| 155 | + findAndThen(customerMap, receivablePlanVO.getCustomerId(), customer -> receivablePlanVO.setCustomerName(customer.getName())); | ||
| 156 | + // 2.2 拼接用户信息 | ||
| 157 | + findAndThen(userMap, receivablePlanVO.getOwnerUserId(), user -> receivablePlanVO.setOwnerUserName(user.getNickname())); | ||
| 158 | + findAndThen(userMap, Long.parseLong(receivablePlanVO.getCreator()), user -> receivablePlanVO.setCreatorName(user.getNickname())); | ||
| 159 | + // 2.3 拼接合同信息 | ||
| 160 | + findAndThen(contractMap, receivablePlanVO.getContractId(), contract -> receivablePlanVO.setContractNo(contract.getNo())); | ||
| 161 | + // 2.4 拼接回款信息 | ||
| 162 | + receivablePlanVO.setReceivable(BeanUtils.toBean(receivableMap.get(receivablePlanVO.getReceivableId()), CrmReceivableRespVO.class)); | ||
| 163 | + }); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + @GetMapping("/simple-list") | ||
| 167 | + @Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项") | ||
| 168 | + @Parameters({ | ||
| 169 | + @Parameter(name = "customerId", description = "客户编号", required = true), | ||
| 170 | + @Parameter(name = "contractId", description = "合同编号", required = true) | ||
| 171 | + }) | ||
| 172 | + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") | ||
| 173 | + public CommonResult<List<CrmReceivablePlanRespVO>> getReceivablePlanSimpleList(@RequestParam("customerId") Long customerId, | ||
| 174 | + @RequestParam("contractId") Long contractId) { | ||
| 175 | + CrmReceivablePlanPageReqVO pageReqVO = new CrmReceivablePlanPageReqVO().setCustomerId(customerId).setContractId(contractId); | ||
| 176 | + pageReqVO.setPageNo(PAGE_SIZE_NONE); | ||
| 177 | + PageResult<CrmReceivablePlanDO> pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO); | ||
| 178 | + return success(convertList(pageResult.getList(), receivablePlan -> new CrmReceivablePlanRespVO() // 只返回 id、period 等信息 | ||
| 179 | + .setId(receivablePlan.getId()).setPeriod(receivablePlan.getPeriod()).setReceivableId(receivablePlan.getReceivableId()) | ||
| 180 | + .setPrice(receivablePlan.getPrice()).setReturnType(receivablePlan.getReturnType()))); | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + @GetMapping("/remind-count") | ||
| 184 | + @Operation(summary = "获得待回款提醒数量") | ||
| 185 | + @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") | ||
| 186 | + public CommonResult<Long> getReceivablePlanRemindCount() { | ||
| 187 | + return success(receivablePlanService.getReceivablePlanRemindCount(getLoginUserId())); | ||
| 154 | } | 188 | } |
| 155 | 189 | ||
| 156 | } | 190 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanBaseVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.Data; | ||
| 5 | -import org.springframework.format.annotation.DateTimeFormat; | ||
| 6 | - | ||
| 7 | -import java.time.LocalDateTime; | ||
| 8 | - | ||
| 9 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 10 | - | ||
| 11 | -/** | ||
| 12 | - * 回款计划 Base VO,提供给添加、修改、详细的子 VO 使用 | ||
| 13 | - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | ||
| 14 | - */ | ||
| 15 | -@Data | ||
| 16 | -public class CrmReceivablePlanBaseVO { | ||
| 17 | - | ||
| 18 | - @Schema(description = "期数", example = "1") | ||
| 19 | - private Integer period; | ||
| 20 | - | ||
| 21 | - @Schema(description = "回款计划编号", example = "19852") | ||
| 22 | - private Long receivableId; | ||
| 23 | - | ||
| 24 | - @Schema(description = "计划回款金额", example = "29675") | ||
| 25 | - private Integer price; | ||
| 26 | - | ||
| 27 | - @Schema(description = "计划回款日期") | ||
| 28 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 29 | - private LocalDateTime returnTime; | ||
| 30 | - | ||
| 31 | - @Schema(description = "提前几天提醒") | ||
| 32 | - private Integer remindDays; | ||
| 33 | - | ||
| 34 | - @Schema(description = "提醒日期") | ||
| 35 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 36 | - private LocalDateTime remindTime; | ||
| 37 | - | ||
| 38 | - @Schema(description = "客户名称", example = "18026") | ||
| 39 | - private Long customerId; | ||
| 40 | - | ||
| 41 | - @Schema(description = "合同编号", example = "3473") | ||
| 42 | - private Long contractId; | ||
| 43 | - | ||
| 44 | - // TODO @liuhongfeng:负责人编号 | ||
| 45 | - @Schema(description = "负责人编号", example = "17828") | ||
| 46 | - private Long ownerUserId; | ||
| 47 | - | ||
| 48 | - @Schema(description = "显示顺序") | ||
| 49 | - private Integer sort; | ||
| 50 | - | ||
| 51 | - @Schema(description = "备注", example = "备注") | ||
| 52 | - private String remark; | ||
| 53 | - | ||
| 54 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanCreateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; | ||
| 2 | - | ||
| 3 | -import lombok.*; | ||
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | - | ||
| 6 | -@Schema(description = "管理后台 - CRM 回款计划创建 Request VO") | ||
| 7 | -@Data | ||
| 8 | -@EqualsAndHashCode(callSuper = true) | ||
| 9 | -@ToString(callSuper = true) | ||
| 10 | -public class CrmReceivablePlanCreateReqVO extends CrmReceivablePlanBaseVO { | ||
| 11 | - | ||
| 12 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java
| @@ -30,8 +30,10 @@ public class CrmReceivablePlanPageReqVO extends PageParam { | @@ -30,8 +30,10 @@ public class CrmReceivablePlanPageReqVO extends PageParam { | ||
| 30 | @Schema(description = "客户编号", example = "18026") | 30 | @Schema(description = "客户编号", example = "18026") |
| 31 | private Long customerId; | 31 | private Long customerId; |
| 32 | 32 | ||
| 33 | - // TODO @芋艿:这个搜的应该是合同编号 no | ||
| 34 | - @Schema(description = "合同名称", example = "3473") | 33 | + @Schema(description = "合同编号", example = "H3473") |
| 34 | + private String contractNo; | ||
| 35 | + | ||
| 36 | + @Schema(description = "合同编号", example = "3473") | ||
| 35 | private Long contractId; | 37 | private Long contractId; |
| 36 | 38 | ||
| 37 | @Schema(description = "场景类型", example = "1") | 39 | @Schema(description = "场景类型", example = "1") |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; | ||
| 4 | +import com.alibaba.excel.annotation.ExcelProperty; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | 6 | +import lombok.Data; |
| 7 | + | ||
| 8 | +import java.math.BigDecimal; | ||
| 5 | import java.time.LocalDateTime; | 9 | import java.time.LocalDateTime; |
| 6 | 10 | ||
| 11 | +// TODO @puhui999:缺导出 | ||
| 7 | @Schema(description = "管理后台 - CRM 回款计划 Response VO") | 12 | @Schema(description = "管理后台 - CRM 回款计划 Response VO") |
| 8 | @Data | 13 | @Data |
| 9 | -@EqualsAndHashCode(callSuper = true) | ||
| 10 | -@ToString(callSuper = true) | ||
| 11 | -public class CrmReceivablePlanRespVO extends CrmReceivablePlanBaseVO { | 14 | +public class CrmReceivablePlanRespVO { |
| 12 | 15 | ||
| 13 | - @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25153") | 16 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 14 | private Long id; | 17 | private Long id; |
| 15 | 18 | ||
| 16 | - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 17 | - private LocalDateTime createTime; | 19 | + @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 20 | + private Integer period; | ||
| 18 | 21 | ||
| 22 | + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 23 | + private Long customerId; | ||
| 19 | @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") | 24 | @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") |
| 20 | private String customerName; | 25 | private String customerName; |
| 21 | 26 | ||
| 27 | + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 28 | + private Long contractId; | ||
| 22 | @Schema(description = "合同编号", example = "Q110") | 29 | @Schema(description = "合同编号", example = "Q110") |
| 23 | private String contractNo; | 30 | private String contractNo; |
| 24 | 31 | ||
| 32 | + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 33 | + private Long ownerUserId; | ||
| 25 | @Schema(description = "负责人", example = "test") | 34 | @Schema(description = "负责人", example = "test") |
| 26 | private String ownerUserName; | 35 | private String ownerUserName; |
| 27 | 36 | ||
| 28 | - @Schema(description = "创建人", example = "25682") | ||
| 29 | - private String creator; | 37 | + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") |
| 38 | + private LocalDateTime returnTime; | ||
| 30 | 39 | ||
| 31 | - @Schema(description = "创建人名字", example = "test") | ||
| 32 | - private String creatorName; | 40 | + @Schema(description = "计划回款方式", example = "1") |
| 41 | + private Integer returnType; | ||
| 33 | 42 | ||
| 34 | - @Schema(description = "完成状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 35 | - private Boolean finishStatus; | 43 | + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") |
| 44 | + private BigDecimal price; | ||
| 36 | 45 | ||
| 37 | - @Schema(description = "回款方式", example = "1") // 来自 Receivable 的 returnType 字段 | ||
| 38 | - private Integer returnType; | 46 | + @Schema(description = "回款编号", example = "19852") |
| 47 | + private Long receivableId; | ||
| 48 | + @Schema(description = "回款信息") | ||
| 49 | + private CrmReceivableRespVO receivable; | ||
| 50 | + | ||
| 51 | + @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 52 | + private Integer remindDays; | ||
| 53 | + | ||
| 54 | + @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 55 | + private LocalDateTime remindTime; | ||
| 56 | + | ||
| 57 | + @Schema(description = "备注", example = "备注") | ||
| 58 | + private String remark; | ||
| 59 | + | ||
| 60 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 61 | + @ExcelProperty("创建时间") | ||
| 62 | + private LocalDateTime createTime; | ||
| 63 | + | ||
| 64 | + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 65 | + @ExcelProperty("更新时间") | ||
| 66 | + private LocalDateTime updateTime; | ||
| 67 | + | ||
| 68 | + @Schema(description = "创建人", example = "1024") | ||
| 69 | + @ExcelProperty("创建人") | ||
| 70 | + private String creator; | ||
| 71 | + @Schema(description = "创建人名字", example = "芋道源码") | ||
| 72 | + @ExcelProperty("创建人名字") | ||
| 73 | + private String creatorName; | ||
| 39 | 74 | ||
| 40 | } | 75 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import jakarta.validation.constraints.NotNull; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import java.math.BigDecimal; | ||
| 8 | +import java.time.LocalDateTime; | ||
| 9 | + | ||
| 10 | +@Schema(description = "管理后台 - CRM 回款计划新增/修改 Request VO") | ||
| 11 | +@Data | ||
| 12 | +public class CrmReceivablePlanSaveReqVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 15 | + private Long id; | ||
| 16 | + | ||
| 17 | + @Schema(description = "客户编号", hidden = true, example = "2") | ||
| 18 | + private Long customerId; // 该字段不通过前端传递,而是 contractId 查询出来设置进去 | ||
| 19 | + | ||
| 20 | + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 21 | + @NotNull(message = "合同编号不能为空") | ||
| 22 | + private Long contractId; | ||
| 23 | + | ||
| 24 | + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 25 | + @NotNull(message = "负责人编号不能为空") | ||
| 26 | + private Long ownerUserId; | ||
| 27 | + | ||
| 28 | + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 29 | + @NotNull(message = "计划回款日期不能为空") | ||
| 30 | + private LocalDateTime returnTime; | ||
| 31 | + | ||
| 32 | + @Schema(description = "回款方式", example = "1") | ||
| 33 | + private Integer returnType; | ||
| 34 | + | ||
| 35 | + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") | ||
| 36 | + @NotNull(message = "计划回款金额不能为空") | ||
| 37 | + private BigDecimal price; | ||
| 38 | + | ||
| 39 | + @Schema(description = "提前几天提醒", example = "1") | ||
| 40 | + private Integer remindDays; | ||
| 41 | + | ||
| 42 | + @Schema(description = "备注", example = "备注") | ||
| 43 | + private String remark; | ||
| 44 | + | ||
| 45 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanUpdateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.*; | ||
| 5 | - | ||
| 6 | -import jakarta.validation.constraints.*; | ||
| 7 | - | ||
| 8 | -@Schema(description = "管理后台 - CRM 回款计划更新 Request VO") | ||
| 9 | -@Data | ||
| 10 | -@EqualsAndHashCode(callSuper = true) | ||
| 11 | -@ToString(callSuper = true) | ||
| 12 | -public class CrmReceivablePlanUpdateReqVO extends CrmReceivablePlanBaseVO { | ||
| 13 | - | ||
| 14 | - @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25153") | ||
| 15 | - @NotNull(message = "ID不能为空") | ||
| 16 | - private Long id; | ||
| 17 | - | ||
| 18 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableBaseVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | -import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; | ||
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 6 | -import lombok.Data; | ||
| 7 | -import org.springframework.format.annotation.DateTimeFormat; | ||
| 8 | - | ||
| 9 | -import java.time.LocalDateTime; | ||
| 10 | - | ||
| 11 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 12 | - | ||
| 13 | -/** | ||
| 14 | - * 回款 Base VO,提供给添加、修改、详细的子 VO 使用 | ||
| 15 | - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | ||
| 16 | - */ | ||
| 17 | -@Data | ||
| 18 | -public class CrmReceivableBaseVO { | ||
| 19 | - | ||
| 20 | - @Schema(description = "回款编号",requiredMode = Schema.RequiredMode.REQUIRED, example = "31177") | ||
| 21 | - private String no; | ||
| 22 | - | ||
| 23 | - // TODO @liuhongfeng:回款计划编号 | ||
| 24 | - @Schema(description = "回款计划", example = "31177") | ||
| 25 | - private Long planId; | ||
| 26 | - | ||
| 27 | - // TODO @liuhongfeng:客户编号 | ||
| 28 | - @Schema(description = "客户名称", example = "4963") | ||
| 29 | - private Long customerId; | ||
| 30 | - | ||
| 31 | - // TODO @liuhongfeng:客户编号 | ||
| 32 | - @Schema(description = "合同名称", example = "30305") | ||
| 33 | - private Long contractId; | ||
| 34 | - | ||
| 35 | - // TODO @liuhongfeng:这个字段,应该不是前端传递的噢,而是后端自己生成的 | ||
| 36 | - @Schema(description = "审批状态", example = "1") | ||
| 37 | - @InEnum(CrmAuditStatusEnum.class) | ||
| 38 | - private Integer checkStatus; | ||
| 39 | - | ||
| 40 | - @Schema(description = "回款日期") | ||
| 41 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 42 | - private LocalDateTime returnTime; | ||
| 43 | - | ||
| 44 | - @Schema(description = "回款方式", example = "2") | ||
| 45 | - private Integer returnType; | ||
| 46 | - | ||
| 47 | - @Schema(description = "回款金额,单位:分", example = "31859") | ||
| 48 | - private Integer price; | ||
| 49 | - | ||
| 50 | - // TODO @liuhongfeng:负责人编号 | ||
| 51 | - @Schema(description = "负责人", example = "22202") | ||
| 52 | - private Long ownerUserId; | ||
| 53 | - | ||
| 54 | - @Schema(description = "显示顺序") | ||
| 55 | - private Integer sort; | ||
| 56 | - | ||
| 57 | - @Schema(description = "备注", example = "备注") | ||
| 58 | - private String remark; | ||
| 59 | - | ||
| 60 | - | ||
| 61 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableCreateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; | ||
| 2 | - | ||
| 3 | -import lombok.*; | ||
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | - | ||
| 6 | -@Schema(description = "管理后台 - CRM 回款创建 Request VO") | ||
| 7 | -@Data | ||
| 8 | -@EqualsAndHashCode(callSuper = true) | ||
| 9 | -@ToString(callSuper = true) | ||
| 10 | -public class CrmReceivableCreateReqVO extends CrmReceivableBaseVO { | ||
| 11 | - | ||
| 12 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivablePageReqVO.java
| @@ -24,6 +24,9 @@ public class CrmReceivablePageReqVO extends PageParam { | @@ -24,6 +24,9 @@ public class CrmReceivablePageReqVO extends PageParam { | ||
| 24 | @Schema(description = "客户编号", example = "4963") | 24 | @Schema(description = "客户编号", example = "4963") |
| 25 | private Long customerId; | 25 | private Long customerId; |
| 26 | 26 | ||
| 27 | + @Schema(description = "合同编号", example = "4963") | ||
| 28 | + private Long contractId; | ||
| 29 | + | ||
| 27 | @Schema(description = "场景类型", example = "1") | 30 | @Schema(description = "场景类型", example = "1") |
| 28 | @InEnum(CrmSceneTypeEnum.class) | 31 | @InEnum(CrmSceneTypeEnum.class) |
| 29 | private Integer sceneType; // 场景类型,为 null 时则表示全部 | 32 | private Integer sceneType; // 场景类型,为 null 时则表示全部 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java
| 1 | package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; | 1 | package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; | ||
| 4 | +import com.alibaba.excel.annotation.ExcelProperty; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | 6 | +import lombok.Data; |
| 7 | + | ||
| 8 | +import java.math.BigDecimal; | ||
| 5 | import java.time.LocalDateTime; | 9 | import java.time.LocalDateTime; |
| 6 | 10 | ||
| 7 | // TODO 芋艿:导出的 VO,可以考虑使用 @Excel 注解,实现导出功能 | 11 | // TODO 芋艿:导出的 VO,可以考虑使用 @Excel 注解,实现导出功能 |
| 8 | @Schema(description = "管理后台 - CRM 回款 Response VO") | 12 | @Schema(description = "管理后台 - CRM 回款 Response VO") |
| 9 | @Data | 13 | @Data |
| 10 | -@EqualsAndHashCode(callSuper = true) | ||
| 11 | -@ToString(callSuper = true) | ||
| 12 | -public class CrmReceivableRespVO extends CrmReceivableBaseVO { | 14 | +public class CrmReceivableRespVO { |
| 13 | 15 | ||
| 14 | - @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25787") | 16 | + @Schema(description = "编号", example = "25787") |
| 15 | private Long id; | 17 | private Long id; |
| 16 | 18 | ||
| 17 | - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 18 | - private LocalDateTime createTime; | 19 | + @Schema(description = "回款编号", example = "31177") |
| 20 | + private String no; | ||
| 21 | + | ||
| 22 | + @Schema(description = "回款计划编号", example = "1024") | ||
| 23 | + private Long planId; | ||
| 19 | 24 | ||
| 25 | + @Schema(description = "回款方式", example = "2") | ||
| 26 | + private Integer returnType; | ||
| 27 | + | ||
| 28 | + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") | ||
| 29 | + private BigDecimal price; | ||
| 30 | + | ||
| 31 | + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 32 | + private LocalDateTime returnTime; | ||
| 33 | + | ||
| 34 | + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 35 | + private Long customerId; | ||
| 20 | @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") | 36 | @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") |
| 21 | private String customerName; | 37 | private String customerName; |
| 22 | 38 | ||
| 39 | + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 40 | + private Long contractId; | ||
| 41 | + @Schema(description = "合同信息") | ||
| 42 | + private CrmContractRespVO contract; | ||
| 43 | + | ||
| 44 | + @Schema(description = "负责人的用户编号", example = "25682") | ||
| 45 | + @ExcelProperty("负责人的用户编号") | ||
| 46 | + private Long ownerUserId; | ||
| 47 | + @Schema(description = "负责人名字", example = "25682") | ||
| 48 | + @ExcelProperty("负责人名字") | ||
| 49 | + private String ownerUserName; | ||
| 50 | + @Schema(description = "负责人部门") | ||
| 51 | + @ExcelProperty("负责人部门") | ||
| 52 | + private String ownerUserDeptName; | ||
| 53 | + | ||
| 54 | + @Schema(description = "工作流编号", example = "1043") | ||
| 55 | + @ExcelProperty("工作流编号") | ||
| 56 | + private String processInstanceId; | ||
| 57 | + | ||
| 23 | @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | 58 | @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 24 | private Integer auditStatus; | 59 | private Integer auditStatus; |
| 25 | 60 | ||
| 26 | - @Schema(description = "合同编号", example = "Q110") | ||
| 27 | - private String contractNo; | 61 | + @Schema(description = "备注", example = "备注") |
| 62 | + private String remark; | ||
| 28 | 63 | ||
| 29 | - @Schema(description = "负责人", example = "test") | ||
| 30 | - private String ownerUserName; | 64 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 65 | + private LocalDateTime createTime; | ||
| 66 | + | ||
| 67 | + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 68 | + private LocalDateTime updateTime; | ||
| 31 | 69 | ||
| 32 | @Schema(description = "创建人", example = "25682") | 70 | @Schema(description = "创建人", example = "25682") |
| 33 | private String creator; | 71 | private String creator; |
| 34 | - | ||
| 35 | @Schema(description = "创建人名字", example = "test") | 72 | @Schema(description = "创建人名字", example = "test") |
| 36 | private String creatorName; | 73 | private String creatorName; |
| 37 | 74 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; | ||
| 5 | +import cn.iocoder.yudao.module.crm.framework.operatelog.core.*; | ||
| 6 | +import com.mzt.logapi.starter.annotation.DiffLogField; | ||
| 7 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 8 | +import jakarta.validation.constraints.NotNull; | ||
| 9 | +import lombok.Data; | ||
| 10 | + | ||
| 11 | +import java.math.BigDecimal; | ||
| 12 | +import java.time.LocalDateTime; | ||
| 13 | + | ||
| 14 | +@Schema(description = "管理后台 - CRM 回款新增/修改 Request VO") | ||
| 15 | +@Data | ||
| 16 | +public class CrmReceivableSaveReqVO { | ||
| 17 | + | ||
| 18 | + @Schema(description = "编号", example = "25787") | ||
| 19 | + private Long id; | ||
| 20 | + | ||
| 21 | + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 22 | + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) | ||
| 23 | + @NotNull(message = "负责人编号不能为空") | ||
| 24 | + private Long ownerUserId; | ||
| 25 | + | ||
| 26 | + @Schema(description = "客户编号", example = "2") | ||
| 27 | + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) | ||
| 28 | + private Long customerId; // 该字段不通过前端传递,而是 contractId 查询出来设置进去 | ||
| 29 | + | ||
| 30 | + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 31 | + @DiffLogField(name = "合同", function = CrmContractParseFunction.NAME) | ||
| 32 | + @NotNull(message = "合同编号不能为空") | ||
| 33 | + private Long contractId; | ||
| 34 | + | ||
| 35 | + @Schema(description = "回款计划编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 36 | + @DiffLogField(name = "合同", function = CrmReceivablePlanParseFunction.NAME) | ||
| 37 | + private Long planId; | ||
| 38 | + | ||
| 39 | + @Schema(description = "回款方式", example = "2") | ||
| 40 | + @DiffLogField(name = "回款方式", function = CrmReceivableReturnTypeParseFunction.NAME) | ||
| 41 | + @InEnum(CrmReceivableReturnTypeEnum.class) | ||
| 42 | + private Integer returnType; | ||
| 43 | + | ||
| 44 | + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") | ||
| 45 | + @DiffLogField(name = "回款金额") | ||
| 46 | + @NotNull(message = "回款金额不能为空") | ||
| 47 | + private BigDecimal price; | ||
| 48 | + | ||
| 49 | + @Schema(description = "回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 50 | + @NotNull(message = "回款日期不能为空") | ||
| 51 | + @DiffLogField(name = "回款日期") | ||
| 52 | + private LocalDateTime returnTime; | ||
| 53 | + | ||
| 54 | + @Schema(description = "备注", example = "备注") | ||
| 55 | + @DiffLogField(name = "备注") | ||
| 56 | + private String remark; | ||
| 57 | + | ||
| 58 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableUpdateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.*; | ||
| 5 | - | ||
| 6 | -import jakarta.validation.constraints.*; | ||
| 7 | - | ||
| 8 | -@Schema(description = "管理后台 - CRM 回款更新 Request VO") | ||
| 9 | -@Data | ||
| 10 | -@EqualsAndHashCode(callSuper = true) | ||
| 11 | -@ToString(callSuper = true) | ||
| 12 | -public class CrmReceivableUpdateReqVO extends CrmReceivableBaseVO { | ||
| 13 | - | ||
| 14 | - @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25787") | ||
| 15 | - @NotNull(message = "ID不能为空") | ||
| 16 | - private Long id; | ||
| 17 | - | ||
| 18 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/CrmBiRankController.http renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http
| 1 | ### 合同金额排行榜 | 1 | ### 合同金额排行榜 |
| 2 | -GET {{baseUrl}}/crm/bi-rank/get-contract-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 | 2 | +GET {{baseUrl}}/crm/statistics-rank/get-contract-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 |
| 3 | Authorization: Bearer {{token}} | 3 | Authorization: Bearer {{token}} |
| 4 | tenant-id: {{adminTenentId}} | 4 | tenant-id: {{adminTenentId}} |
| 5 | 5 | ||
| 6 | ### 回款金额排行榜 | 6 | ### 回款金额排行榜 |
| 7 | -GET {{baseUrl}}/crm/bi-rank/get-receivable-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 | 7 | +GET {{baseUrl}}/crm/statistics-rank/get-receivable-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 |
| 8 | Authorization: Bearer {{token}} | 8 | Authorization: Bearer {{token}} |
| 9 | tenant-id: {{adminTenentId}} | 9 | tenant-id: {{adminTenentId}} |
| 10 | \ No newline at end of file | 10 | \ No newline at end of file |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/CrmBiRankController.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.bi; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.statistics; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO; | ||
| 5 | -import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRankReqVO; | ||
| 6 | -import cn.iocoder.yudao.module.crm.service.bi.CrmBiRankingService; | 4 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; |
| 5 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsRankingService; | ||
| 7 | import io.swagger.v3.oas.annotations.Operation; | 7 | import io.swagger.v3.oas.annotations.Operation; |
| 8 | import io.swagger.v3.oas.annotations.tags.Tag; | 8 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 9 | import jakarta.annotation.Resource; | 9 | import jakarta.annotation.Resource; |
| @@ -19,68 +19,68 @@ import java.util.List; | @@ -19,68 +19,68 @@ import java.util.List; | ||
| 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | -@Tag(name = "管理后台 - CRM BI 排行榜") | 22 | +@Tag(name = "管理后台 - CRM 排行榜统计") |
| 23 | @RestController | 23 | @RestController |
| 24 | -@RequestMapping("/crm/bi-rank") | 24 | +@RequestMapping("/crm/statistics-rank") |
| 25 | @Validated | 25 | @Validated |
| 26 | -public class CrmBiRankController { | 26 | +public class CrmStatisticsRankController { |
| 27 | 27 | ||
| 28 | @Resource | 28 | @Resource |
| 29 | - private CrmBiRankingService rankingService; | 29 | + private CrmStatisticsRankingService rankingService; |
| 30 | 30 | ||
| 31 | @GetMapping("/get-contract-price-rank") | 31 | @GetMapping("/get-contract-price-rank") |
| 32 | @Operation(summary = "获得合同金额排行榜") | 32 | @Operation(summary = "获得合同金额排行榜") |
| 33 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 34 | - public CommonResult<List<CrmBiRanKRespVO>> getContractPriceRank(@Valid CrmBiRankReqVO rankingReqVO) { | 33 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 34 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getContractPriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 35 | return success(rankingService.getContractPriceRank(rankingReqVO)); | 35 | return success(rankingService.getContractPriceRank(rankingReqVO)); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | @GetMapping("/get-receivable-price-rank") | 38 | @GetMapping("/get-receivable-price-rank") |
| 39 | @Operation(summary = "获得回款金额排行榜") | 39 | @Operation(summary = "获得回款金额排行榜") |
| 40 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 41 | - public CommonResult<List<CrmBiRanKRespVO>> getReceivablePriceRank(@Valid CrmBiRankReqVO rankingReqVO) { | 40 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 41 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getReceivablePriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 42 | return success(rankingService.getReceivablePriceRank(rankingReqVO)); | 42 | return success(rankingService.getReceivablePriceRank(rankingReqVO)); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | @GetMapping("/get-contract-count-rank") | 45 | @GetMapping("/get-contract-count-rank") |
| 46 | @Operation(summary = "获得签约合同数量排行榜") | 46 | @Operation(summary = "获得签约合同数量排行榜") |
| 47 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 48 | - public CommonResult<List<CrmBiRanKRespVO>> getContractCountRank(@Valid CrmBiRankReqVO rankingReqVO) { | 47 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 48 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getContractCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 49 | return success(rankingService.getContractCountRank(rankingReqVO)); | 49 | return success(rankingService.getContractCountRank(rankingReqVO)); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | @GetMapping("/get-product-sales-rank") | 52 | @GetMapping("/get-product-sales-rank") |
| 53 | @Operation(summary = "获得产品销量排行榜") | 53 | @Operation(summary = "获得产品销量排行榜") |
| 54 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 55 | - public CommonResult<List<CrmBiRanKRespVO>> getProductSalesRank(@Valid CrmBiRankReqVO rankingReqVO) { | 54 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 55 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getProductSalesRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 56 | return success(rankingService.getProductSalesRank(rankingReqVO)); | 56 | return success(rankingService.getProductSalesRank(rankingReqVO)); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | @GetMapping("/get-customer-count-rank") | 59 | @GetMapping("/get-customer-count-rank") |
| 60 | @Operation(summary = "获得新增客户数排行榜") | 60 | @Operation(summary = "获得新增客户数排行榜") |
| 61 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 62 | - public CommonResult<List<CrmBiRanKRespVO>> getCustomerCountRank(@Valid CrmBiRankReqVO rankingReqVO) { | 61 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 62 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 63 | return success(rankingService.getCustomerCountRank(rankingReqVO)); | 63 | return success(rankingService.getCustomerCountRank(rankingReqVO)); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | @GetMapping("/get-contacts-count-rank") | 66 | @GetMapping("/get-contacts-count-rank") |
| 67 | @Operation(summary = "获得新增联系人数排行榜") | 67 | @Operation(summary = "获得新增联系人数排行榜") |
| 68 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 69 | - public CommonResult<List<CrmBiRanKRespVO>> getContactsCountRank(@Valid CrmBiRankReqVO rankingReqVO) { | 68 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 69 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getContactsCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 70 | return success(rankingService.getContactsCountRank(rankingReqVO)); | 70 | return success(rankingService.getContactsCountRank(rankingReqVO)); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | @GetMapping("/get-follow-count-rank") | 73 | @GetMapping("/get-follow-count-rank") |
| 74 | @Operation(summary = "获得跟进次数排行榜") | 74 | @Operation(summary = "获得跟进次数排行榜") |
| 75 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 76 | - public CommonResult<List<CrmBiRanKRespVO>> getFollowCountRank(@Valid CrmBiRankReqVO rankingReqVO) { | 75 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 76 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getFollowCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 77 | return success(rankingService.getFollowCountRank(rankingReqVO)); | 77 | return success(rankingService.getFollowCountRank(rankingReqVO)); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | @GetMapping("/get-follow-customer-count-rank") | 80 | @GetMapping("/get-follow-customer-count-rank") |
| 81 | @Operation(summary = "获得跟进客户数排行榜") | 81 | @Operation(summary = "获得跟进客户数排行榜") |
| 82 | - @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')") | ||
| 83 | - public CommonResult<List<CrmBiRanKRespVO>> getFollowCustomerCountRank(@Valid CrmBiRankReqVO rankingReqVO) { | 82 | + @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") |
| 83 | + public CommonResult<List<CrmStatisticsRanKRespVO>> getFollowCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { | ||
| 84 | return success(rankingService.getFollowCustomerCountRank(rankingReqVO)); | 84 | return success(rankingService.getFollowCustomerCountRank(rankingReqVO)); |
| 85 | } | 85 | } |
| 86 | 86 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/vo/CrmBiRanKRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.bi.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Data; | 4 | import lombok.Data; |
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | -@Schema(description = "管理后台 - CRM BI 排行榜 Response VO") | 7 | +@Schema(description = "管理后台 - CRM BI 排行榜统计 Response VO") |
| 8 | @Data | 8 | @Data |
| 9 | -public class CrmBiRanKRespVO { | 9 | +public class CrmStatisticsRanKRespVO { |
| 10 | 10 | ||
| 11 | @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 11 | @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 12 | private Long ownerUserId; | 12 | private Long ownerUserId; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/vo/CrmBiRankReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.bi.vo; | 1 | +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import jakarta.validation.constraints.NotEmpty; | 4 | import jakarta.validation.constraints.NotEmpty; |
| @@ -11,9 +11,9 @@ import java.util.List; | @@ -11,9 +11,9 @@ import java.util.List; | ||
| 11 | 11 | ||
| 12 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | 12 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 13 | 13 | ||
| 14 | -@Schema(description = "管理后台 - CRM BI 排行榜 Request VO") | 14 | +@Schema(description = "管理后台 - CRM 排行榜统计 Request VO") |
| 15 | @Data | 15 | @Data |
| 16 | -public class CrmBiRankReqVO { | 16 | +public class CrmStatisticsRankReqVO { |
| 17 | 17 | ||
| 18 | @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 18 | @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 19 | @NotNull(message = "部门 id 不能为空") | 19 | @NotNull(message = "部门 id 不能为空") |