Commit e53a0ca8845229fb298c4d77da0f09315a6a5a4f
1 parent
a64da48a
✨ CRM:code review 客户导入
Showing
33 changed files
with
273 additions
and
213 deletions
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-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java
| @@ -4,7 +4,6 @@ import cn.hutool.core.io.resource.ResourceUtil; | @@ -4,7 +4,6 @@ import cn.hutool.core.io.resource.ResourceUtil; | ||
| 4 | import cn.hutool.core.lang.Assert; | 4 | import cn.hutool.core.lang.Assert; |
| 5 | import cn.hutool.core.text.csv.CsvRow; | 5 | import cn.hutool.core.text.csv.CsvRow; |
| 6 | import cn.hutool.core.text.csv.CsvUtil; | 6 | import cn.hutool.core.text.csv.CsvUtil; |
| 7 | -import cn.hutool.core.util.ObjUtil; | ||
| 8 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 9 | import cn.iocoder.yudao.framework.ip.core.Area; | 8 | import cn.iocoder.yudao.framework.ip.core.Area; |
| 10 | import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; | 9 | import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; |
| @@ -72,26 +71,25 @@ public class AreaUtils { | @@ -72,26 +71,25 @@ public class AreaUtils { | ||
| 72 | * @param id 区域编号 | 71 | * @param id 区域编号 |
| 73 | * @return 区域 | 72 | * @return 区域 |
| 74 | */ | 73 | */ |
| 75 | - public static Area getArea(Integer id) { | 74 | + public static Area parseArea(Integer id) { |
| 76 | return areas.get(id); | 75 | return areas.get(id); |
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | /** | 78 | /** |
| 80 | * 获得指定区域对应的编号 | 79 | * 获得指定区域对应的编号 |
| 81 | * | 80 | * |
| 82 | - * @param path 区域编号 | ||
| 83 | - * @return 编号 | 81 | + * @param pathStr 区域路径,例如说:河南省/石家庄市/新华区 |
| 82 | + * @return 区域 | ||
| 84 | */ | 83 | */ |
| 85 | - public static Area getArea(String path) { | ||
| 86 | - String[] paths = path.split("/"); | 84 | + public static Area parseArea(String pathStr) { |
| 85 | + String[] paths = pathStr.split("/"); | ||
| 87 | Area area = null; | 86 | Area area = null; |
| 88 | - for (int i = 0; i < paths.length; i++) { | ||
| 89 | - final int finalI = i; | 87 | + for (String path : paths) { |
| 90 | if (area == null) { | 88 | if (area == null) { |
| 91 | - area = findFirst(convertList(areas.values(), a -> a), item -> ObjUtil.equal(paths[finalI], item.getName())); | ||
| 92 | - continue; | 89 | + area = findFirst(areas.values(), item -> item.getName().equals(path)); |
| 90 | + } else { | ||
| 91 | + area = findFirst(area.getChildren(), item -> item.getName().equals(path)); | ||
| 93 | } | 92 | } |
| 94 | - area = findFirst(area.getChildren(), item -> ObjUtil.equal(paths[finalI], item.getName())); | ||
| 95 | } | 93 | } |
| 96 | return area; | 94 | return area; |
| 97 | } | 95 | } |
| @@ -102,9 +100,9 @@ public class AreaUtils { | @@ -102,9 +100,9 @@ public class AreaUtils { | ||
| 102 | * @param areas 地区树 | 100 | * @param areas 地区树 |
| 103 | * @return 所有节点的全路径名称 | 101 | * @return 所有节点的全路径名称 |
| 104 | */ | 102 | */ |
| 105 | - public static List<String> getAllAreaNodePaths(List<Area> areas) { | 103 | + public static List<String> getAreaNodePathList(List<Area> areas) { |
| 106 | List<String> paths = new ArrayList<>(); | 104 | List<String> paths = new ArrayList<>(); |
| 107 | - areas.forEach(area -> traverse(area, "", paths)); | 105 | + areas.forEach(area -> getAreaNodePathList(area, "", paths)); |
| 108 | return paths; | 106 | return paths; |
| 109 | } | 107 | } |
| 110 | 108 | ||
| @@ -113,9 +111,9 @@ public class AreaUtils { | @@ -113,9 +111,9 @@ public class AreaUtils { | ||
| 113 | * | 111 | * |
| 114 | * @param node 父节点 | 112 | * @param node 父节点 |
| 115 | * @param path 全路径名称 | 113 | * @param path 全路径名称 |
| 116 | - * @param paths 全路径名称列表 | 114 | + * @param paths 全路径名称列表,省份/城市/地区 |
| 117 | */ | 115 | */ |
| 118 | - private static void traverse(Area node, String path, List<String> paths) { | 116 | + private static void getAreaNodePathList(Area node, String path, List<String> paths) { |
| 119 | if (node == null) { | 117 | if (node == null) { |
| 120 | return; | 118 | return; |
| 121 | } | 119 | } |
| @@ -124,7 +122,7 @@ public class AreaUtils { | @@ -124,7 +122,7 @@ public class AreaUtils { | ||
| 124 | paths.add(currentPath); | 122 | paths.add(currentPath); |
| 125 | // 递归遍历子节点 | 123 | // 递归遍历子节点 |
| 126 | for (Area child : node.getChildren()) { | 124 | for (Area child : node.getChildren()) { |
| 127 | - traverse(child, currentPath, paths); | 125 | + getAreaNodePathList(child, currentPath, paths); |
| 128 | } | 126 | } |
| 129 | } | 127 | } |
| 130 | 128 | ||
| @@ -195,7 +193,7 @@ public class AreaUtils { | @@ -195,7 +193,7 @@ public class AreaUtils { | ||
| 195 | */ | 193 | */ |
| 196 | public static Integer getParentIdByType(Integer id, @NonNull AreaTypeEnum type) { | 194 | public static Integer getParentIdByType(Integer id, @NonNull AreaTypeEnum type) { |
| 197 | for (int i = 0; i < Byte.MAX_VALUE; i++) { | 195 | for (int i = 0; i < Byte.MAX_VALUE; i++) { |
| 198 | - Area area = AreaUtils.getArea(id); | 196 | + Area area = AreaUtils.parseArea(id); |
| 199 | if (area == null) { | 197 | if (area == null) { |
| 200 | return null; | 198 | return null; |
| 201 | } | 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
| @@ -49,7 +49,7 @@ | @@ -49,7 +49,7 @@ | ||
| 49 | <dependency> | 49 | <dependency> |
| 50 | <groupId>cn.iocoder.boot</groupId> | 50 | <groupId>cn.iocoder.boot</groupId> |
| 51 | <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> | 51 | <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> |
| 52 | - <scope>provided</scope> <!-- 设置为 provided,只有 ExcelUtils 使用 --> | 52 | + <optional>true</optional> <!-- 设置为 optional,只有在 AreaConvert 的时候使用 --> |
| 53 | </dependency> | 53 | </dependency> |
| 54 | </dependencies> | 54 | </dependencies> |
| 55 | 55 |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java
| @@ -33,7 +33,7 @@ public class AreaConvert implements Converter<Object> { | @@ -33,7 +33,7 @@ public class AreaConvert implements Converter<Object> { | ||
| 33 | GlobalConfiguration globalConfiguration) { | 33 | GlobalConfiguration globalConfiguration) { |
| 34 | // 解析地区编号 | 34 | // 解析地区编号 |
| 35 | String label = readCellData.getStringValue(); | 35 | String label = readCellData.getStringValue(); |
| 36 | - Area area = AreaUtils.getArea(label); | 36 | + Area area = AreaUtils.parseArea(label); |
| 37 | if (area == null) { | 37 | if (area == null) { |
| 38 | log.error("[convertToJavaData][label({}) 解析不掉]", label); | 38 | log.error("[convertToJavaData][label({}) 解析不掉]", label); |
| 39 | return null; | 39 | return null; |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java
| @@ -19,33 +19,40 @@ import java.util.List; | @@ -19,33 +19,40 @@ import java.util.List; | ||
| 19 | */ | 19 | */ |
| 20 | public class SelectSheetWriteHandler implements SheetWriteHandler { | 20 | public class SelectSheetWriteHandler implements SheetWriteHandler { |
| 21 | 21 | ||
| 22 | + private static final String DICT_SHEET_NAME = "字典sheet"; | ||
| 23 | + | ||
| 24 | + // TODO @puhui999:key 不使用 int 值么?感觉不是很优雅哈。 | ||
| 22 | private final List<KeyValue<Integer, List<String>>> selectMap; | 25 | private final List<KeyValue<Integer, List<String>>> selectMap; |
| 23 | 26 | ||
| 24 | private static final char[] ALPHABET = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', | 27 | private static final char[] ALPHABET = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', |
| 25 | 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; | 28 | 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; |
| 26 | 29 | ||
| 27 | public SelectSheetWriteHandler(List<KeyValue<Integer, List<String>>> selectMap) { | 30 | public SelectSheetWriteHandler(List<KeyValue<Integer, List<String>>> selectMap) { |
| 31 | + if (CollUtil.isEmpty(selectMap)) { | ||
| 32 | + this.selectMap = null; | ||
| 33 | + return; | ||
| 34 | + } | ||
| 28 | selectMap.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 | 35 | selectMap.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 |
| 29 | this.selectMap = selectMap; | 36 | this.selectMap = selectMap; |
| 30 | } | 37 | } |
| 31 | 38 | ||
| 32 | @Override | 39 | @Override |
| 33 | public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { | 40 | public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { |
| 34 | - if (selectMap == null || CollUtil.isEmpty(selectMap)) { | 41 | + if (CollUtil.isEmpty(selectMap)) { |
| 35 | return; | 42 | return; |
| 36 | } | 43 | } |
| 37 | - // 需要设置下拉框的sheet页 | ||
| 38 | - Sheet curSheet = writeSheetHolder.getSheet(); | ||
| 39 | - DataValidationHelper helper = curSheet.getDataValidationHelper(); | ||
| 40 | - String dictSheetName = "字典sheet"; | 44 | + // 需要设置下拉框的 sheet 页 |
| 45 | + Sheet currentSheet = writeSheetHolder.getSheet(); | ||
| 46 | + DataValidationHelper helper = currentSheet.getDataValidationHelper(); | ||
| 41 | Workbook workbook = writeWorkbookHolder.getWorkbook(); | 47 | Workbook workbook = writeWorkbookHolder.getWorkbook(); |
| 42 | - // 数据字典的sheet页 | ||
| 43 | - Sheet dictSheet = workbook.createSheet(dictSheetName); | 48 | + |
| 49 | + // 数据字典的 sheet 页 | ||
| 50 | + Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); | ||
| 44 | for (KeyValue<Integer, List<String>> keyValue : selectMap) { | 51 | for (KeyValue<Integer, List<String>> keyValue : selectMap) { |
| 45 | // 设置下拉单元格的首行、末行、首列、末列 | 52 | // 设置下拉单元格的首行、末行、首列、末列 |
| 46 | CellRangeAddressList rangeAddressList = new CellRangeAddressList(1, 65533, keyValue.getKey(), keyValue.getKey()); | 53 | CellRangeAddressList rangeAddressList = new CellRangeAddressList(1, 65533, keyValue.getKey(), keyValue.getKey()); |
| 47 | int rowLen = keyValue.getValue().size(); | 54 | int rowLen = keyValue.getValue().size(); |
| 48 | - // 设置字典sheet页的值 每一列一个字典项 | 55 | + // 设置字典 sheet 页的值 每一列一个字典项 |
| 49 | for (int i = 0; i < rowLen; i++) { | 56 | for (int i = 0; i < rowLen; i++) { |
| 50 | Row row = dictSheet.getRow(i); | 57 | Row row = dictSheet.getRow(i); |
| 51 | if (row == null) { | 58 | if (row == null) { |
| @@ -53,18 +60,18 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | @@ -53,18 +60,18 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | ||
| 53 | } | 60 | } |
| 54 | row.createCell(keyValue.getKey()).setCellValue(keyValue.getValue().get(i)); | 61 | row.createCell(keyValue.getKey()).setCellValue(keyValue.getValue().get(i)); |
| 55 | } | 62 | } |
| 56 | - String excelColumn = getExcelColumn(keyValue.getKey()); | ||
| 57 | - // 下拉框数据来源 eg:字典sheet!$B1:$B2 | ||
| 58 | - String refers = dictSheetName + "!$" + excelColumn + "$1:$" + excelColumn + "$" + rowLen; | ||
| 59 | - // 创建可被其他单元格引用的名称 | 63 | + |
| 64 | + // TODO @puhui999:下面 1. 2.1 2.2 2.3 我是按照已经理解的,调整了下格式;这样可读性更好;在 52 到 62 行,你可以看看,是不是也弄下序号; | ||
| 65 | + // 1. 创建可被其他单元格引用的名称 | ||
| 60 | Name name = workbook.createName(); | 66 | Name name = workbook.createName(); |
| 61 | - // 设置名称的名字 | ||
| 62 | - name.setNameName("dict" + keyValue.getKey()); | ||
| 63 | - // 设置公式 | ||
| 64 | - name.setRefersToFormula(refers); | ||
| 65 | - // 设置引用约束 | ||
| 66 | - DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + keyValue.getKey()); | ||
| 67 | - // 设置约束 | 67 | + // TODO @puhui999:下面的 excelColumn 和 refers 两行,是不是可以封装成一个方法,替代 getExcelColumn; |
| 68 | + String excelColumn = getExcelColumn(keyValue.getKey()); | ||
| 69 | + String refers = DICT_SHEET_NAME + "!$" + excelColumn + "$1:$" + excelColumn + "$" + rowLen; // 下拉框数据来源 eg:字典sheet!$B1:$B2 | ||
| 70 | + name.setNameName("dict" + keyValue.getKey()); // 设置名称的名字 | ||
| 71 | + name.setRefersToFormula(refers); // 设置公式 | ||
| 72 | + | ||
| 73 | + // 2.1 设置约束 | ||
| 74 | + DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + keyValue.getKey()); // 设置引用约束 | ||
| 68 | DataValidation validation = helper.createValidation(constraint, rangeAddressList); | 75 | DataValidation validation = helper.createValidation(constraint, rangeAddressList); |
| 69 | if (validation instanceof HSSFDataValidation) { | 76 | if (validation instanceof HSSFDataValidation) { |
| 70 | validation.setSuppressDropDownArrow(false); | 77 | validation.setSuppressDropDownArrow(false); |
| @@ -72,10 +79,10 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | @@ -72,10 +79,10 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | ||
| 72 | validation.setSuppressDropDownArrow(true); | 79 | validation.setSuppressDropDownArrow(true); |
| 73 | validation.setShowErrorBox(true); | 80 | validation.setShowErrorBox(true); |
| 74 | } | 81 | } |
| 75 | - // 阻止输入非下拉框的值 | 82 | + // 2.2 阻止输入非下拉框的值 |
| 76 | validation.setErrorStyle(DataValidation.ErrorStyle.STOP); | 83 | validation.setErrorStyle(DataValidation.ErrorStyle.STOP); |
| 77 | validation.createErrorBox("提示", "此值不存在于下拉选择中!"); | 84 | validation.createErrorBox("提示", "此值不存在于下拉选择中!"); |
| 78 | - // 添加下拉框约束 | 85 | + // 2.3 添加下拉框约束 |
| 79 | writeSheetHolder.getSheet().addValidationData(validation); | 86 | writeSheetHolder.getSheet().addValidationData(validation); |
| 80 | } | 87 | } |
| 81 | } | 88 | } |
| @@ -86,8 +93,9 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | @@ -86,8 +93,9 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | ||
| 86 | * @param num 数字 | 93 | * @param num 数字 |
| 87 | * @return 字母 | 94 | * @return 字母 |
| 88 | */ | 95 | */ |
| 96 | + // TODO @puhui999:这个是必须字母列哇?还是数字其实也可以哈?主要想看看,怎么能把这个逻辑,进一步简化 | ||
| 89 | private String getExcelColumn(int num) { | 97 | private String getExcelColumn(int num) { |
| 90 | - String column = ""; | 98 | + String column; |
| 91 | int len = ALPHABET.length - 1; | 99 | int len = ALPHABET.length - 1; |
| 92 | int first = num / len; | 100 | int first = num / len; |
| 93 | int second = num % len; | 101 | int second = num % len; |
| @@ -96,9 +104,9 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | @@ -96,9 +104,9 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { | ||
| 96 | } else { | 104 | } else { |
| 97 | column = ALPHABET[first - 1] + ""; | 105 | column = ALPHABET[first - 1] + ""; |
| 98 | if (second == 0) { | 106 | if (second == 0) { |
| 99 | - column = column + ALPHABET[len] + ""; | 107 | + column = column + ALPHABET[len]; |
| 100 | } else { | 108 | } else { |
| 101 | - column = column + ALPHABET[second - 1] + ""; | 109 | + column = column + ALPHABET[second - 1]; |
| 102 | } | 110 | } |
| 103 | } | 111 | } |
| 104 | return column; | 112 | return column; |
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
| @@ -33,15 +33,7 @@ public class ExcelUtils { | @@ -33,15 +33,7 @@ public class ExcelUtils { | ||
| 33 | */ | 33 | */ |
| 34 | public static <T> void write(HttpServletResponse response, String filename, String sheetName, | 34 | public static <T> void write(HttpServletResponse response, String filename, String sheetName, |
| 35 | Class<T> head, List<T> data) throws IOException { | 35 | Class<T> head, List<T> data) throws IOException { |
| 36 | - // 输出 Excel | ||
| 37 | - EasyExcel.write(response.getOutputStream(), head) | ||
| 38 | - .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 | ||
| 39 | - .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 | ||
| 40 | - .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 | ||
| 41 | - .sheet(sheetName).doWrite(data); | ||
| 42 | - // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 | ||
| 43 | - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); | ||
| 44 | - response.setContentType("application/vnd.ms-excel;charset=UTF-8"); | 36 | + write(response, filename, sheetName, head, data, null); |
| 45 | } | 37 | } |
| 46 | 38 | ||
| 47 | /** | 39 | /** |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
| @@ -14,6 +14,7 @@ public interface ErrorCodeConstants { | @@ -14,6 +14,7 @@ public interface ErrorCodeConstants { | ||
| 14 | ErrorCode CONTRACT_UPDATE_FAIL_NOT_DRAFT = 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, "更新合同审核状态失败,原因:合同不是审核中状态"); | 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, "生成合同序列号重复,请重试"); | ||
| 17 | 18 | ||
| 18 | // ========== 线索管理 1-020-001-000 ========== | 19 | // ========== 线索管理 1-020-001-000 ========== |
| 19 | ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); | 20 | ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java renamed to yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java
| @@ -13,26 +13,18 @@ import java.util.Arrays; | @@ -13,26 +13,18 @@ import java.util.Arrays; | ||
| 13 | */ | 13 | */ |
| 14 | @Getter | 14 | @Getter |
| 15 | @AllArgsConstructor | 15 | @AllArgsConstructor |
| 16 | -public enum CrmReturnTypeEnum implements IntArrayValuable { | 16 | +public enum CrmReceivableReturnTypeEnum implements IntArrayValuable { |
| 17 | 17 | ||
| 18 | - // 支票 | ||
| 19 | CHECK(1, "支票"), | 18 | CHECK(1, "支票"), |
| 20 | - // 现金 | ||
| 21 | CASH(2, "现金"), | 19 | CASH(2, "现金"), |
| 22 | - // 邮政汇款 | ||
| 23 | POSTAL_REMITTANCE(3, "邮政汇款"), | 20 | POSTAL_REMITTANCE(3, "邮政汇款"), |
| 24 | - // 电汇 | ||
| 25 | TELEGRAPHIC_TRANSFER(4, "电汇"), | 21 | TELEGRAPHIC_TRANSFER(4, "电汇"), |
| 26 | - // 网上转账 | ||
| 27 | ONLINE_TRANSFER(5, "网上转账"), | 22 | ONLINE_TRANSFER(5, "网上转账"), |
| 28 | - // 支付宝 | ||
| 29 | ALIPAY(6, "支付宝"), | 23 | ALIPAY(6, "支付宝"), |
| 30 | - // 微信支付 | ||
| 31 | WECHAT_PAY(7, "微信支付"), | 24 | WECHAT_PAY(7, "微信支付"), |
| 32 | - // 其他 | ||
| 33 | OTHER(8, "其它"); | 25 | OTHER(8, "其它"); |
| 34 | 26 | ||
| 35 | - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReturnTypeEnum::getType).toArray(); | 27 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReceivableReturnTypeEnum::getType).toArray(); |
| 36 | 28 | ||
| 37 | /** | 29 | /** |
| 38 | * 类型 | 30 | * 类型 |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
| @@ -268,6 +268,24 @@ public class CrmCustomerController { | @@ -268,6 +268,24 @@ public class CrmCustomerController { | ||
| 268 | ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list, builderSelectMap()); | 268 | ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list, builderSelectMap()); |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | + private List<KeyValue<Integer, List<String>>> builderSelectMap() { | ||
| 272 | + List<KeyValue<Integer, List<String>>> selectMap = new ArrayList<>(); | ||
| 273 | + // 获取地区下拉数据 | ||
| 274 | + // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? | ||
| 275 | + Area area = AreaUtils.parseArea(Area.ID_CHINA); | ||
| 276 | + selectMap.add(new KeyValue<>(6, AreaUtils.getAreaNodePathList(area.getChildren()))); | ||
| 277 | + // 获取客户所属行业 | ||
| 278 | + List<String> customerIndustries = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); | ||
| 279 | + selectMap.add(new KeyValue<>(8, customerIndustries)); | ||
| 280 | + // 获取客户等级 | ||
| 281 | + List<String> customerLevels = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); | ||
| 282 | + selectMap.add(new KeyValue<>(9, customerLevels)); | ||
| 283 | + // 获取客户来源 | ||
| 284 | + List<String> customerSources = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); | ||
| 285 | + selectMap.add(new KeyValue<>(10, customerSources)); | ||
| 286 | + return selectMap; | ||
| 287 | + } | ||
| 288 | + | ||
| 271 | @PostMapping("/import") | 289 | @PostMapping("/import") |
| 272 | @Operation(summary = "导入客户") | 290 | @Operation(summary = "导入客户") |
| 273 | @PreAuthorize("@ss.hasPermission('system:customer:import')") | 291 | @PreAuthorize("@ss.hasPermission('system:customer:import')") |
| @@ -321,21 +339,4 @@ public class CrmCustomerController { | @@ -321,21 +339,4 @@ public class CrmCustomerController { | ||
| 321 | return success(true); | 339 | return success(true); |
| 322 | } | 340 | } |
| 323 | 341 | ||
| 324 | - private List<KeyValue<Integer, List<String>>> builderSelectMap() { | ||
| 325 | - List<KeyValue<Integer, List<String>>> selectMap = new ArrayList<>(); | ||
| 326 | - // 获取地区下拉数据 | ||
| 327 | - Area area = AreaUtils.getArea(Area.ID_CHINA); | ||
| 328 | - selectMap.add(new KeyValue<>(6, AreaUtils.getAllAreaNodePaths(area.getChildren()))); | ||
| 329 | - // 获取客户所属行业 | ||
| 330 | - List<String> customerIndustries = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); | ||
| 331 | - selectMap.add(new KeyValue<>(8, customerIndustries)); | ||
| 332 | - // 获取客户等级 | ||
| 333 | - List<String> customerLevels = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); | ||
| 334 | - selectMap.add(new KeyValue<>(9, customerLevels)); | ||
| 335 | - // 获取客户来源 | ||
| 336 | - List<String> customerSources = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); | ||
| 337 | - selectMap.add(new KeyValue<>(10, customerSources)); | ||
| 338 | - return selectMap; | ||
| 339 | - } | ||
| 340 | - | ||
| 341 | } | 342 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java
| @@ -107,7 +107,6 @@ public class CrmReceivableController { | @@ -107,7 +107,6 @@ public class CrmReceivableController { | ||
| 107 | return success(buildReceivableDetailPage(pageResult)); | 107 | return success(buildReceivableDetailPage(pageResult)); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | - // TODO 芋艿:后面在优化导出 | ||
| 111 | @GetMapping("/export-excel") | 110 | @GetMapping("/export-excel") |
| 112 | @Operation(summary = "导出回款 Excel") | 111 | @Operation(summary = "导出回款 Excel") |
| 113 | @PreAuthorize("@ss.hasPermission('crm:receivable:export')") | 112 | @PreAuthorize("@ss.hasPermission('crm:receivable:export')") |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java
| @@ -28,7 +28,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; | @@ -28,7 +28,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 28 | import jakarta.annotation.Resource; | 28 | import jakarta.annotation.Resource; |
| 29 | import jakarta.servlet.http.HttpServletResponse; | 29 | import jakarta.servlet.http.HttpServletResponse; |
| 30 | import jakarta.validation.Valid; | 30 | import jakarta.validation.Valid; |
| 31 | -import org.springframework.context.annotation.Lazy; | ||
| 32 | import org.springframework.security.access.prepost.PreAuthorize; | 31 | import org.springframework.security.access.prepost.PreAuthorize; |
| 33 | import org.springframework.validation.annotation.Validated; | 32 | import org.springframework.validation.annotation.Validated; |
| 34 | import org.springframework.web.bind.annotation.*; | 33 | import org.springframework.web.bind.annotation.*; |
| @@ -56,7 +55,6 @@ public class CrmReceivablePlanController { | @@ -56,7 +55,6 @@ public class CrmReceivablePlanController { | ||
| 56 | @Resource | 55 | @Resource |
| 57 | private CrmReceivableService receivableService; | 56 | private CrmReceivableService receivableService; |
| 58 | @Resource | 57 | @Resource |
| 59 | - @Lazy | ||
| 60 | private CrmContractService contractService; | 58 | private CrmContractService contractService; |
| 61 | @Resource | 59 | @Resource |
| 62 | private CrmCustomerService customerService; | 60 | private CrmCustomerService customerService; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java
| @@ -6,6 +6,7 @@ import lombok.Data; | @@ -6,6 +6,7 @@ import lombok.Data; | ||
| 6 | import java.math.BigDecimal; | 6 | import java.math.BigDecimal; |
| 7 | import java.time.LocalDateTime; | 7 | import java.time.LocalDateTime; |
| 8 | 8 | ||
| 9 | +// TODO @puhui999:缺导出 | ||
| 9 | @Schema(description = "管理后台 - CRM 回款计划 Response VO") | 10 | @Schema(description = "管理后台 - CRM 回款计划 Response VO") |
| 10 | @Data | 11 | @Data |
| 11 | public class CrmReceivablePlanRespVO { | 12 | public class CrmReceivablePlanRespVO { |
| @@ -13,35 +14,44 @@ public class CrmReceivablePlanRespVO { | @@ -13,35 +14,44 @@ public class CrmReceivablePlanRespVO { | ||
| 13 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | 14 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 14 | private Long id; | 15 | private Long id; |
| 15 | 16 | ||
| 16 | - @Schema(description = "回款编号", example = "19852") | ||
| 17 | - private Long receivableId; | ||
| 18 | - | ||
| 19 | @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | 17 | @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 20 | private Integer period; | 18 | private Integer period; |
| 21 | 19 | ||
| 22 | - @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") | ||
| 23 | - private BigDecimal price; | ||
| 24 | - | ||
| 25 | - @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 26 | - private LocalDateTime returnTime; | ||
| 27 | - | ||
| 28 | - @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 29 | - private Integer remindDays; | ||
| 30 | - | ||
| 31 | - @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 32 | - private LocalDateTime remindTime; | ||
| 33 | - | ||
| 34 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | 20 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 35 | private Long customerId; | 21 | private Long customerId; |
| 22 | + @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") | ||
| 23 | + private String customerName; | ||
| 36 | 24 | ||
| 37 | @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | 25 | @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 38 | private Long contractId; | 26 | private Long contractId; |
| 27 | + @Schema(description = "合同编号", example = "Q110") | ||
| 28 | + private String contractNo; | ||
| 39 | 29 | ||
| 40 | @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | 30 | @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 41 | private Long ownerUserId; | 31 | private Long ownerUserId; |
| 32 | + @Schema(description = "负责人", example = "test") | ||
| 33 | + private String ownerUserName; | ||
| 34 | + | ||
| 35 | + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 36 | + private LocalDateTime returnTime; | ||
| 37 | + | ||
| 38 | + @Schema(description = "回款方式", example = "1") | ||
| 39 | + private Integer returnType; // 来自 Receivable 的 returnType 字段 | ||
| 42 | 40 | ||
| 43 | - @Schema(description = "显示顺序") | ||
| 44 | - private Integer sort; | 41 | + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") |
| 42 | + private BigDecimal price; | ||
| 43 | + | ||
| 44 | + @Schema(description = "回款编号", example = "19852") | ||
| 45 | + private Long receivableId; | ||
| 46 | + | ||
| 47 | + @Schema(description = "完成状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||
| 48 | + private Boolean finishStatus; | ||
| 49 | + | ||
| 50 | + @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 51 | + private Integer remindDays; | ||
| 52 | + | ||
| 53 | + @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 54 | + private LocalDateTime remindTime; | ||
| 45 | 55 | ||
| 46 | @Schema(description = "备注", example = "备注") | 56 | @Schema(description = "备注", example = "备注") |
| 47 | private String remark; | 57 | private String remark; |
| @@ -49,25 +59,10 @@ public class CrmReceivablePlanRespVO { | @@ -49,25 +59,10 @@ public class CrmReceivablePlanRespVO { | ||
| 49 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 59 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 50 | private LocalDateTime createTime; | 60 | private LocalDateTime createTime; |
| 51 | 61 | ||
| 52 | - @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") | ||
| 53 | - private String customerName; | ||
| 54 | - | ||
| 55 | - @Schema(description = "合同编号", example = "Q110") | ||
| 56 | - private String contractNo; | ||
| 57 | - | ||
| 58 | - @Schema(description = "负责人", example = "test") | ||
| 59 | - private String ownerUserName; | ||
| 60 | - | ||
| 61 | @Schema(description = "创建人", example = "25682") | 62 | @Schema(description = "创建人", example = "25682") |
| 62 | private String creator; | 63 | private String creator; |
| 63 | 64 | ||
| 64 | @Schema(description = "创建人名字", example = "test") | 65 | @Schema(description = "创建人名字", example = "test") |
| 65 | private String creatorName; | 66 | private String creatorName; |
| 66 | 67 | ||
| 67 | - @Schema(description = "完成状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 68 | - private Boolean finishStatus; | ||
| 69 | - | ||
| 70 | - @Schema(description = "回款方式", example = "1") | ||
| 71 | - private Integer returnType; // 来自 Receivable 的 returnType 字段 | ||
| 72 | - | ||
| 73 | } | 68 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java
| @@ -14,26 +14,6 @@ public class CrmReceivablePlanSaveReqVO { | @@ -14,26 +14,6 @@ public class CrmReceivablePlanSaveReqVO { | ||
| 14 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | 14 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 15 | private Long id; | 15 | private Long id; |
| 16 | 16 | ||
| 17 | - @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 18 | - @NotNull(message = "期数不能为空") | ||
| 19 | - private Integer period; | ||
| 20 | - | ||
| 21 | - @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") | ||
| 22 | - @NotNull(message = "计划回款金额不能为空") | ||
| 23 | - private BigDecimal price; | ||
| 24 | - | ||
| 25 | - @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 26 | - @NotNull(message = "计划回款日期不能为空") | ||
| 27 | - private LocalDateTime returnTime; | ||
| 28 | - | ||
| 29 | - @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 30 | - @NotNull(message = "提前几天提醒不能为空") | ||
| 31 | - private Integer remindDays; | ||
| 32 | - | ||
| 33 | - @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") | ||
| 34 | - @NotNull(message = "提醒日期不能为空") | ||
| 35 | - private LocalDateTime remindTime; | ||
| 36 | - | ||
| 37 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | 17 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 38 | @NotNull(message = "客户编号不能为空") | 18 | @NotNull(message = "客户编号不能为空") |
| 39 | private Long customerId; | 19 | private Long customerId; |
| @@ -46,8 +26,19 @@ public class CrmReceivablePlanSaveReqVO { | @@ -46,8 +26,19 @@ public class CrmReceivablePlanSaveReqVO { | ||
| 46 | @NotNull(message = "负责人编号不能为空") | 26 | @NotNull(message = "负责人编号不能为空") |
| 47 | private Long ownerUserId; | 27 | private Long ownerUserId; |
| 48 | 28 | ||
| 49 | - @Schema(description = "显示顺序") | ||
| 50 | - private Integer sort; | 29 | + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") |
| 30 | + @NotNull(message = "计划回款日期不能为空") | ||
| 31 | + private LocalDateTime returnTime; | ||
| 32 | + | ||
| 33 | + @Schema(description = "回款方式", example = "1") | ||
| 34 | + private Integer returnType; | ||
| 35 | + | ||
| 36 | + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") | ||
| 37 | + @NotNull(message = "计划回款金额不能为空") | ||
| 38 | + private BigDecimal price; | ||
| 39 | + | ||
| 40 | + @Schema(description = "提前几天提醒", example = "1") | ||
| 41 | + private Integer remindDays; | ||
| 51 | 42 | ||
| 52 | @Schema(description = "备注", example = "备注") | 43 | @Schema(description = "备注", example = "备注") |
| 53 | private String remark; | 44 | private String remark; |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.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.framework.common.validation.InEnum; | 3 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 4 | -import cn.iocoder.yudao.module.crm.enums.receivable.CrmReturnTypeEnum; | 4 | +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; |
| 5 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | import jakarta.validation.constraints.NotNull; | 6 | import jakarta.validation.constraints.NotNull; |
| 7 | import lombok.Data; | 7 | import lombok.Data; |
| @@ -23,7 +23,7 @@ public class CrmReceivableSaveReqVO { | @@ -23,7 +23,7 @@ public class CrmReceivableSaveReqVO { | ||
| 23 | private Long planId; // 不是通过回款计划创建的回款没有回款计划编号 | 23 | private Long planId; // 不是通过回款计划创建的回款没有回款计划编号 |
| 24 | 24 | ||
| 25 | @Schema(description = "回款方式", example = "2") | 25 | @Schema(description = "回款方式", example = "2") |
| 26 | - @InEnum(CrmReturnTypeEnum.class) | 26 | + @InEnum(CrmReceivableReturnTypeEnum.class) |
| 27 | private Integer returnType; | 27 | private Integer returnType; |
| 28 | 28 | ||
| 29 | @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") | 29 | @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java
| @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; | 4 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| 5 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 5 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 6 | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; | 6 | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| 7 | -import cn.iocoder.yudao.module.crm.enums.receivable.CrmReturnTypeEnum; | 7 | +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; |
| 8 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 8 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 9 | import com.baomidou.mybatisplus.annotation.KeySequence; | 9 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 10 | import com.baomidou.mybatisplus.annotation.TableId; | 10 | import com.baomidou.mybatisplus.annotation.TableId; |
| @@ -60,7 +60,7 @@ public class CrmReceivableDO extends BaseDO { | @@ -60,7 +60,7 @@ public class CrmReceivableDO extends BaseDO { | ||
| 60 | */ | 60 | */ |
| 61 | private LocalDateTime returnTime; | 61 | private LocalDateTime returnTime; |
| 62 | /** | 62 | /** |
| 63 | - * 回款方式,关联枚举{@link CrmReturnTypeEnum} | 63 | + * 回款方式,关联枚举{@link CrmReceivableReturnTypeEnum} |
| 64 | */ | 64 | */ |
| 65 | private Integer returnType; | 65 | private Integer returnType; |
| 66 | /** | 66 | /** |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java
| @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.receivable; | @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.receivable; | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; | 4 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| 5 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; | 5 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 6 | -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 6 | +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; |
| 7 | import com.baomidou.mybatisplus.annotation.KeySequence; | 7 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 8 | import com.baomidou.mybatisplus.annotation.TableId; | 8 | import com.baomidou.mybatisplus.annotation.TableId; |
| 9 | import com.baomidou.mybatisplus.annotation.TableName; | 9 | import com.baomidou.mybatisplus.annotation.TableName; |
| @@ -13,7 +13,7 @@ import java.math.BigDecimal; | @@ -13,7 +13,7 @@ import java.math.BigDecimal; | ||
| 13 | import java.time.LocalDateTime; | 13 | import java.time.LocalDateTime; |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | - * 回款计划 DO | 16 | + * CRM 回款计划 DO |
| 17 | * | 17 | * |
| 18 | * @author 芋道源码 | 18 | * @author 芋道源码 |
| 19 | */ | 19 | */ |
| @@ -37,49 +37,60 @@ public class CrmReceivablePlanDO extends BaseDO { | @@ -37,49 +37,60 @@ public class CrmReceivablePlanDO extends BaseDO { | ||
| 37 | */ | 37 | */ |
| 38 | private Integer period; | 38 | private Integer period; |
| 39 | /** | 39 | /** |
| 40 | - * 回款编号,关联 {@link CrmReceivableDO#getId()} | 40 | + * 客户编号 |
| 41 | + * | ||
| 42 | + * 关联 {@link CrmCustomerDO#getId()} | ||
| 41 | */ | 43 | */ |
| 42 | - private Long receivableId; | 44 | + private Long customerId; |
| 43 | /** | 45 | /** |
| 44 | - * 计划回款金额,单位:元 | 46 | + * 合同编号 |
| 47 | + * | ||
| 48 | + * 关联 {@link CrmContractDO#getId()} | ||
| 45 | */ | 49 | */ |
| 46 | - private BigDecimal price; | 50 | + private Long contractId; |
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * 负责人编号 | ||
| 54 | + * | ||
| 55 | + * 关联 AdminUserDO 的 id 字段 | ||
| 56 | + */ | ||
| 57 | + private Long ownerUserId; | ||
| 58 | + | ||
| 47 | /** | 59 | /** |
| 48 | * 计划回款日期 | 60 | * 计划回款日期 |
| 49 | */ | 61 | */ |
| 50 | private LocalDateTime returnTime; | 62 | private LocalDateTime returnTime; |
| 51 | /** | 63 | /** |
| 52 | - * 提前几天提醒 | 64 | + * 回款类型 |
| 65 | + * | ||
| 66 | + * 枚举 {@link CrmReceivableReturnTypeEnum} | ||
| 53 | */ | 67 | */ |
| 54 | - private Integer remindDays; | 68 | + private Integer returnType; |
| 55 | /** | 69 | /** |
| 56 | - * 提醒日期 | 70 | + * 计划回款金额,单位:元 |
| 57 | */ | 71 | */ |
| 58 | - private LocalDateTime remindTime; | 72 | + private BigDecimal price; |
| 73 | + | ||
| 59 | /** | 74 | /** |
| 60 | - * 客户编号,关联 {@link CrmCustomerDO#getId()} | 75 | + * 回款编号,关联 {@link CrmReceivableDO#getId()} |
| 61 | */ | 76 | */ |
| 62 | - private Long customerId; | 77 | + private Long receivableId; |
| 63 | /** | 78 | /** |
| 64 | - * 合同编号,关联 {@link CrmContractDO#getId()} | 79 | + * 完成状态 |
| 65 | */ | 80 | */ |
| 66 | - private Long contractId; | 81 | + private Boolean finishStatus; |
| 82 | + | ||
| 67 | /** | 83 | /** |
| 68 | - * 负责人编号,关联 {@link AdminUserRespDTO#getId()} | 84 | + * 提前几天提醒 |
| 69 | */ | 85 | */ |
| 70 | - private Long ownerUserId; | 86 | + private Integer remindDays; |
| 71 | /** | 87 | /** |
| 72 | - * 显示顺序 | 88 | + * 提醒日期 |
| 73 | */ | 89 | */ |
| 74 | - private Integer sort; | 90 | + private LocalDateTime remindTime; |
| 75 | /** | 91 | /** |
| 76 | * 备注 | 92 | * 备注 |
| 77 | */ | 93 | */ |
| 78 | private String remark; | 94 | private String remark; |
| 79 | 95 | ||
| 80 | - /** | ||
| 81 | - * 完成状态 | ||
| 82 | - */ | ||
| 83 | - private Boolean finishStatus; | ||
| 84 | - | ||
| 85 | } | 96 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java
| @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; | @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; | ||
| 11 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | 11 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| 12 | import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; | 12 | import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; |
| 13 | import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; | 13 | import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; |
| 14 | -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||
| 15 | import org.apache.ibatis.annotations.Mapper; | 14 | import org.apache.ibatis.annotations.Mapper; |
| 16 | 15 | ||
| 17 | import java.time.LocalDateTime; | 16 | import java.time.LocalDateTime; |
| @@ -26,10 +25,8 @@ import java.util.List; | @@ -26,10 +25,8 @@ import java.util.List; | ||
| 26 | @Mapper | 25 | @Mapper |
| 27 | public interface CrmContractMapper extends BaseMapperX<CrmContractDO> { | 26 | public interface CrmContractMapper extends BaseMapperX<CrmContractDO> { |
| 28 | 27 | ||
| 29 | - default int updateOwnerUserIdById(Long id, Long ownerUserId) { | ||
| 30 | - return update(new LambdaUpdateWrapper<CrmContractDO>() | ||
| 31 | - .eq(CrmContractDO::getId, id) | ||
| 32 | - .set(CrmContractDO::getOwnerUserId, ownerUserId)); | 28 | + default CrmContractDO selectByNo(String no) { |
| 29 | + return selectOne(CrmContractDO::getNo, no); | ||
| 33 | } | 30 | } |
| 34 | 31 | ||
| 35 | default PageResult<CrmContractDO> selectPageByCustomerId(CrmContractPageReqVO pageReqVO) { | 32 | default PageResult<CrmContractDO> selectPageByCustomerId(CrmContractPageReqVO pageReqVO) { |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java
0 → 100644
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.dal.redis.no; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.date.DatePattern; | ||
| 4 | +import cn.hutool.core.date.DateUtil; | ||
| 5 | +import cn.iocoder.yudao.module.crm.dal.redis.RedisKeyConstants; | ||
| 6 | +import jakarta.annotation.Resource; | ||
| 7 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 8 | +import org.springframework.stereotype.Repository; | ||
| 9 | + | ||
| 10 | +import java.time.Duration; | ||
| 11 | +import java.time.LocalDateTime; | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * Crm 订单序号的 Redis DAO | ||
| 16 | + * | ||
| 17 | + * @author HUIHUI | ||
| 18 | + */ | ||
| 19 | +@Repository | ||
| 20 | +public class CrmNoRedisDAO { | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 合同 {@link cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO} | ||
| 24 | + */ | ||
| 25 | + public static final String CONTRACT_NO_PREFIX = "HT"; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 还款 {@link cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO} | ||
| 29 | + */ | ||
| 30 | + public static final String RECEIVABLE_PREFIX = "HK"; | ||
| 31 | + | ||
| 32 | + @Resource | ||
| 33 | + private StringRedisTemplate stringRedisTemplate; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 生成序号,使用当前日期,格式为 {PREFIX} + yyyyMMdd + 6 位自增 | ||
| 37 | + * 例如说:QTRK 202109 000001 (没有中间空格) | ||
| 38 | + * | ||
| 39 | + * @param prefix 前缀 | ||
| 40 | + * @return 序号 | ||
| 41 | + */ | ||
| 42 | + public String generate(String prefix) { | ||
| 43 | + // 递增序号 | ||
| 44 | + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); | ||
| 45 | + String key = RedisKeyConstants.NO + noPrefix; | ||
| 46 | + Long no = stringRedisTemplate.opsForValue().increment(key); | ||
| 47 | + // 设置过期时间 | ||
| 48 | + stringRedisTemplate.expire(key, Duration.ofDays(1L)); | ||
| 49 | + return noPrefix + String.format("%06d", no); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | +} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
| @@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; | @@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; | ||
| 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; | 17 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO; |
| 18 | import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper; | 18 | import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper; |
| 19 | import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper; | 19 | import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper; |
| 20 | +import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO; | ||
| 20 | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; | 21 | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| 21 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | 22 | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| 22 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | 23 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| @@ -70,6 +71,9 @@ public class CrmContractServiceImpl implements CrmContractService { | @@ -70,6 +71,9 @@ public class CrmContractServiceImpl implements CrmContractService { | ||
| 70 | private CrmContractProductMapper contractProductMapper; | 71 | private CrmContractProductMapper contractProductMapper; |
| 71 | 72 | ||
| 72 | @Resource | 73 | @Resource |
| 74 | + private CrmNoRedisDAO noRedisDAO; | ||
| 75 | + | ||
| 76 | + @Resource | ||
| 73 | private CrmPermissionService crmPermissionService; | 77 | private CrmPermissionService crmPermissionService; |
| 74 | @Resource | 78 | @Resource |
| 75 | private CrmProductService productService; | 79 | private CrmProductService productService; |
| @@ -94,11 +98,14 @@ public class CrmContractServiceImpl implements CrmContractService { | @@ -94,11 +98,14 @@ public class CrmContractServiceImpl implements CrmContractService { | ||
| 94 | List<CrmContractProductDO> contractProducts = validateContractProducts(createReqVO.getProducts()); | 98 | List<CrmContractProductDO> contractProducts = validateContractProducts(createReqVO.getProducts()); |
| 95 | // 1.2 校验关联字段 | 99 | // 1.2 校验关联字段 |
| 96 | validateRelationDataExists(createReqVO); | 100 | validateRelationDataExists(createReqVO); |
| 97 | - // TODO 芋艿:生成 no | 101 | + // 1.3 生成序号 |
| 102 | + String no = noRedisDAO.generate(CrmNoRedisDAO.CONTRACT_NO_PREFIX); | ||
| 103 | + if (contractMapper.selectByNo(no) != null) { | ||
| 104 | + throw exception(CONTRACT_NO_EXISTS); | ||
| 105 | + } | ||
| 98 | 106 | ||
| 99 | // 2.1 插入合同 | 107 | // 2.1 插入合同 |
| 100 | - CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class); | ||
| 101 | - contract.setNo(System.currentTimeMillis() + ""); // TODO | 108 | + CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setNo(no); |
| 102 | calculateTotalPrice(contract, contractProducts); | 109 | calculateTotalPrice(contract, contractProducts); |
| 103 | contractMapper.insert(contract); | 110 | contractMapper.insert(contract); |
| 104 | // 2.2 插入合同关联商品 | 111 | // 2.2 插入合同关联商品 |
| @@ -247,7 +254,7 @@ public class CrmContractServiceImpl implements CrmContractService { | @@ -247,7 +254,7 @@ public class CrmContractServiceImpl implements CrmContractService { | ||
| 247 | crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(), | 254 | crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(), |
| 248 | reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); | 255 | reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); |
| 249 | // 2.2 设置负责人 | 256 | // 2.2 设置负责人 |
| 250 | - contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); | 257 | + contractMapper.updateById(new CrmContractDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); |
| 251 | 258 | ||
| 252 | // 3. 记录转移日志 | 259 | // 3. 记录转移日志 |
| 253 | LogRecordContext.putVariable("contract", contract); | 260 | LogRecordContext.putVariable("contract", contract); |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java
| @@ -23,7 +23,7 @@ import com.mzt.logapi.context.LogRecordContext; | @@ -23,7 +23,7 @@ import com.mzt.logapi.context.LogRecordContext; | ||
| 23 | import com.mzt.logapi.service.impl.DiffParseFunction; | 23 | import com.mzt.logapi.service.impl.DiffParseFunction; |
| 24 | import com.mzt.logapi.starter.annotation.LogRecord; | 24 | import com.mzt.logapi.starter.annotation.LogRecord; |
| 25 | import jakarta.annotation.Resource; | 25 | import jakarta.annotation.Resource; |
| 26 | -import org.hibernate.validator.internal.util.stereotypes.Lazy; | 26 | +import org.springframework.context.annotation.Lazy; |
| 27 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
| 28 | import org.springframework.transaction.annotation.Transactional; | 28 | import org.springframework.transaction.annotation.Transactional; |
| 29 | import org.springframework.validation.annotation.Validated; | 29 | import org.springframework.validation.annotation.Validated; |
| @@ -57,6 +57,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { | @@ -57,6 +57,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { | ||
| 57 | private CrmCustomerService customerService; | 57 | private CrmCustomerService customerService; |
| 58 | @Resource | 58 | @Resource |
| 59 | private CrmPermissionService permissionService; | 59 | private CrmPermissionService permissionService; |
| 60 | + | ||
| 60 | @Resource | 61 | @Resource |
| 61 | private AdminUserApi adminUserApi; | 62 | private AdminUserApi adminUserApi; |
| 62 | 63 | ||
| @@ -72,15 +73,16 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { | @@ -72,15 +73,16 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { | ||
| 72 | int period = (int) (count + 1); | 73 | int period = (int) (count + 1); |
| 73 | createReqVO.setPeriod(createReqVO.getPeriod() != period ? period : createReqVO.getPeriod()); // 如果期数不对则纠正 | 74 | createReqVO.setPeriod(createReqVO.getPeriod() != period ? period : createReqVO.getPeriod()); // 如果期数不对则纠正 |
| 74 | 75 | ||
| 75 | - // 2.1 插入 | 76 | + // 2. 插入还款计划 |
| 76 | CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setId(null).setFinishStatus(false); | 77 | CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setId(null).setFinishStatus(false); |
| 77 | receivablePlanMapper.insert(receivablePlan); | 78 | receivablePlanMapper.insert(receivablePlan); |
| 78 | - // 2.2 创建数据权限 | 79 | + |
| 80 | + // 3. 创建数据权限 | ||
| 79 | permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(createReqVO.getOwnerUserId()) | 81 | permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(createReqVO.getOwnerUserId()) |
| 80 | .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(receivablePlan.getId()) | 82 | .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(receivablePlan.getId()) |
| 81 | .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); | 83 | .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); |
| 82 | 84 | ||
| 83 | - // 3. 记录操作日志上下文 | 85 | + // 4. 记录操作日志上下文 |
| 84 | LogRecordContext.putVariable("receivablePlan", receivablePlan); | 86 | LogRecordContext.putVariable("receivablePlan", receivablePlan); |
| 85 | return receivablePlan.getId(); | 87 | return receivablePlan.getId(); |
| 86 | } | 88 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java
| @@ -31,6 +31,7 @@ import com.mzt.logapi.service.impl.DiffParseFunction; | @@ -31,6 +31,7 @@ import com.mzt.logapi.service.impl.DiffParseFunction; | ||
| 31 | import com.mzt.logapi.starter.annotation.LogRecord; | 31 | import com.mzt.logapi.starter.annotation.LogRecord; |
| 32 | import jakarta.annotation.Resource; | 32 | import jakarta.annotation.Resource; |
| 33 | import lombok.extern.slf4j.Slf4j; | 33 | import lombok.extern.slf4j.Slf4j; |
| 34 | +import org.springframework.context.annotation.Lazy; | ||
| 34 | import org.springframework.stereotype.Service; | 35 | import org.springframework.stereotype.Service; |
| 35 | import org.springframework.transaction.annotation.Transactional; | 36 | import org.springframework.transaction.annotation.Transactional; |
| 36 | import org.springframework.validation.annotation.Validated; | 37 | import org.springframework.validation.annotation.Validated; |
| @@ -66,10 +67,12 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { | @@ -66,10 +67,12 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { | ||
| 66 | private CrmContractService contractService; | 67 | private CrmContractService contractService; |
| 67 | @Resource | 68 | @Resource |
| 68 | private CrmCustomerService customerService; | 69 | private CrmCustomerService customerService; |
| 69 | - @Resource | 70 | +// @Resource |
| 71 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 70 | private CrmReceivablePlanService receivablePlanService; | 72 | private CrmReceivablePlanService receivablePlanService; |
| 71 | @Resource | 73 | @Resource |
| 72 | private CrmPermissionService permissionService; | 74 | private CrmPermissionService permissionService; |
| 75 | + | ||
| 73 | @Resource | 76 | @Resource |
| 74 | private AdminUserApi adminUserApi; | 77 | private AdminUserApi adminUserApi; |
| 75 | @Resource | 78 | @Resource |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java
| 1 | package cn.iocoder.yudao.module.crm.util; | 1 | package cn.iocoder.yudao.module.crm.util; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||
| 5 | import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; | 4 | import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; |
| 6 | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; | 5 | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| 7 | 6 | ||
| @@ -18,23 +17,11 @@ public class CrmAuditStatusUtils { | @@ -18,23 +17,11 @@ public class CrmAuditStatusUtils { | ||
| 18 | * @param bpmResult BPM 审批结果 | 17 | * @param bpmResult BPM 审批结果 |
| 19 | */ | 18 | */ |
| 20 | public static Integer convertBpmResultToAuditStatus(Integer bpmResult) { | 19 | public static Integer convertBpmResultToAuditStatus(Integer bpmResult) { |
| 21 | - Assert.isTrue(isEndResult(bpmResult), "BPM 审批结果({}) 转换失败, 流程状态不是最终结果", bpmResult); | ||
| 22 | Integer auditStatus = BpmProcessInstanceResultEnum.APPROVE.getResult().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() | 20 | Integer auditStatus = BpmProcessInstanceResultEnum.APPROVE.getResult().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() |
| 23 | : BpmProcessInstanceResultEnum.REJECT.getResult().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() | 21 | : BpmProcessInstanceResultEnum.REJECT.getResult().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() |
| 24 | - : BpmProcessInstanceResultEnum.CANCEL.getResult(); | 22 | + : BpmProcessInstanceResultEnum.CANCEL.getResult().equals(bpmResult) ? BpmProcessInstanceResultEnum.CANCEL.getResult() : null; |
| 25 | Assert.notNull(auditStatus, "BPM 审批结果({}) 转换失败", bpmResult); | 23 | Assert.notNull(auditStatus, "BPM 审批结果({}) 转换失败", bpmResult); |
| 26 | return auditStatus; | 24 | return auditStatus; |
| 27 | } | 25 | } |
| 28 | 26 | ||
| 29 | - /** | ||
| 30 | - * 判断该结果是否处于 End 最终结果 | ||
| 31 | - * | ||
| 32 | - * @param bpmResult BPM 审批结果 | ||
| 33 | - * @return 是否 | ||
| 34 | - */ | ||
| 35 | - public static boolean isEndResult(Integer bpmResult) { | ||
| 36 | - return ObjectUtils.equalsAny(bpmResult, BpmProcessInstanceResultEnum.APPROVE.getResult(), | ||
| 37 | - BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult()); | ||
| 38 | - } | ||
| 39 | - | ||
| 40 | } | 27 | } |
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java
| @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; | @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; | ||
| 5 | import java.util.Collection; | 5 | import java.util.Collection; |
| 6 | import java.util.List; | 6 | import java.util.List; |
| 7 | 7 | ||
| 8 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 9 | + | ||
| 8 | /** | 10 | /** |
| 9 | * 字典数据 API 接口 | 11 | * 字典数据 API 接口 |
| 10 | * | 12 | * |
| @@ -41,11 +43,22 @@ public interface DictDataApi { | @@ -41,11 +43,22 @@ public interface DictDataApi { | ||
| 41 | DictDataRespDTO parseDictData(String type, String label); | 43 | DictDataRespDTO parseDictData(String type, String label); |
| 42 | 44 | ||
| 43 | /** | 45 | /** |
| 46 | + * 获得指定字典类型的字典数据列表 | ||
| 47 | + * | ||
| 48 | + * @param dictType 字典类型 | ||
| 49 | + * @return 字典数据列表 | ||
| 50 | + */ | ||
| 51 | + List<DictDataRespDTO> getDictDataList(String dictType); | ||
| 52 | + | ||
| 53 | + /** | ||
| 44 | * 获得字典数据标签列表 | 54 | * 获得字典数据标签列表 |
| 45 | * | 55 | * |
| 46 | * @param dictType 字典类型 | 56 | * @param dictType 字典类型 |
| 47 | * @return 字典数据标签列表 | 57 | * @return 字典数据标签列表 |
| 48 | */ | 58 | */ |
| 49 | - List<String> getDictDataLabelList(String dictType); | 59 | + default List<String> getDictDataLabelList(String dictType) { |
| 60 | + List<DictDataRespDTO> list = getDictDataList(dictType); | ||
| 61 | + return convertList(list, DictDataRespDTO::getLabel); | ||
| 62 | + } | ||
| 50 | 63 | ||
| 51 | } | 64 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java
| 1 | package cn.iocoder.yudao.module.system.api.dict; | 1 | package cn.iocoder.yudao.module.system.api.dict; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 3 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; | 4 | import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; |
| 6 | import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; | 5 | import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; |
| @@ -9,11 +8,8 @@ import jakarta.annotation.Resource; | @@ -9,11 +8,8 @@ import jakarta.annotation.Resource; | ||
| 9 | import org.springframework.stereotype.Service; | 8 | import org.springframework.stereotype.Service; |
| 10 | 9 | ||
| 11 | import java.util.Collection; | 10 | import java.util.Collection; |
| 12 | -import java.util.Collections; | ||
| 13 | import java.util.List; | 11 | import java.util.List; |
| 14 | 12 | ||
| 15 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 16 | - | ||
| 17 | /** | 13 | /** |
| 18 | * 字典数据 API 实现类 | 14 | * 字典数据 API 实现类 |
| 19 | * | 15 | * |
| @@ -43,12 +39,9 @@ public class DictDataApiImpl implements DictDataApi { | @@ -43,12 +39,9 @@ public class DictDataApiImpl implements DictDataApi { | ||
| 43 | } | 39 | } |
| 44 | 40 | ||
| 45 | @Override | 41 | @Override |
| 46 | - public List<String> getDictDataLabelList(String dictType) { | ||
| 47 | - List<DictDataDO> dictDataList = dictDataService.getDictDataListByDictType(dictType); | ||
| 48 | - if (CollUtil.isEmpty(dictDataList)) { | ||
| 49 | - return Collections.emptyList(); | ||
| 50 | - } | ||
| 51 | - return convertList(dictDataList, DictDataDO::getLabel); | 42 | + public List<DictDataRespDTO> getDictDataList(String dictType) { |
| 43 | + List<DictDataDO> list = dictDataService.getDictDataListByDictType(dictType); | ||
| 44 | + return BeanUtils.toBean(list, DictDataRespDTO.class); | ||
| 52 | } | 45 | } |
| 53 | 46 | ||
| 54 | } | 47 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java
| @@ -29,7 +29,7 @@ public class AreaController { | @@ -29,7 +29,7 @@ public class AreaController { | ||
| 29 | @GetMapping("/tree") | 29 | @GetMapping("/tree") |
| 30 | @Operation(summary = "获得地区树") | 30 | @Operation(summary = "获得地区树") |
| 31 | public CommonResult<List<AreaNodeRespVO>> getAreaTree() { | 31 | public CommonResult<List<AreaNodeRespVO>> getAreaTree() { |
| 32 | - Area area = AreaUtils.getArea(Area.ID_CHINA); | 32 | + Area area = AreaUtils.parseArea(Area.ID_CHINA); |
| 33 | Assert.notNull(area, "获取不到中国"); | 33 | Assert.notNull(area, "获取不到中国"); |
| 34 | return success(BeanUtils.toBean(area.getChildren(), AreaNodeRespVO.class)); | 34 | return success(BeanUtils.toBean(area.getChildren(), AreaNodeRespVO.class)); |
| 35 | } | 35 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java
| @@ -26,7 +26,7 @@ public class AppAreaController { | @@ -26,7 +26,7 @@ public class AppAreaController { | ||
| 26 | @GetMapping("/tree") | 26 | @GetMapping("/tree") |
| 27 | @Operation(summary = "获得地区树") | 27 | @Operation(summary = "获得地区树") |
| 28 | public CommonResult<List<AppAreaNodeRespVO>> getAreaTree() { | 28 | public CommonResult<List<AppAreaNodeRespVO>> getAreaTree() { |
| 29 | - Area area = AreaUtils.getArea(Area.ID_CHINA); | 29 | + Area area = AreaUtils.parseArea(Area.ID_CHINA); |
| 30 | Assert.notNull(area, "获取不到中国"); | 30 | Assert.notNull(area, "获取不到中国"); |
| 31 | return success(BeanUtils.toBean(area.getChildren(), AppAreaNodeRespVO.class)); | 31 | return success(BeanUtils.toBean(area.getChildren(), AppAreaNodeRespVO.class)); |
| 32 | } | 32 | } |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java
| @@ -100,7 +100,7 @@ public interface DictDataService { | @@ -100,7 +100,7 @@ public interface DictDataService { | ||
| 100 | DictDataDO parseDictData(String dictType, String label); | 100 | DictDataDO parseDictData(String dictType, String label); |
| 101 | 101 | ||
| 102 | /** | 102 | /** |
| 103 | - * 获得字典数据列表 | 103 | + * 获得指定数据类型的字典数据列表 |
| 104 | * | 104 | * |
| 105 | * @param dictType 字典类型 | 105 | * @param dictType 字典类型 |
| 106 | * @return 字典数据列表 | 106 | * @return 字典数据列表 |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java
| @@ -171,7 +171,9 @@ public class DictDataServiceImpl implements DictDataService { | @@ -171,7 +171,9 @@ public class DictDataServiceImpl implements DictDataService { | ||
| 171 | 171 | ||
| 172 | @Override | 172 | @Override |
| 173 | public List<DictDataDO> getDictDataListByDictType(String dictType) { | 173 | public List<DictDataDO> getDictDataListByDictType(String dictType) { |
| 174 | - return dictDataMapper.selectList(DictDataDO::getDictType, dictType); | 174 | + List<DictDataDO> list = dictDataMapper.selectList(DictDataDO::getDictType, dictType); |
| 175 | + list.sort(Comparator.comparing(DictDataDO::getSort)); | ||
| 176 | + return list; | ||
| 175 | } | 177 | } |
| 176 | 178 | ||
| 177 | } | 179 | } |