From 462a4ee8230b05b1fb4a9b15382ce84446e7cabf Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 25 Feb 2024 22:32:12 +0800 Subject: [PATCH 01/86] =?UTF-8?q?=E9=87=8D=E6=9E=84=20excel=20=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E6=A8=A1=E7=89=88=E4=B8=8B=E6=8B=89=E7=94=9F=E6=88=90?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BD=BF=E7=94=A8=E5=AD=97=E6=AE=B5=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E7=9A=84=E6=96=B9=E5=BC=8F=E9=85=8D=E7=BD=AE=E4=B8=8B?= =?UTF-8?q?=E6=8B=89=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/annotations/ExcelColumnSelect.java | 20 ++++ .../excel/core/enums/ExcelColumn.java | 27 ----- .../core/handler/SelectSheetWriteHandler.java | 100 ++++++++++++++---- .../service/ExcelColumnSelectDataService.java | 38 +++++++ .../framework/excel/core/util/ExcelUtils.java | 20 +--- .../admin/customer/CrmCustomerController.java | 25 +---- .../vo/customer/CrmCustomerImportExcelVO.java | 9 ++ .../crm/framework/excel/package-info.java | 1 + .../AreaExcelColumnSelectDataServiceImpl.java | 38 +++++++ ...ustryExcelColumnSelectDataServiceImpl.java | 35 ++++++ ...LevelExcelColumnSelectDataServiceImpl.java | 35 ++++++ ...ourceExcelColumnSelectDataServiceImpl.java | 35 ++++++ 12 files changed, 291 insertions(+), 92 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/enums/ExcelColumn.java create mode 100644 yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java new file mode 100644 index 0000000000..2c519523b9 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.framework.excel.core.annotations; + +import java.lang.annotation.*; + +/** + * 给列添加下拉选择数据 + * + * @author HUIHUI + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelColumnSelect { + + /** + * @return 获取下拉数据源的方法名称 + */ + String value(); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/enums/ExcelColumn.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/enums/ExcelColumn.java deleted file mode 100644 index dd8a8374c1..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/enums/ExcelColumn.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.framework.excel.core.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -// TODO @puhui999:列表有办法通过 field name 么?主要考虑一个点,可能导入模版的顺序可能会变 -/** - * Excel 列名枚举 - * 默认枚举 26 列列名如果有需求更多的列名请自行补充 - * - * @author HUIHUI - */ -@Getter -@AllArgsConstructor -public enum ExcelColumn { - - A(0), B(1), C(2), D(3), E(4), F(5), G(6), H(7), I(8), - J(9), K(10), L(11), M(12), N(13), O(14), P(15), Q(16), - R(17), S(18), T(19), U(20), V(21), W(22), X(23), Y(24), - Z(25); - - /** - * 列索引 - */ - private final int colNum; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java index 38d01bd879..421c592009 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java @@ -1,9 +1,12 @@ package cn.iocoder.yudao.framework.excel.core.handler; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn; +import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; +import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; +import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; @@ -11,10 +14,11 @@ import org.apache.poi.hssf.usermodel.HSSFDataValidation; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddressList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; /** * 基于固定 sheet 实现下拉框 @@ -23,6 +27,9 @@ import java.util.stream.Collectors; */ public class SelectSheetWriteHandler implements SheetWriteHandler { + private static final List ALPHABET = getExcelColumnNameList(); + private static final List EXCEL_COLUMN_SELECT_DATA_SERVICES = new ArrayList<>(); + /** * 数据起始行从 0 开始 * @@ -36,21 +43,46 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { private static final String DICT_SHEET_NAME = "字典sheet"; - // TODO @puhui999:Map> 可以么?之前用 keyvalue 的原因,返回给前端,无法用 linkedhashmap,默认 key 会乱序 - private final List>> selectMap; + private final List>> selectMap = new ArrayList<>(); // 使用 List + KeyValue 组合方便排序 - public SelectSheetWriteHandler(List>> selectMap) { - if (CollUtil.isEmpty(selectMap)) { - this.selectMap = null; + public SelectSheetWriteHandler(Class head) { + // 加载下拉数据获取接口 + Map beansMap = SpringUtil.getBeanFactory().getBeansOfType(ExcelColumnSelectDataService.class); + if (MapUtil.isEmpty(beansMap)) { return; } - // 校验一下 key 是否唯一 - Map nameCounts = selectMap.stream() - .collect(Collectors.groupingBy(item -> item.getKey().name(), Collectors.counting())); - Assert.isFalse(nameCounts.entrySet().stream().allMatch(entry -> entry.getValue() > 1), "下拉数据 key 重复请排查!!!"); - + if (CollUtil.isEmpty(EXCEL_COLUMN_SELECT_DATA_SERVICES) || EXCEL_COLUMN_SELECT_DATA_SERVICES.size() != beansMap.values().size()) { + EXCEL_COLUMN_SELECT_DATA_SERVICES.clear(); + EXCEL_COLUMN_SELECT_DATA_SERVICES.addAll(convertList(beansMap.values(), b -> b)); + } + // 解析下拉数据 + Map excelPropertyFields = getFieldsWithAnnotation(head, ExcelProperty.class); + Map excelColumnSelectFields = getFieldsWithAnnotation(head, ExcelColumnSelect.class); + int colIndex = 0; + for (String fieldName : excelPropertyFields.keySet()) { + Field field = excelColumnSelectFields.get(fieldName); + if (field != null) { + getSelectDataList(colIndex, field); + } + colIndex++; + } selectMap.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 - this.selectMap = selectMap; + } + + /** + * 获得下拉数据 + * + * @param colIndex 列索引 + * @param field 字段 + */ + private void getSelectDataList(int colIndex, Field field) { + EXCEL_COLUMN_SELECT_DATA_SERVICES.forEach(selectDataService -> { + List stringList = selectDataService.handle(field.getAnnotation(ExcelColumnSelect.class).value()); + if (CollUtil.isEmpty(stringList)) { + return; + } + selectMap.add(new KeyValue<>(colIndex, stringList)); + }); } @Override @@ -65,7 +97,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { // 2. 创建数据字典的 sheet 页 Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); - for (KeyValue> keyValue : selectMap) { + for (KeyValue> keyValue : selectMap) { int rowLength = keyValue.getValue().size(); // 2.1 设置字典 sheet 页的值 每一列一个字典项 for (int i = 0; i < rowLength; i++) { @@ -73,7 +105,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { if (row == null) { row = dictSheet.createRow(i); } - row.createCell(keyValue.getKey().getColNum()).setCellValue(keyValue.getValue().get(i)); + row.createCell(keyValue.getKey()).setCellValue(keyValue.getValue().get(i)); } // 2.2 设置单元格下拉选择 setColumnSelect(writeSheetHolder, workbook, helper, keyValue); @@ -84,10 +116,10 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { * 设置单元格下拉选择 */ private static void setColumnSelect(WriteSheetHolder writeSheetHolder, Workbook workbook, DataValidationHelper helper, - KeyValue> keyValue) { + KeyValue> keyValue) { // 1.1 创建可被其他单元格引用的名称 Name name = workbook.createName(); - String excelColumn = keyValue.getKey().name(); + String excelColumn = ALPHABET.get(keyValue.getKey()); // 1.2 下拉框数据来源 eg:字典sheet!$B1:$B2 String refers = DICT_SHEET_NAME + "!$" + excelColumn + "$1:$" + excelColumn + "$" + keyValue.getValue().size(); name.setNameName("dict" + keyValue.getKey()); // 设置名称的名字 @@ -97,7 +129,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + keyValue.getKey()); // 设置引用约束 // 设置下拉单元格的首行、末行、首列、末列 CellRangeAddressList rangeAddressList = new CellRangeAddressList(FIRST_ROW, LAST_ROW, - keyValue.getKey().getColNum(), keyValue.getKey().getColNum()); + keyValue.getKey(), keyValue.getKey()); DataValidation validation = helper.createValidation(constraint, rangeAddressList); if (validation instanceof HSSFDataValidation) { validation.setSuppressDropDownArrow(false); @@ -112,4 +144,28 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { writeSheetHolder.getSheet().addValidationData(validation); } + public static Map getFieldsWithAnnotation(Class clazz, Class annotationClass) { + Map annotatedFields = new LinkedHashMap<>(); + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (field.isAnnotationPresent(annotationClass)) { + annotatedFields.put(field.getName(), field); + } + } + return annotatedFields; + } + + + private static List getExcelColumnNameList() { + ArrayList strings = new ArrayList<>(); + for (int i = 1; i <= 52; i++) { // 生成 52 列名称,需要更多请重写此方法 + if (i <= 26) { + strings.add(String.valueOf((char) ('A' + i - 1))); // 使用 ASCII 码值转字母 + } else { + strings.add(String.valueOf((char) ('A' + (i - 1) / 26 - 1)) + (char) ('A' + (i - 1) % 26)); + } + } + return strings; + } + } \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java new file mode 100644 index 0000000000..987cf79298 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.framework.excel.core.service; + +import cn.hutool.core.util.StrUtil; + +import java.util.Collections; +import java.util.List; + +/** + * Excel 列下拉数据源获取接口 + * + * 为什么不直接解析字典还搞个接口?考虑到有的下拉数据不是从字典中获取的所有需要做一个兼容 + * + * @author HUIHUI + */ +public interface ExcelColumnSelectDataService { + + /** + * 获得方法名称 + * + * @return 方法名称 + */ + String getFunctionName(); + + /** + * 获得列下拉数据源 + * + * @return 下拉数据源 + */ + List getSelectDataList(); + + default List handle(String funcName) { + if (StrUtil.isEmptyIfStr(funcName) || !StrUtil.equals(getFunctionName(), funcName)) { + return Collections.emptyList(); + } + return getSelectDataList(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java index 81d9a8a978..f5c4b83139 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java @@ -1,7 +1,5 @@ package cn.iocoder.yudao.framework.excel.core.util; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn; import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.converters.longconverter.LongStringConverter; @@ -34,27 +32,11 @@ public class ExcelUtils { */ public static void write(HttpServletResponse response, String filename, String sheetName, Class head, List data) throws IOException { - write(response, filename, sheetName, head, data, null); - } - - /** - * 将列表以 Excel 响应给前端 - * - * @param response 响应 - * @param filename 文件名 - * @param sheetName Excel sheet 名 - * @param head Excel head 头 - * @param data 数据列表哦 - * @param selectMap 下拉选择数据 Map<下拉所对应的列表名,下拉数据> - * @throws IOException 写入失败的情况 - */ - public static void write(HttpServletResponse response, String filename, String sheetName, - Class head, List data, List>> selectMap) throws IOException { // 输出 Excel EasyExcel.write(response.getOutputStream(), head) .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 - .registerWriteHandler(new SelectSheetWriteHandler(selectMap)) // 基于固定 sheet 实现下拉框 + .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 .sheet(sheetName).doWrite(data); // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index e784447b25..eea4ed147e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -10,9 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.framework.ip.core.Area; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; @@ -38,7 +35,6 @@ import org.springframework.web.bind.annotation.*; import java.io.IOException; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -49,7 +45,6 @@ import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; import static java.util.Collections.singletonList; @Tag(name = "管理后台 - CRM 客户") @@ -266,25 +261,7 @@ public class CrmCustomerController { .areaId(null).detailAddress("").remark("").build() ); // 输出 - ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list, builderSelectMap()); - } - - private List>> builderSelectMap() { - List>> selectMap = new ArrayList<>(); - // 获取地区下拉数据 - // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? - Area area = AreaUtils.parseArea(Area.ID_CHINA); - selectMap.add(new KeyValue<>(ExcelColumn.G, AreaUtils.getAreaNodePathList(area.getChildren()))); - // 获取客户所属行业 - List customerIndustries = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); - selectMap.add(new KeyValue<>(ExcelColumn.I, customerIndustries)); - // 获取客户等级 - List customerLevels = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); - selectMap.add(new KeyValue<>(ExcelColumn.J, customerLevels)); - // 获取客户来源 - List customerSources = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); - selectMap.add(new KeyValue<>(ExcelColumn.K, customerSources)); - return selectMap; + ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list); } @PostMapping("/import") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java index 2c39472fd6..4b5fbefbd7 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java @@ -1,8 +1,13 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.crm.framework.excel.service.AreaExcelColumnSelectDataServiceImpl; +import cn.iocoder.yudao.module.crm.framework.excel.service.CrmCustomerIndustryExcelColumnSelectDataServiceImpl; +import cn.iocoder.yudao.module.crm.framework.excel.service.CrmCustomerLevelExcelColumnSelectDataServiceImpl; +import cn.iocoder.yudao.module.crm.framework.excel.service.CrmCustomerSourceExcelColumnSelectDataServiceImpl; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -41,6 +46,7 @@ public class CrmCustomerImportExcelVO { private String email; @ExcelProperty(value = "地区", converter = AreaConvert.class) + @ExcelColumnSelect(AreaExcelColumnSelectDataServiceImpl.FUNCTION_NAME) private Integer areaId; @ExcelProperty("详细地址") @@ -48,14 +54,17 @@ public class CrmCustomerImportExcelVO { @ExcelProperty(value = "所属行业", converter = DictConvert.class) @DictFormat(CRM_CUSTOMER_INDUSTRY) + @ExcelColumnSelect(CrmCustomerIndustryExcelColumnSelectDataServiceImpl.FUNCTION_NAME) private Integer industryId; @ExcelProperty(value = "客户等级", converter = DictConvert.class) @DictFormat(CRM_CUSTOMER_LEVEL) + @ExcelColumnSelect(CrmCustomerLevelExcelColumnSelectDataServiceImpl.FUNCTION_NAME) private Integer level; @ExcelProperty(value = "客户来源", converter = DictConvert.class) @DictFormat(CRM_CUSTOMER_SOURCE) + @ExcelColumnSelect(CrmCustomerSourceExcelColumnSelectDataServiceImpl.FUNCTION_NAME) private Integer source; @ExcelProperty("备注") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java new file mode 100644 index 0000000000..8b54b9f555 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.crm.framework.excel; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java new file mode 100644 index 0000000000..c6a6534498 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.crm.framework.excel.service; + +import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * Excel 所属地区列下拉数据源获取接口实现类 + * + * @author HUIHUI + */ +@Service +public class AreaExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { + + public static final String FUNCTION_NAME = "getCrmAreaNameList"; // 防止和别的模块重名 + + @Resource + private DictDataApi dictDataApi; + + @Override + public String getFunctionName() { + return FUNCTION_NAME; + } + + @Override + public List getSelectDataList() { + // 获取地区下拉数据 + // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? + Area area = AreaUtils.parseArea(Area.ID_CHINA); + return AreaUtils.getAreaNodePathList(area.getChildren()); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java new file mode 100644 index 0000000000..8a78104bf3 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.crm.framework.excel.service; + +import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; + +/** + * Excel 客户所属行业列下拉数据源获取接口实现类 + * + * @author HUIHUI + */ +@Service +public class CrmCustomerIndustryExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { + + public static final String FUNCTION_NAME = "getCrmCustomerIndustryList"; + + @Resource + private DictDataApi dictDataApi; + + @Override + public String getFunctionName() { + return FUNCTION_NAME; + } + + @Override + public List getSelectDataList() { + return dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java new file mode 100644 index 0000000000..5948aa4270 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.crm.framework.excel.service; + +import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL; + +/** + * Excel 客户等级列下拉数据源获取接口实现类 + * + * @author HUIHUI + */ +@Service +public class CrmCustomerLevelExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { + + public static final String FUNCTION_NAME = "getCrmCustomerLevelList"; + + @Resource + private DictDataApi dictDataApi; + + @Override + public String getFunctionName() { + return FUNCTION_NAME; + } + + @Override + public List getSelectDataList() { + return dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java new file mode 100644 index 0000000000..c160ed90fd --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.crm.framework.excel.service; + +import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE; + +/** + * Excel 客户来源列下拉数据源获取接口实现类 + * + * @author HUIHUI + */ +@Service +public class CrmCustomerSourceExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { + + public static final String FUNCTION_NAME = "getCrmCustomerSourceList"; + + @Resource + private DictDataApi dictDataApi; + + @Override + public String getFunctionName() { + return FUNCTION_NAME; + } + + @Override + public List getSelectDataList() { + return dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); + } + +} From c3337f21cebf86eae18b1ad9186e3d03b98840c4 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 28 Feb 2024 00:07:25 +0800 Subject: [PATCH 02/86] =?UTF-8?q?fix=EF=BC=9A=E4=B8=BB=E5=AD=90=E8=A1=A8?= =?UTF-8?q?=20props?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codegen/vue3/views/components/list_sub_erp.vue.vm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm index 71a7511beb..3f0710e01c 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm @@ -94,7 +94,7 @@ const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 const props = defineProps<{ - ${subJoinColumn.javaField}: undefined // ${subJoinColumn.columnComment}(主表的关联字段) + ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段) }>() const loading = ref(false) // 列表的加载中 const list = ref([]) // 列表的数据 @@ -103,17 +103,20 @@ const total = ref(0) // 列表的总页数 const queryParams = reactive({ pageNo: 1, pageSize: 10, - ${subJoinColumn.javaField}: undefined + ${subJoinColumn.javaField}: undefined as unknown }) /** 监听主表的关联字段的变化,加载对应的子表数据 */ watch( () => props.${subJoinColumn.javaField}, - (val) => { + (val: number) => { + if (!val) { + return + } queryParams.${subJoinColumn.javaField} = val handleQuery() }, - { immediate: false } + { immediate: true, deep: true } ) #end From 720b54c353cc199d86aae346ecacce7c471070f0 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 28 Feb 2024 11:25:06 +0800 Subject: [PATCH 03/86] =?UTF-8?q?CRM:=20=E5=AE=8C=E5=96=84=E5=9B=9E?= =?UTF-8?q?=E6=AC=BE=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/crm/enums/ErrorCodeConstants.java | 2 + .../module/crm/enums/LogRecordConstants.java | 6 +-- .../vo/plan/CrmReceivablePlanRespVO.java | 19 ++++++++- .../vo/receivable/CrmReceivableRespVO.java | 21 +++++++++- .../contract/CrmContractServiceImpl.java | 11 ++++- .../receivable/CrmReceivableService.java | 8 ++++ .../receivable/CrmReceivableServiceImpl.java | 40 +++++++++++++------ 7 files changed, 87 insertions(+), 20 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index a15a3211b4..5d942d8754 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -15,6 +15,7 @@ public interface ErrorCodeConstants { ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态"); ErrorCode CONTRACT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_000_003, "更新合同审核状态失败,原因:合同不是审核中状态"); ErrorCode CONTRACT_NO_EXISTS = new ErrorCode(1_020_000_004, "生成合同序列号重复,请重试"); + ErrorCode CONTRACT_DELETE_FAIL = new ErrorCode(1_020_000_005, "删除合同失败,原因:有被回款所使用"); // ========== 线索管理 1-020-001-000 ========== ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); @@ -40,6 +41,7 @@ public interface ErrorCodeConstants { ErrorCode RECEIVABLE_NO_EXISTS = new ErrorCode(1_020_004_005, "生成回款序列号重复,请重试"); ErrorCode RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE = new ErrorCode(1_020_004_006, "创建回款失败,原因:合同不是审核通过状态"); ErrorCode RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT = new ErrorCode(1_020_004_007, "创建回款失败,原因:回款金额超出合同金额,目前剩余可退:{} 元"); + ErrorCode RECEIVABLE_DELETE_FAIL_IS_APPROVE = new ErrorCode(1_020_004_008, "删除回款失败,原因:回款审批已通过"); // ========== 回款计划 1-020-005-000 ========== ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java index c2c835b7f1..aeeed316dd 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java @@ -142,11 +142,11 @@ public interface LogRecordConstants { String CRM_RECEIVABLE_TYPE = "CRM 回款"; String CRM_RECEIVABLE_CREATE_SUB_TYPE = "创建回款"; - String CRM_RECEIVABLE_CREATE_SUCCESS = "创建了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; + String CRM_RECEIVABLE_CREATE_SUCCESS = "创建了合同【{getContractById{#receivable.contractId}}】的{{#period != null ? '【第'+ #period +'期】' : '编号为【'+ #receivable.no +'】的'}}回款"; String CRM_RECEIVABLE_UPDATE_SUB_TYPE = "更新回款"; - String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款: {_DIFF{#updateReqVO}}"; + String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的{{#period != null ? '【第'+ #period +'期】' : '编号为【'+ #receivable.no +'】的'}}回款: {_DIFF{#updateReqVO}}"; String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; - String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; + String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的{{#period != null ? '【第'+ #period +'期】' : '编号为【'+ #receivable.no +'】的'}}回款"; String CRM_RECEIVABLE_SUBMIT_SUB_TYPE = "提交回款审批"; String CRM_RECEIVABLE_SUBMIT_SUCCESS = "提交编号为【{{#receivableNo}}】的回款审批成功"; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java index 1c58766e1e..ad1ce3a7b7 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -8,53 +9,69 @@ import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; -// TODO @puhui999:缺导出 @Schema(description = "管理后台 - CRM 回款计划 Response VO") @Data +@ExcelIgnoreUnannotated public class CrmReceivablePlanRespVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("编号") private Long id; @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("期数") private Integer period; @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("客户编号") private Long customerId; @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @ExcelProperty("客户名字") private String customerName; @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("合同编号") private Long contractId; @Schema(description = "合同编号", example = "Q110") + @ExcelProperty("合同编号") private String contractNo; @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("负责人编号") private Long ownerUserId; @Schema(description = "负责人", example = "test") + @ExcelProperty("负责人") private String ownerUserName; @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @ExcelProperty("计划回款日期") private LocalDateTime returnTime; @Schema(description = "计划回款方式", example = "1") + @ExcelProperty("计划回款方式") private Integer returnType; @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @ExcelProperty("计划回款金额") private BigDecimal price; @Schema(description = "回款编号", example = "19852") + @ExcelProperty("回款编号") private Long receivableId; @Schema(description = "回款信息") + @ExcelProperty("回款信息") private CrmReceivableRespVO receivable; @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("提前几天提醒") private Integer remindDays; @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @ExcelProperty("提醒日期") private LocalDateTime remindTime; @Schema(description = "备注", example = "备注") + @ExcelProperty("备注") private String remark; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java index a9fcb1b8b1..12dcbaa026 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -8,37 +9,47 @@ import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; -// TODO 芋艿:导出的 VO,可以考虑使用 @Excel 注解,实现导出功能 @Schema(description = "管理后台 - CRM 回款 Response VO") @Data +@ExcelIgnoreUnannotated public class CrmReceivableRespVO { @Schema(description = "编号", example = "25787") + @ExcelProperty("编号") private Long id; @Schema(description = "回款编号", example = "31177") + @ExcelProperty("回款编号") private String no; @Schema(description = "回款计划编号", example = "1024") + @ExcelProperty("回款计划编号") private Long planId; @Schema(description = "回款方式", example = "2") + @ExcelProperty("回款方式") private Integer returnType; @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @ExcelProperty("回款金额") private BigDecimal price; @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @ExcelProperty("计划回款日期") private LocalDateTime returnTime; @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("客户编号") private Long customerId; @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + @ExcelProperty("客户名字") private String customerName; @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("合同编号") private Long contractId; @Schema(description = "合同信息") + @ExcelProperty("合同信息") private CrmContractRespVO contract; @Schema(description = "负责人的用户编号", example = "25682") @@ -56,20 +67,26 @@ public class CrmReceivableRespVO { private String processInstanceId; @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty("审批状态") private Integer auditStatus; - @Schema(description = "备注", example = "备注") + @Schema(description = "工作流编号", example = "备注") + @ExcelProperty("工作流编号") private String remark; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") private LocalDateTime createTime; @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") private LocalDateTime updateTime; @Schema(description = "创建人", example = "25682") + @ExcelProperty("创建人") private String creator; @Schema(description = "创建人名字", example = "test") + @ExcelProperty("创建人名字") private String creatorName; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index e8a8dbf59f..8ef0d84bb5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -30,12 +30,14 @@ import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; import cn.iocoder.yudao.module.crm.service.product.CrmProductService; +import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import com.mzt.logapi.context.LogRecordContext; import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -86,7 +88,9 @@ public class CrmContractServiceImpl implements CrmContractService { private CrmContactService contactService; @Resource private CrmContractConfigService contractConfigService; - + @Resource + @Lazy // 延迟加载,避免循环依赖 + private CrmReceivableService receivableService; @Resource private AdminUserApi adminUserApi; @Resource @@ -222,9 +226,12 @@ public class CrmContractServiceImpl implements CrmContractService { success = CRM_CONTRACT_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteContract(Long id) { - // TODO @puhui999:如果被 CrmReceivableDO 所使用,则不允许删除 // 校验存在 CrmContractDO contract = validateContractExists(id); + // 如果被 CrmReceivableDO 所使用,则不允许删除 + if (CollUtil.isNotEmpty(receivableService.getReceivableByContractId(contract.getId()))) { + throw exception(CONTRACT_DELETE_FAIL); + } // 删除 contractMapper.deleteById(id); // 删除数据权限 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java index c0ca645b2b..a07f33a750 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java @@ -122,4 +122,12 @@ public interface CrmReceivableService { */ Map getReceivablePriceMapByContractId(Collection contractIds); + /** + * 更具合同编号查询回款列表 + * + * @param contractId 合同编号 + * @return 回款 + */ + List getReceivableByContractId(Long contractId); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index 7ef96effa4..516556bc96 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -37,10 +37,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; @@ -81,7 +78,6 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { @Resource private BpmProcessInstanceApi bpmProcessInstanceApi; - // TODO @puhui999:操作日志没记录上 @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}", @@ -115,6 +111,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { // 5. 记录操作日志上下文 LogRecordContext.putVariable("receivable", receivable); + LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); return receivable.getId(); } @@ -156,7 +153,6 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { } } - // TODO @puhui999:操作日志没记录上 @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", @@ -165,10 +161,13 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) { Assert.notNull(updateReqVO.getId(), "回款编号不能为空"); updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null).setPlanId(null); // 不允许修改的字段 - // 1.1 校验可回款金额超过上限 - validateReceivablePriceExceedsLimit(updateReqVO); - // 1.2 校验存在 + // 1.1 校验存在 CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId()); + updateReqVO.setOwnerUserId(receivable.getOwnerUserId()).setCustomerId(receivable.getCustomerId()) + .setContractId(receivable.getContractId()).setPlanId(receivable.getPlanId()); // 设置已存在的值 + // 1.2 校验可回款金额超过上限 + validateReceivablePriceExceedsLimit(updateReqVO); + // 1.3 只有草稿、审批中,可以编辑; if (!ObjectUtils.equalsAny(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) { @@ -180,8 +179,17 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { receivableMapper.updateById(updateObj); // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(receivable, CrmReceivableSaveReqVO.class)); LogRecordContext.putVariable("receivable", receivable); + LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(receivable, CrmReceivableSaveReqVO.class)); + } + + private Integer getReceivablePeriod(Long planId) { + if (Objects.isNull(planId)) { + return null; + } + CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(planId); + return receivablePlan.getPeriod(); } @Override @@ -212,8 +220,10 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { if (receivable.getPlanId() != null && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) { throw exception(RECEIVABLE_DELETE_FAIL); } - // TODO @puhui999:审批通过时,不允许删除; - + // 1.3 审批通过时,不允许删除 + if (ObjUtil.equal(receivable.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { + throw exception(RECEIVABLE_DELETE_FAIL_IS_APPROVE); + } // 2. 删除 receivableMapper.deleteById(id); // 3. 删除数据权限 @@ -221,6 +231,7 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { // 4. 记录操作日志上下文 LogRecordContext.putVariable("receivable", receivable); + LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); } @Override @@ -289,4 +300,9 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { return receivableMapper.selectReceivablePriceMapByContractId(contractIds); } + @Override + public List getReceivableByContractId(Long contractId) { + return receivableMapper.selectList(CrmReceivableDO::getContractId, contractId); + } + } From 7d120a2f3699d402c6f1d1424c57bee8fb27a78d Mon Sep 17 00:00:00 2001 From: dhb52 Date: Wed, 28 Feb 2024 21:41:10 +0800 Subject: [PATCH 04/86] =?UTF-8?q?feat:=20CRM/=E6=95=B0=E6=8D=AE=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1/=E5=AE=A2=E6=88=B7=E6=80=BB=E9=87=8F=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.http | 19 +++ .../CrmStatisticsCustomerController.java | 44 +++++++ .../CrmStatisticsCustomerCountVO.java | 28 ++++ .../customer/CrmStatisticsCustomerReqVO.java | 47 +++++++ .../CrmStatisticsCustomerMapper.java | 21 +++ .../CrmStatisticsCustomerService.java | 31 +++++ .../CrmStatisticsCustomerServiceImpl.java | 124 ++++++++++++++++++ .../CrmStatisticsCustomerMapper.xml | 46 +++++++ 8 files changed, 360 insertions(+) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http new file mode 100644 index 0000000000..70a4fd43d3 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http @@ -0,0 +1,19 @@ +### 新建客户总量分析(按日) +GET {{baseUrl}}/crm/statistics-customer/get-total-customer-count?deptId=100×[0]=2024-12-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 新建客户总量分析(按月) +GET {{baseUrl}}/crm/statistics-customer/get-total-customer-count?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 成交客户总量分析(按日) +GET {{baseUrl}}/crm/statistics-customer/get-deal-total-customer-count?deptId=100×[0]=2024-12-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + +### 成交客户总量分析(按月) +GET {{baseUrl}}/crm/statistics-customer/get-deal-total-customer-count?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java new file mode 100644 index 0000000000..cecddd294c --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 数据统计 员工客户分析") +@RestController +@RequestMapping("/crm/statistics-customer") +@Validated +public class CrmStatisticsCustomerController { + + @Resource + private CrmStatisticsCustomerService customerService; + + @GetMapping("/get-total-customer-count") + @Operation(summary = "获得新建客户数量") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getTotalCustomerCount(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getTotalCustomerCount(reqVO)); + } + + @GetMapping("/get-deal-total-customer-count") + @Operation(summary = "获得成交客户数量") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getDealTotalCustomerCount(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getDealTotalCustomerCount(reqVO)); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java new file mode 100644 index 0000000000..01dbd6fc2b --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +@Schema(description = "管理后台 - CRM 数据统计 员工客户分析 VO") +@Data +public class CrmStatisticsCustomerCountVO { + + /** + * 时间轴 + *

+ * group by DATE_FORMAT(create_date, '%Y%m') + */ + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String category; + + /** + * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义 + *

+ * 1. 金额:合同金额排行、回款金额排行 + * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 + */ + @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer count; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java new file mode 100644 index 0000000000..62828162b3 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 数据统计 员工客户分析 Request VO") +@Data +public class CrmStatisticsCustomerReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * 负责人用户 id, 当用户为空, 则计算部门下用户 + */ + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + *

+ * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") + private List userIds; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotEmpty(message = "时间范围不能为空") + private LocalDateTime[] times; + + /** + * group by DATE_FORMAT(field, #{dateFormat}) + */ + @Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m") + private String sqlDateFormat; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java new file mode 100644 index 0000000000..062110db8a --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 数据统计 员工客户分析 Mapper + * + * @author dhb52 + */ +@Mapper +public interface CrmStatisticsCustomerMapper { + + List selectCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + + List selectDealCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java new file mode 100644 index 0000000000..b1688b55be --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; + +import java.util.List; + +/** + * CRM 数据统计 员工客户分析 Service 接口 + * + * @author dhb52 + */ +public interface CrmStatisticsCustomerService { + + /** + * 获取新建客户数量 + * + * @param reqVO 请求参数 + * @return 新建客户数量统计 + */ + List getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取成交客户数量 + * + * @param reqVO 请求参数 + * @return 成交客户数量统计 + */ + List getDealTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java new file mode 100644 index 0000000000..e154382bee --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -0,0 +1,124 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; + +/** + * CRM 数据统计 员工客户分析 Service 实现类 + * + * @author dhb52 + */ +@Service +@Validated +public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerService { + + @Resource + private CrmStatisticsCustomerMapper customerMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Override + public List getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) { + return getStat(reqVO, customerMapper::selectCustomerCountGroupbyDate); + } + + @Override + public List getDealTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) { + return getStat(reqVO, customerMapper::selectDealCustomerCountGroupbyDate); + } + + /** + * 获得统计数据 + * + * @param reqVO 参数 + * @param statFunction 统计方法 + * @return 统计数据 + */ + private List getStat(CrmStatisticsCustomerReqVO reqVO, Function> statFunction) { + // 1. 获得用户编号数组: 如果用户编号为空, 则获得部门下的用户编号数组 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + reqVO.setUserIds(List.of(reqVO.getUserId())); + } else { + reqVO.setUserIds(getUserIds(reqVO.getDeptId())); + } + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 生成日期格式 + LocalDateTime startTime = reqVO.getTimes()[0]; + final LocalDateTime endTime = reqVO.getTimes()[1]; + final long days = LocalDateTimeUtil.between(startTime, endTime).toDays(); + boolean byMonth = days > 31; + if (byMonth) { + // 按月 + reqVO.setSqlDateFormat("%Y%m"); + } else { + // 按日 + reqVO.setSqlDateFormat("%Y%m%d"); + } + + // 3. 获得排行数据 + List stats = statFunction.apply(reqVO); + + // 4. 生成时间序列 + List result = CollUtil.newArrayList(); + while (startTime.compareTo(endTime) <= 0) { + final String category = LocalDateTimeUtil.format(startTime, byMonth ? "yyyyMM" : "yyyyMMdd"); + result.add(new CrmStatisticsCustomerCountVO().setCategory(category).setCount(0)); + if (byMonth) + startTime = startTime.plusMonths(1); + else + startTime = startTime.plusDays(1); + } + + // 5. 使用时间序列填充结果 + final Map statMap = convertMap(stats, + CrmStatisticsCustomerCountVO::getCategory, + CrmStatisticsCustomerCountVO::getCount); + result.forEach(r -> { + if (statMap.containsKey(r.getCategory())) { + r.setCount(statMap.get(r.getCategory())); + } + }); + + return result; + } + + + /** + * 获得部门下的用户编号数组,包括子部门的 + * + * @param deptId 部门编号 + * @return 用户编号数组 + */ + public List getUserIds(Long deptId) { + // 1. 获得部门列表 + List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); + deptIds.add(deptId); + // 2. 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml new file mode 100644 index 0000000000..e4d2487ce6 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + From a0b413b3a3cf42dc1ba3c238b436a2da3be7ed04 Mon Sep 17 00:00:00 2001 From: dhb52 Date: Wed, 28 Feb 2024 21:41:53 +0800 Subject: [PATCH 05/86] =?UTF-8?q?refactor:=20CRM/=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1/=E6=8E=92=E8=A1=8C=E6=A6=9C=20=E9=87=8D?= =?UTF-8?q?=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsRankController.java | 42 +++++++++---------- .../vo/{ => rank}/CrmStatisticsRankReqVO.java | 6 +-- .../CrmStatisticsRankRespVO.java} | 8 ++-- ...pper.java => CrmStatisticsRankMapper.java} | 24 +++++------ ...ice.java => CrmStatisticsRankService.java} | 24 +++++------ ...java => CrmStatisticsRankServiceImpl.java} | 40 +++++++++--------- .../CrmStatisticsRankMapper.xml} | 18 ++++---- 7 files changed, 81 insertions(+), 81 deletions(-) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/{ => rank}/CrmStatisticsRankReqVO.java (92%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/{CrmStatisticsRanKRespVO.java => rank/CrmStatisticsRankRespVO.java} (87%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/{CrmStatisticsRankingMapper.java => CrmStatisticsRankMapper.java} (70%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/{CrmStatisticsRankingService.java => CrmStatisticsRankService.java} (69%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/{CrmStatisticsRankingServiceImpl.java => CrmStatisticsRankServiceImpl.java} (77%) rename yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/{bi/CrmBiRankingMapper.xml => statistics/CrmStatisticsRankMapper.xml} (92%) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java index e4cf61f7a3..fe79b1d3c5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; -import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsRankingService; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsRankService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -19,69 +19,69 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Tag(name = "管理后台 - CRM 排行榜统计") +@Tag(name = "管理后台 - CRM 数据统计 排行榜统计") @RestController @RequestMapping("/crm/statistics-rank") @Validated public class CrmStatisticsRankController { @Resource - private CrmStatisticsRankingService rankingService; + private CrmStatisticsRankService rankService; @GetMapping("/get-contract-price-rank") @Operation(summary = "获得合同金额排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getContractPriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getContractPriceRank(rankingReqVO)); + public CommonResult> getContractPriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getContractPriceRank(rankingReqVO)); } @GetMapping("/get-receivable-price-rank") @Operation(summary = "获得回款金额排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getReceivablePriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getReceivablePriceRank(rankingReqVO)); + public CommonResult> getReceivablePriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getReceivablePriceRank(rankingReqVO)); } @GetMapping("/get-contract-count-rank") @Operation(summary = "获得签约合同数量排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getContractCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getContractCountRank(rankingReqVO)); + public CommonResult> getContractCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getContractCountRank(rankingReqVO)); } @GetMapping("/get-product-sales-rank") @Operation(summary = "获得产品销量排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getProductSalesRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getProductSalesRank(rankingReqVO)); + public CommonResult> getProductSalesRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getProductSalesRank(rankingReqVO)); } @GetMapping("/get-customer-count-rank") @Operation(summary = "获得新增客户数排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getCustomerCountRank(rankingReqVO)); + public CommonResult> getCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getCustomerCountRank(rankingReqVO)); } @GetMapping("/get-contacts-count-rank") @Operation(summary = "获得新增联系人数排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getContactsCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getContactsCountRank(rankingReqVO)); + public CommonResult> getContactsCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getContactsCountRank(rankingReqVO)); } @GetMapping("/get-follow-count-rank") @Operation(summary = "获得跟进次数排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getFollowCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getFollowCountRank(rankingReqVO)); + public CommonResult> getFollowCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getFollowCountRank(rankingReqVO)); } @GetMapping("/get-follow-customer-count-rank") @Operation(summary = "获得跟进客户数排行榜") @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getFollowCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getFollowCustomerCountRank(rankingReqVO)); + public CommonResult> getFollowCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { + return success(rankService.getFollowCustomerCountRank(rankingReqVO)); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java similarity index 92% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java index 487921957c..5bd5ec295e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo; +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; @@ -11,7 +11,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -@Schema(description = "管理后台 - CRM 排行榜统计 Request VO") +@Schema(description = "管理后台 - CRM 数据统计 排行榜统计 Request VO") @Data public class CrmStatisticsRankReqVO { @@ -21,7 +21,7 @@ public class CrmStatisticsRankReqVO { /** * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 - * + *

* 后续,可能会支持选择部分用户进行查询 */ @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java similarity index 87% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java index d5c865fd34..86260e74ef 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java @@ -1,12 +1,12 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo; +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Schema(description = "管理后台 - CRM BI 排行榜统计 Response VO") +@Schema(description = "管理后台 - CRM 数据统计 排行榜统计 Response VO") @Data -public class CrmStatisticsRanKRespVO { +public class CrmStatisticsRankRespVO { @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long ownerUserId; @@ -19,7 +19,7 @@ public class CrmStatisticsRanKRespVO { /** * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义 - * + *

* 1. 金额:合同金额排行、回款金额排行 * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankingMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java similarity index 70% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankingMapper.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java index 4b51ab2fe9..b63e42ab83 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankingMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java @@ -1,18 +1,18 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; import org.apache.ibatis.annotations.Mapper; import java.util.List; /** - * CRM 排行榜统计 Mapper + * CRM 数据统计 排行榜统计 Mapper * * @author anhaohao */ @Mapper -public interface CrmStatisticsRankingMapper { +public interface CrmStatisticsRankMapper { /** * 查询合同金额排行榜 @@ -20,7 +20,7 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 合同金额排行榜 */ - List selectContractPriceRank(CrmStatisticsRankReqVO rankReqVO); + List selectContractPriceRank(CrmStatisticsRankReqVO rankReqVO); /** * 查询回款金额排行榜 @@ -28,7 +28,7 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 回款金额排行榜 */ - List selectReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); + List selectReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); /** * 查询签约合同数量排行榜 @@ -36,7 +36,7 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 签约合同数量排行榜 */ - List selectContractCountRank(CrmStatisticsRankReqVO rankReqVO); + List selectContractCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 查询产品销量排行榜 @@ -44,7 +44,7 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 产品销量排行榜 */ - List selectProductSalesRank(CrmStatisticsRankReqVO rankReqVO); + List selectProductSalesRank(CrmStatisticsRankReqVO rankReqVO); /** * 查询新增客户数排行榜 @@ -52,7 +52,7 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 新增客户数排行榜 */ - List selectCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + List selectCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 查询联系人数量排行榜 @@ -60,7 +60,7 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 联系人数量排行榜 */ - List selectContactsCountRank(CrmStatisticsRankReqVO rankReqVO); + List selectContactsCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 查询跟进次数排行榜 @@ -68,7 +68,7 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 跟进次数排行榜 */ - List selectFollowCountRank(CrmStatisticsRankReqVO rankReqVO); + List selectFollowCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 查询跟进客户数排行榜 @@ -76,6 +76,6 @@ public interface CrmStatisticsRankingMapper { * @param rankReqVO 参数 * @return 跟进客户数排行榜 */ - List selectFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + List selectFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java similarity index 69% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingService.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java index c9455708c1..f985f53f9d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java @@ -1,17 +1,17 @@ package cn.iocoder.yudao.module.crm.service.statistics; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; import java.util.List; /** - * CRM 排行榜统计 Service 接口 + * CRM 数据统计 排行榜统计 Service 接口 * * @author anhaohao */ -public interface CrmStatisticsRankingService { +public interface CrmStatisticsRankService { /** * 获得合同金额排行榜 @@ -19,7 +19,7 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 合同金额排行榜 */ - List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO); + List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO); /** * 获得回款金额排行榜 @@ -27,7 +27,7 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 回款金额排行榜 */ - List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); + List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); /** * 获得签约合同数量排行榜 @@ -35,7 +35,7 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 签约合同数量排行榜 */ - List getContractCountRank(CrmStatisticsRankReqVO rankReqVO); + List getContractCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 获得产品销量排行榜 @@ -43,7 +43,7 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 产品销量排行榜 */ - List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO); + List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO); /** * 获得新增客户数排行榜 @@ -51,7 +51,7 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 新增客户数排行榜 */ - List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 获得联系人数量排行榜 @@ -59,7 +59,7 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 联系人数量排行榜 */ - List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO); + List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 获得跟进次数排行榜 @@ -67,7 +67,7 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 跟进次数排行榜 */ - List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO); + List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO); /** * 获得跟进客户数排行榜 @@ -75,6 +75,6 @@ public interface CrmStatisticsRankingService { * @param rankReqVO 排行参数 * @return 跟进客户数排行榜 */ - List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); + List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java similarity index 77% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingServiceImpl.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java index 428ec17637..ff2acfef5d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java @@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; -import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsRankingMapper; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsRankMapper; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -23,16 +23,16 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; /** - * CRM 排行榜统计 Service 实现类 + * CRM 数据统计 排行榜统计 Service 实现类 * * @author anhaohao */ @Service @Validated -public class CrmStatisticsRankingServiceImpl implements CrmStatisticsRankingService { +public class CrmStatisticsRankServiceImpl implements CrmStatisticsRankService { @Resource - private CrmStatisticsRankingMapper rankMapper; + private CrmStatisticsRankMapper rankMapper; @Resource private AdminUserApi adminUserApi; @@ -40,64 +40,64 @@ public class CrmStatisticsRankingServiceImpl implements CrmStatisticsRankingServ private DeptApi deptApi; @Override - public List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO) { + public List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectContractPriceRank); } @Override - public List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO) { + public List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectReceivablePriceRank); } @Override - public List getContractCountRank(CrmStatisticsRankReqVO rankReqVO) { + public List getContractCountRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectContractCountRank); } @Override - public List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO) { + public List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectProductSalesRank); } @Override - public List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { + public List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectCustomerCountRank); } @Override - public List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO) { + public List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectContactsCountRank); } @Override - public List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO) { + public List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectFollowCountRank); } @Override - public List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { + public List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { return getRank(rankReqVO, rankMapper::selectFollowCustomerCountRank); } /** * 获得排行版数据 * - * @param rankReqVO 参数 + * @param rankReqVO 参数 * @param rankFunction 排行榜方法 * @return 排行版数据 */ - private List getRank(CrmStatisticsRankReqVO rankReqVO, Function> rankFunction) { + private List getRank(CrmStatisticsRankReqVO rankReqVO, Function> rankFunction) { // 1. 获得用户编号数组 rankReqVO.setUserIds(getUserIds(rankReqVO.getDeptId())); if (CollUtil.isEmpty(rankReqVO.getUserIds())) { return Collections.emptyList(); } // 2. 获得排行数据 - List ranks = rankFunction.apply(rankReqVO); + List ranks = rankFunction.apply(rankReqVO); if (CollUtil.isEmpty(ranks)) { return Collections.emptyList(); } - ranks.sort(Comparator.comparing(CrmStatisticsRanKRespVO::getCount).reversed()); + ranks.sort(Comparator.comparing(CrmStatisticsRankRespVO::getCount).reversed()); // 3. 拼接用户信息 appendUserInfo(ranks); return ranks; @@ -108,8 +108,8 @@ public class CrmStatisticsRankingServiceImpl implements CrmStatisticsRankingServ * * @param ranks 排行榜数据 */ - private void appendUserInfo(List ranks) { - Map userMap = adminUserApi.getUserMap(convertSet(ranks, CrmStatisticsRanKRespVO::getOwnerUserId)); + private void appendUserInfo(List ranks) { + Map userMap = adminUserApi.getUserMap(convertSet(ranks, CrmStatisticsRankRespVO::getOwnerUserId)); Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); ranks.forEach(rank -> MapUtils.findAndThen(userMap, rank.getOwnerUserId(), user -> { rank.setNickname(user.getNickname()); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml similarity index 92% rename from yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml rename to yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml index c193873ce0..c82c554120 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml @@ -1,9 +1,9 @@ - + + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatisticsRankRespVO"> SELECT COUNT(1) AS count, owner_user_id FROM crm_contract WHERE deleted = 0 @@ -64,7 +64,7 @@ + + + + From 34f68ce4c63876b02484ba30aab5b37364663232 Mon Sep 17 00:00:00 2001 From: dhb52 Date: Fri, 1 Mar 2024 00:10:23 +0800 Subject: [PATCH 07/86] =?UTF-8?q?feat:=20CRM/=E6=95=B0=E6=8D=AE=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1/=E5=91=98=E5=B7=A5=E5=AE=A2=E6=88=B7=E5=88=86?= =?UTF-8?q?=E6=9E=90=20=E5=88=9D=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.java | 14 +++++ .../CrmStatisticsCustomerCountVO.java | 8 ++- .../CrmStatisticsCustomerMapper.java | 4 ++ .../CrmStatisticsCustomerService.java | 16 ++++++ .../CrmStatisticsCustomerServiceImpl.java | 53 +++++++++++++++--- .../CrmStatisticsCustomerMapper.xml | 55 +++++++++++++++---- 6 files changed, 130 insertions(+), 20 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index ffd88e97ae..5644c512bd 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -55,4 +55,18 @@ public class CrmStatisticsCustomerController { return success(customerService.getDistinctRecordCount(reqVO)); } + @GetMapping("/get-record-type-count") + @Operation(summary = "获取客户跟进方式统计数") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getRecordTypeCount(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getRecordTypeCount(reqVO)); + } + + @GetMapping("/get-customer-cycle") + @Operation(summary = "获取客户成交周期") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerCycle(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerCycle(reqVO)); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java index 01dbd6fc2b..a2537db9aa 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java @@ -23,6 +23,12 @@ public class CrmStatisticsCustomerCountVO { * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 */ @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer count; + private Integer count = 0; + + /** + * 成交周期(天) + */ + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") + private Double cycle = 0.0; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 1be2dc1ff8..464c521c61 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -22,4 +22,8 @@ public interface CrmStatisticsCustomerMapper { List selectDistinctRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + List selectRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO); + + List selectCustomerCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index 908f02c99a..e568816d6a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -45,4 +45,20 @@ public interface CrmStatisticsCustomerService { */ List getDistinctRecordCount(CrmStatisticsCustomerReqVO reqVO); + /** + * 获取客户跟进方式统计数 + * + * @param reqVO 请求参数 + * @return 客户跟进方式统计数 + */ + List getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取客户成交周期 + * + * @param reqVO 请求参数 + * @return 客户成交周期 + */ + List getCustomerCycle(CrmStatisticsCustomerReqVO reqVO); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index 08cd1c4809..94eb560d1e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -3,12 +3,14 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; @@ -21,7 +23,8 @@ import java.util.List; import java.util.Map; import java.util.function.Function; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * CRM 数据统计 员工客户分析 Service 实现类 @@ -39,6 +42,8 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; + @Resource + private DictDataApi dictDataApi; @Override public List getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) { @@ -62,6 +67,37 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe return getStat(reqVO, customerMapper::selectDistinctRecordCountGroupbyDate); } + @Override + public List getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组: 如果用户编号为空, 则获得部门下的用户编号数组 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + reqVO.setUserIds(List.of(reqVO.getUserId())); + } else { + reqVO.setUserIds(getUserIds(reqVO.getDeptId())); + } + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 获得排行数据 + reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); + List stats = customerMapper.selectRecordCountGroupbyType(reqVO); + + // 3. 获取字典数据 + List followUpTypes = dictDataApi.getDictDataList("crm_follow_up_type"); + final Map followUpTypeMap = convertMap(followUpTypes, DictDataRespDTO::getValue, DictDataRespDTO::getLabel); + stats.forEach(stat -> { + stat.setCategory(followUpTypeMap.get(stat.getCategory())); + }); + + return stats; + } + + @Override + public List getCustomerCycle(CrmStatisticsCustomerReqVO reqVO) { + return getStat(reqVO, customerMapper::selectCustomerCycleGroupbyDate); + } + /** * 获得统计数据 * @@ -98,9 +134,9 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 4. 生成时间序列 List result = CollUtil.newArrayList(); - while (startTime.compareTo(endTime) <= 0) { + while (!startTime.isAfter(endTime)) { final String category = LocalDateTimeUtil.format(startTime, byMonth ? "yyyyMM" : "yyyyMMdd"); - result.add(new CrmStatisticsCustomerCountVO().setCategory(category).setCount(0)); + result.add(new CrmStatisticsCustomerCountVO().setCategory(category)); if (byMonth) startTime = startTime.plusMonths(1); else @@ -108,12 +144,13 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe } // 5. 使用时间序列填充结果 - final Map statMap = convertMap(stats, - CrmStatisticsCustomerCountVO::getCategory, - CrmStatisticsCustomerCountVO::getCount); + final Map statMap = convertMap(stats, + CrmStatisticsCustomerCountVO::getCategory, + Function.identity()); result.forEach(r -> { if (statMap.containsKey(r.getCategory())) { - r.setCount(statMap.get(r.getCategory())); + r.setCount(statMap.get(r.getCategory()).getCount()) + .setCycle(statMap.get(r.getCategory()).getCycle()); } }); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index cbc87f59f3..06affccabb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -6,8 +6,8 @@ + + + + From a787f2a0cd17164f6cb72b417ba6dc150657bd3a Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Fri, 1 Mar 2024 18:57:12 +0800 Subject: [PATCH 08/86] =?UTF-8?q?fix:=E7=A7=AF=E6=9C=A8=E6=8A=A5=E8=A1=A8?= =?UTF-8?q?=E5=AF=BC=E5=87=BAExcel=E6=8A=A5=E9=94=99=EF=BC=88=E5=8C=85?= =?UTF-8?q?=E5=86=B2=E7=AA=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 16 ++++++++-------- .../yudao-module-report-biz/pom.xml | 10 ++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 3a66524bc1..8933d64a10 100644 --- a/pom.xml +++ b/pom.xml @@ -15,14 +15,14 @@ yudao-module-system yudao-module-infra - - - - - - - - + yudao-module-member + yudao-module-bpm + yudao-module-report + yudao-module-mp + yudao-module-pay + yudao-module-mall + yudao-module-crm + yudao-module-erp diff --git a/yudao-module-report/yudao-module-report-biz/pom.xml b/yudao-module-report/yudao-module-report-biz/pom.xml index 62aeb3ee01..f38b38e751 100644 --- a/yudao-module-report/yudao-module-report-biz/pom.xml +++ b/yudao-module-report/yudao-module-report-biz/pom.xml @@ -77,6 +77,16 @@ com.bstek.ureport ureport2-console + + + org.apache.poi + poi + + + org.apache.poi + poi-ooxml + + From 01695567a1ed9f27357b70b0e61f95a3be533b85 Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Fri, 1 Mar 2024 18:59:11 +0800 Subject: [PATCH 09/86] re --- pom.xml | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index 8933d64a10..094dc5433b 100644 --- a/pom.xml +++ b/pom.xml @@ -15,16 +15,16 @@ yudao-module-system yudao-module-infra - yudao-module-member - yudao-module-bpm - yudao-module-report - yudao-module-mp - yudao-module-pay - yudao-module-mall - yudao-module-crm - yudao-module-erp + + + + + + + + - + ${project.artifactId} @@ -32,17 +32,17 @@ https://github.com/YunaiV/ruoyi-vue-pro - 2.0.1-snapshot + 2.0.1-jdk8-snapshot - 21 + 1.8 ${java.version} ${java.version} - 3.2.2 - 3.11.0 + 3.0.0-M5 + 3.8.1 1.5.0 1.18.30 - 3.2.2 + 2.7.18 1.5.5.Final UTF-8 @@ -93,11 +93,6 @@ ${mapstruct.version} - - false - - -parameters - From 6846d429c0c0fab746c588e02769194567cc2fad Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Fri, 1 Mar 2024 18:59:49 +0800 Subject: [PATCH 10/86] re --- yudao-module-report/yudao-module-report-biz/pom.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/yudao-module-report/yudao-module-report-biz/pom.xml b/yudao-module-report/yudao-module-report-biz/pom.xml index f38b38e751..62aeb3ee01 100644 --- a/yudao-module-report/yudao-module-report-biz/pom.xml +++ b/yudao-module-report/yudao-module-report-biz/pom.xml @@ -77,16 +77,6 @@ com.bstek.ureport ureport2-console - - - org.apache.poi - poi - - - org.apache.poi - poi-ooxml - - From 7841fba59bb70071ead10de00bc413a409d9fea2 Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Fri, 1 Mar 2024 19:00:10 +0800 Subject: [PATCH 11/86] =?UTF-8?q?fix:=E7=A7=AF=E6=9C=A8=E6=8A=A5=E8=A1=A8?= =?UTF-8?q?=E5=AF=BC=E5=87=BAExcel=E6=8A=A5=E9=94=99=EF=BC=88=E5=8C=85?= =?UTF-8?q?=E5=86=B2=E7=AA=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-report/yudao-module-report-biz/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/yudao-module-report/yudao-module-report-biz/pom.xml b/yudao-module-report/yudao-module-report-biz/pom.xml index 62aeb3ee01..f38b38e751 100644 --- a/yudao-module-report/yudao-module-report-biz/pom.xml +++ b/yudao-module-report/yudao-module-report-biz/pom.xml @@ -77,6 +77,16 @@ com.bstek.ureport ureport2-console + + + org.apache.poi + poi + + + org.apache.poi + poi-ooxml + + From 0bd7d310a18d66df2d1b24bf7414ef2d65313262 Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Fri, 1 Mar 2024 19:05:54 +0800 Subject: [PATCH 12/86] pom --- pom.xml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 094dc5433b..439120219a 100644 --- a/pom.xml +++ b/pom.xml @@ -32,17 +32,17 @@ https://github.com/YunaiV/ruoyi-vue-pro - 2.0.1-jdk8-snapshot + 2.0.1-snapshot - 1.8 + 21 ${java.version} ${java.version} - 3.0.0-M5 - 3.8.1 + 3.2.2 + 3.11.0 1.5.0 1.18.30 - 2.7.18 + 3.2.2 1.5.5.Final UTF-8 @@ -93,6 +93,11 @@ ${mapstruct.version} + + false + + -parameters + From ca7b19c40b3f2723678c005745cde611b2e8112a Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Fri, 1 Mar 2024 19:06:24 +0800 Subject: [PATCH 13/86] pom --- pom.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 439120219a..3a66524bc1 100644 --- a/pom.xml +++ b/pom.xml @@ -15,16 +15,16 @@ yudao-module-system yudao-module-infra - - - - - - - - + + + + + + + + - + ${project.artifactId} From 379bd958400c43c3f4844b15b0ec1f4f91fd9ae2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 1 Mar 2024 23:37:07 +0800 Subject: [PATCH 14/86] =?UTF-8?q?CRM=EF=BC=9Acode=20review=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E5=88=86=E6=9E=90=EF=BC=88=E5=AE=A2=E6=88=B7=E6=80=BB?= =?UTF-8?q?=E9=87=8F=E5=88=86=E6=9E=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/statistics/CrmStatisticsCustomerController.java | 5 +++++ .../admin/statistics/CrmStatisticsRankController.java | 2 +- .../admin/statistics/vo/rank/CrmStatisticsRankReqVO.java | 2 +- .../admin/statistics/vo/rank/CrmStatisticsRankRespVO.java | 2 +- .../crm/dal/mysql/statistics/CrmStatisticsRankMapper.java | 2 +- .../crm/service/statistics/CrmStatisticsRankService.java | 2 +- .../crm/service/statistics/CrmStatisticsRankServiceImpl.java | 2 +- 7 files changed, 11 insertions(+), 6 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index 5644c512bd..b51740dafa 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -18,6 +18,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +// TODO @dhb52:数据统计 员工客户分析,改成“客户统计” @Tag(name = "管理后台 - CRM 数据统计 员工客户分析") @RestController @RequestMapping("/crm/statistics-customer") @@ -27,6 +28,10 @@ public class CrmStatisticsCustomerController { @Resource private CrmStatisticsCustomerService customerService; + // TODO @dhb52:建议 getCustomerCount 和 getDealTotalCustomerCount 搞成一个接口; + // 1. 数量接口:【方法:getCustomerSummaryByDate】,VO:CrmStatisticsCustomerSummaryByDateRespVO,然后里面是 time、customerCreateCount customerDealCount + // 2. 按人统计:【方法:getCustomerSummaryByUser】,VO:CrmStatisticsCustomerSummaryByOwnerRespVO,然后里面是 ownerUserId、ownerUserName、customerCreateCount customerDealCount、contractPrice、receivablePrice;客户成交率、未回款金额、回款完成率,交给前端计算; + @GetMapping("/get-total-customer-count") @Operation(summary = "获得新建客户数量") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java index fe79b1d3c5..f3757ea28c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java @@ -19,7 +19,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Tag(name = "管理后台 - CRM 数据统计 排行榜统计") +@Tag(name = "管理后台 - CRM 排行榜统计") @RestController @RequestMapping("/crm/statistics-rank") @Validated diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java index 5bd5ec295e..c9b1ae7e76 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankReqVO.java @@ -11,7 +11,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -@Schema(description = "管理后台 - CRM 数据统计 排行榜统计 Request VO") +@Schema(description = "管理后台 - CRM 排行榜统计 Request VO") @Data public class CrmStatisticsRankReqVO { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java index 86260e74ef..101cd8bccf 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Schema(description = "管理后台 - CRM 数据统计 排行榜统计 Response VO") +@Schema(description = "管理后台 - CRM 排行榜统计 Response VO") @Data public class CrmStatisticsRankRespVO { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java index b63e42ab83..d58241cf87 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankMapper.java @@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; /** - * CRM 数据统计 排行榜统计 Mapper + * CRM 排行榜统计 Mapper * * @author anhaohao */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java index f985f53f9d..2fc8a5be9d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankService.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank.CrmStatis import java.util.List; /** - * CRM 数据统计 排行榜统计 Service 接口 + * CRM 排行榜统计 Service 接口 * * @author anhaohao */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java index ff2acfef5d..e591c35c0c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankServiceImpl.java @@ -23,7 +23,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; /** - * CRM 数据统计 排行榜统计 Service 实现类 + * CRM 排行榜统计 Service 实现类 * * @author anhaohao */ From 1f35ef59d11a1c1d96a102aa770d5f88d79ddbfc Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 2 Mar 2024 00:25:51 +0800 Subject: [PATCH 15/86] =?UTF-8?q?CRM=EF=BC=9Acode=20review=20excel=20?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E7=9A=84=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/core/handler/SelectSheetWriteHandler.java | 8 ++++++++ .../core/service/ExcelColumnSelectDataService.java | 5 +++++ .../module/crm/framework/excel/package-info.java | 1 + .../service/AreaExcelColumnSelectDataServiceImpl.java | 7 +------ .../crm/service/contract/CrmContractServiceImpl.java | 11 ++++++----- .../crm/service/receivable/CrmReceivableService.java | 1 + .../service/receivable/CrmReceivableServiceImpl.java | 7 ++++--- 7 files changed, 26 insertions(+), 14 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java index 421c592009..c50158de31 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.excel.core.handler; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.poi.excel.ExcelUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; @@ -27,7 +28,9 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. */ public class SelectSheetWriteHandler implements SheetWriteHandler { + // TODO @puhui999:注释哈; private static final List ALPHABET = getExcelColumnNameList(); + private static final List EXCEL_COLUMN_SELECT_DATA_SERVICES = new ArrayList<>(); /** @@ -43,6 +46,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { private static final String DICT_SHEET_NAME = "字典sheet"; + // TODO @puhui999:这个 selectMap 可以改成 Map>,然后在 afterSheetCreate 里面进行排序。这样整体的理解成本会更简单 private final List>> selectMap = new ArrayList<>(); // 使用 List + KeyValue 组合方便排序 public SelectSheetWriteHandler(Class head) { @@ -51,11 +55,14 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { if (MapUtil.isEmpty(beansMap)) { return; } + // TODO @puhui999:static 是共享。如果并发情况下,会不会存在问题? 其实 EXCEL_COLUMN_SELECT_DATA_SERVICES 不用全局声明,直接 按照 ExcelColumnSelect 去拿下就好了; if (CollUtil.isEmpty(EXCEL_COLUMN_SELECT_DATA_SERVICES) || EXCEL_COLUMN_SELECT_DATA_SERVICES.size() != beansMap.values().size()) { EXCEL_COLUMN_SELECT_DATA_SERVICES.clear(); EXCEL_COLUMN_SELECT_DATA_SERVICES.addAll(convertList(beansMap.values(), b -> b)); } + // 解析下拉数据 + // TODO @puhui999:感觉可以 head 循环 field,如果有 ExcelColumnSelect 则进行处理;而 ExcelProperty 可能是非必须的 Map excelPropertyFields = getFieldsWithAnnotation(head, ExcelProperty.class); Map excelColumnSelectFields = getFieldsWithAnnotation(head, ExcelColumnSelect.class); int colIndex = 0; @@ -157,6 +164,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { private static List getExcelColumnNameList() { + // TODO @puhui999:是不是可以使用 ExcelUtil.indexToColName() 替代 ArrayList strings = new ArrayList<>(); for (int i = 1; i <= 52; i++) { // 生成 52 列名称,需要更多请重写此方法 if (i <= 26) { diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java index 987cf79298..c4dc6e3bc1 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java @@ -9,11 +9,14 @@ import java.util.List; * Excel 列下拉数据源获取接口 * * 为什么不直接解析字典还搞个接口?考虑到有的下拉数据不是从字典中获取的所有需要做一个兼容 + * TODO @puhui999:是不是 @ExcelColumnSelect 可以搞两个属性,一个 dictType,一个 functionName;如果 dictType,则默认走字典,否则走 functionName + * 这样的话,ExcelColumnSelectDataService 改成 ExcelColumnSelectFunction 用于获取数据。 * * @author HUIHUI */ public interface ExcelColumnSelectDataService { + // TODO @puhui999:可以考虑改成 getName /** * 获得方法名称 * @@ -21,6 +24,7 @@ public interface ExcelColumnSelectDataService { */ String getFunctionName(); + // TODO @puhui999:可以考虑改成 getOptions;因为 select 下面是 option 哈,和前端 html 类似的标签; /** * 获得列下拉数据源 * @@ -28,6 +32,7 @@ public interface ExcelColumnSelectDataService { */ List getSelectDataList(); + // TODO @puhui999:这个建议放到 SelectSheetWriteHandler 里 default List handle(String funcName) { if (StrUtil.isEmptyIfStr(funcName) || !StrUtil.equals(getFunctionName(), funcName)) { return Collections.emptyList(); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java index 8b54b9f555..bd9cb957a7 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java @@ -1 +1,2 @@ +// TODO @puhui999:在 framework 目录,保持 config 和 core 目录的风格哈; package cn.iocoder.yudao.module.crm.framework.excel; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java index c6a6534498..bd2bbd9e99 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.crm.framework.excel.service; import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; import cn.iocoder.yudao.framework.ip.core.Area; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import java.util.List; @@ -19,9 +17,6 @@ public class AreaExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDa public static final String FUNCTION_NAME = "getCrmAreaNameList"; // 防止和别的模块重名 - @Resource - private DictDataApi dictDataApi; - @Override public String getFunctionName() { return FUNCTION_NAME; @@ -31,7 +26,7 @@ public class AreaExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDa public List getSelectDataList() { // 获取地区下拉数据 // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? - Area area = AreaUtils.parseArea(Area.ID_CHINA); + Area area = AreaUtils.getArea(Area.ID_CHINA); return AreaUtils.getAreaNodePathList(area.getChildren()); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index ec12acfd53..1a8772415b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -226,18 +226,19 @@ public class CrmContractServiceImpl implements CrmContractService { success = CRM_CONTRACT_DELETE_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteContract(Long id) { - // 校验存在 + // 1.1 校验存在 CrmContractDO contract = validateContractExists(id); - // 如果被 CrmReceivableDO 所使用,则不允许删除 + // 1.2 如果被 CrmReceivableDO 所使用,则不允许删除 if (CollUtil.isNotEmpty(receivableService.getReceivableByContractId(contract.getId()))) { throw exception(CONTRACT_DELETE_FAIL); } - // 删除 + + // 2.1 删除合同 contractMapper.deleteById(id); - // 删除数据权限 + // 2.2 删除数据权限 crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CONTRACT.getType(), id); - // 记录操作日志上下文 + // 3. 记录操作日志上下文 LogRecordContext.putVariable("contractName", contract.getName()); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java index a07f33a750..ed84ad03f9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java @@ -122,6 +122,7 @@ public interface CrmReceivableService { */ Map getReceivablePriceMapByContractId(Collection contractIds); + // TODO @puhui999:这个搞成根据数量判断,会更好一点哈; /** * 更具合同编号查询回款列表 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index 516556bc96..52db93273e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -224,12 +224,13 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { if (ObjUtil.equal(receivable.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { throw exception(RECEIVABLE_DELETE_FAIL_IS_APPROVE); } - // 2. 删除 + + // 2.1 删除回款 receivableMapper.deleteById(id); - // 3. 删除数据权限 + // 2.2 删除数据权限 permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id); - // 4. 记录操作日志上下文 + // 3. 记录操作日志上下文 LogRecordContext.putVariable("receivable", receivable); LogRecordContext.putVariable("period", getReceivablePeriod(receivable.getPlanId())); } From 1e13365ef4fee023ff119b92b7b5e2defa6f5158 Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Sat, 2 Mar 2024 13:23:54 +0800 Subject: [PATCH 16/86] pom --- yudao-module-report/yudao-module-report-biz/pom.xml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/yudao-module-report/yudao-module-report-biz/pom.xml b/yudao-module-report/yudao-module-report-biz/pom.xml index f38b38e751..62aeb3ee01 100644 --- a/yudao-module-report/yudao-module-report-biz/pom.xml +++ b/yudao-module-report/yudao-module-report-biz/pom.xml @@ -77,16 +77,6 @@ com.bstek.ureport ureport2-console - - - org.apache.poi - poi - - - org.apache.poi - poi-ooxml - - From 29b7106985719aa727364236eff6a1185c9680fb Mon Sep 17 00:00:00 2001 From: zhanhong <283456800@qq.com> Date: Sat, 2 Mar 2024 13:26:05 +0800 Subject: [PATCH 17/86] =?UTF-8?q?fix:=E5=8C=85=E5=86=B2=E7=AA=81=20?= =?UTF-8?q?=E7=A7=AF=E6=9C=A8=E6=8A=A5=E8=A1=A8=20=E5=AF=BC=E5=87=BAExcel?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 7c7ca609be..c9667aea2d 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -626,6 +626,16 @@ com.bstek.ureport ureport2-console ${ureport2.version} + + + org.apache.poi + poi + + + org.apache.poi + poi-ooxml + + From f56fab932a34369b49457de7ab1569cd966710e9 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 2 Mar 2024 23:24:42 +0800 Subject: [PATCH 18/86] =?UTF-8?q?CRM=EF=BC=9A=E5=AE=8C=E5=96=84=20excel=20?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=20review=20=E6=8F=90=E5=88=B0=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dict/core/DictFrameworkUtils.java | 22 ++++++ .../core/annotations/ExcelColumnSelect.java | 7 +- .../function/ExcelColumnSelectFunction.java | 28 +++++++ .../core/handler/SelectSheetWriteHandler.java | 75 ++++++++++--------- .../service/ExcelColumnSelectDataService.java | 43 ----------- .../vo/customer/CrmCustomerImportExcelVO.java | 13 ++-- .../AreaExcelColumnSelectFunctionImpl.java} | 14 ++-- .../crm/framework/excel/package-info.java | 1 - ...ustryExcelColumnSelectDataServiceImpl.java | 35 --------- ...LevelExcelColumnSelectDataServiceImpl.java | 35 --------- ...ourceExcelColumnSelectDataServiceImpl.java | 35 --------- .../contract/CrmContractServiceImpl.java | 2 +- .../receivable/CrmReceivableService.java | 3 +- .../receivable/CrmReceivableServiceImpl.java | 4 +- 14 files changed, 110 insertions(+), 207 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/{service/AreaExcelColumnSelectDataServiceImpl.java => core/AreaExcelColumnSelectFunctionImpl.java} (56%) delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java index 9fb0f692ef..e51ef16e7f 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java @@ -11,6 +11,9 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import java.time.Duration; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; /** * 字典工具类 @@ -38,6 +41,20 @@ public class DictFrameworkUtils { }); + /** + * 针对 {@link #getDictDataLabelList(String)} 的缓存 + */ + private static final LoadingCache> GET_DICT_DATA_LIST_CACHE = CacheUtils.buildAsyncReloadingCache( + Duration.ofMinutes(1L), // 过期时间 1 分钟 + new CacheLoader>() { + + @Override + public List load(String dictType) { + return dictDataApi.getDictDataLabelList(dictType); + } + + }); + /** * 针对 {@link #parseDictDataValue(String, String)} 的缓存 */ @@ -67,6 +84,11 @@ public class DictFrameworkUtils { return GET_DICT_DATA_CACHE.get(new KeyValue<>(dictType, value)).getLabel(); } + @SneakyThrows + public static List getDictDataLabelList(String dictType) { + return GET_DICT_DATA_LIST_CACHE.get(dictType); + } + @SneakyThrows public static String parseDictDataValue(String dictType, String label) { return PARSE_DICT_DATA_CACHE.get(new KeyValue<>(dictType, label)).getValue(); diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java index 2c519523b9..5daa1e0642 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java @@ -12,9 +12,14 @@ import java.lang.annotation.*; @Inherited public @interface ExcelColumnSelect { + /** + * @return 字典类型 + */ + String dictType() default ""; + /** * @return 获取下拉数据源的方法名称 */ - String value(); + String functionName() default ""; } diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java new file mode 100644 index 0000000000..51953c4631 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/function/ExcelColumnSelectFunction.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.excel.core.function; + +import java.util.List; + +/** + * Excel 列下拉数据源获取接口 + * + * 为什么不直接解析字典还搞个接口?考虑到有的下拉数据不是从字典中获取的所有需要做一个兼容 + + * @author HUIHUI + */ +public interface ExcelColumnSelectFunction { + + /** + * 获得方法名称 + * + * @return 方法名称 + */ + String getName(); + + /** + * 获得列下拉数据源 + * + * @return 下拉数据源 + */ + List getOptions(); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java index c50158de31..df4601b94c 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java @@ -2,15 +2,19 @@ package cn.iocoder.yudao.framework.excel.core.handler; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.hutool.poi.excel.ExcelUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils; import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; -import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; +import cn.iocoder.yudao.framework.excel.core.function.ExcelColumnSelectFunction; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.HSSFDataValidation; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddressList; @@ -26,13 +30,9 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. * * @author HUIHUI */ +@Slf4j public class SelectSheetWriteHandler implements SheetWriteHandler { - // TODO @puhui999:注释哈; - private static final List ALPHABET = getExcelColumnNameList(); - - private static final List EXCEL_COLUMN_SELECT_DATA_SERVICES = new ArrayList<>(); - /** * 数据起始行从 0 开始 * @@ -46,34 +46,35 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { private static final String DICT_SHEET_NAME = "字典sheet"; - // TODO @puhui999:这个 selectMap 可以改成 Map>,然后在 afterSheetCreate 里面进行排序。这样整体的理解成本会更简单 - private final List>> selectMap = new ArrayList<>(); // 使用 List + KeyValue 组合方便排序 + /** + * key: 列 value: 下拉数据源 + */ + private final Map> selectMap = new HashMap<>(); public SelectSheetWriteHandler(Class head) { // 加载下拉数据获取接口 - Map beansMap = SpringUtil.getBeanFactory().getBeansOfType(ExcelColumnSelectDataService.class); + Map beansMap = SpringUtil.getBeanFactory().getBeansOfType(ExcelColumnSelectFunction.class); if (MapUtil.isEmpty(beansMap)) { return; } - // TODO @puhui999:static 是共享。如果并发情况下,会不会存在问题? 其实 EXCEL_COLUMN_SELECT_DATA_SERVICES 不用全局声明,直接 按照 ExcelColumnSelect 去拿下就好了; - if (CollUtil.isEmpty(EXCEL_COLUMN_SELECT_DATA_SERVICES) || EXCEL_COLUMN_SELECT_DATA_SERVICES.size() != beansMap.values().size()) { - EXCEL_COLUMN_SELECT_DATA_SERVICES.clear(); - EXCEL_COLUMN_SELECT_DATA_SERVICES.addAll(convertList(beansMap.values(), b -> b)); - } // 解析下拉数据 - // TODO @puhui999:感觉可以 head 循环 field,如果有 ExcelColumnSelect 则进行处理;而 ExcelProperty 可能是非必须的 + // TODO @puhui999:感觉可以 head 循环 field,如果有 ExcelColumnSelect 则进行处理;而 ExcelProperty 可能是非必须的。回答:主要是用于定位到列索引 Map excelPropertyFields = getFieldsWithAnnotation(head, ExcelProperty.class); Map excelColumnSelectFields = getFieldsWithAnnotation(head, ExcelColumnSelect.class); int colIndex = 0; for (String fieldName : excelPropertyFields.keySet()) { Field field = excelColumnSelectFields.get(fieldName); if (field != null) { + // ExcelProperty 有一个自定义列索引的属性 index 兼容这个字段 + int index = field.getAnnotation(ExcelProperty.class).index(); + if (index != -1) { + colIndex = index; + } getSelectDataList(colIndex, field); } colIndex++; } - selectMap.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 } /** @@ -83,12 +84,25 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { * @param field 字段 */ private void getSelectDataList(int colIndex, Field field) { - EXCEL_COLUMN_SELECT_DATA_SERVICES.forEach(selectDataService -> { - List stringList = selectDataService.handle(field.getAnnotation(ExcelColumnSelect.class).value()); - if (CollUtil.isEmpty(stringList)) { + // 获得下拉注解信息 + ExcelColumnSelect columnSelect = field.getAnnotation(ExcelColumnSelect.class); + String dictType = columnSelect.dictType(); + if (StrUtil.isNotEmpty(dictType)) { // 情况一: 字典数据 (默认) + selectMap.put(colIndex, DictFrameworkUtils.getDictDataLabelList(dictType)); + return; + } + String functionName = columnSelect.functionName(); + if (StrUtil.isEmpty(functionName)) { // 情况二: 获取自定义数据 + log.warn("[getSelectDataList]解析下拉数据失败,参数信息 dictType[{}] functionName[{}]", dictType, functionName); + return; + } + // 获得所有的下拉数据源获取方法 + Map functionMap = SpringUtil.getApplicationContext().getBeansOfType(ExcelColumnSelectFunction.class); + functionMap.values().forEach(func -> { + if (ObjUtil.notEqual(func.getName(), functionName)) { return; } - selectMap.add(new KeyValue<>(colIndex, stringList)); + selectMap.put(colIndex, func.getOptions()); }); } @@ -101,10 +115,11 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { // 1. 获取相应操作对象 DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper(); // 需要设置下拉框的 sheet 页的数据验证助手 Workbook workbook = writeWorkbookHolder.getWorkbook(); // 获得工作簿 - + List>> keyValues = convertList(selectMap.entrySet(), entry -> new KeyValue<>(entry.getKey(), entry.getValue())); + keyValues.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 // 2. 创建数据字典的 sheet 页 Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); - for (KeyValue> keyValue : selectMap) { + for (KeyValue> keyValue : keyValues) { int rowLength = keyValue.getValue().size(); // 2.1 设置字典 sheet 页的值 每一列一个字典项 for (int i = 0; i < rowLength; i++) { @@ -126,7 +141,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { KeyValue> keyValue) { // 1.1 创建可被其他单元格引用的名称 Name name = workbook.createName(); - String excelColumn = ALPHABET.get(keyValue.getKey()); + String excelColumn = ExcelUtil.indexToColName(keyValue.getKey()); // 1.2 下拉框数据来源 eg:字典sheet!$B1:$B2 String refers = DICT_SHEET_NAME + "!$" + excelColumn + "$1:$" + excelColumn + "$" + keyValue.getValue().size(); name.setNameName("dict" + keyValue.getKey()); // 设置名称的名字 @@ -162,18 +177,4 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { return annotatedFields; } - - private static List getExcelColumnNameList() { - // TODO @puhui999:是不是可以使用 ExcelUtil.indexToColName() 替代 - ArrayList strings = new ArrayList<>(); - for (int i = 1; i <= 52; i++) { // 生成 52 列名称,需要更多请重写此方法 - if (i <= 26) { - strings.add(String.valueOf((char) ('A' + i - 1))); // 使用 ASCII 码值转字母 - } else { - strings.add(String.valueOf((char) ('A' + (i - 1) / 26 - 1)) + (char) ('A' + (i - 1) % 26)); - } - } - return strings; - } - } \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java deleted file mode 100644 index c4dc6e3bc1..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/service/ExcelColumnSelectDataService.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.framework.excel.core.service; - -import cn.hutool.core.util.StrUtil; - -import java.util.Collections; -import java.util.List; - -/** - * Excel 列下拉数据源获取接口 - * - * 为什么不直接解析字典还搞个接口?考虑到有的下拉数据不是从字典中获取的所有需要做一个兼容 - * TODO @puhui999:是不是 @ExcelColumnSelect 可以搞两个属性,一个 dictType,一个 functionName;如果 dictType,则默认走字典,否则走 functionName - * 这样的话,ExcelColumnSelectDataService 改成 ExcelColumnSelectFunction 用于获取数据。 - * - * @author HUIHUI - */ -public interface ExcelColumnSelectDataService { - - // TODO @puhui999:可以考虑改成 getName - /** - * 获得方法名称 - * - * @return 方法名称 - */ - String getFunctionName(); - - // TODO @puhui999:可以考虑改成 getOptions;因为 select 下面是 option 哈,和前端 html 类似的标签; - /** - * 获得列下拉数据源 - * - * @return 下拉数据源 - */ - List getSelectDataList(); - - // TODO @puhui999:这个建议放到 SelectSheetWriteHandler 里 - default List handle(String funcName) { - if (StrUtil.isEmptyIfStr(funcName) || !StrUtil.equals(getFunctionName(), funcName)) { - return Collections.emptyList(); - } - return getSelectDataList(); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java index 4b5fbefbd7..f06122c3b4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java @@ -4,10 +4,7 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.crm.framework.excel.service.AreaExcelColumnSelectDataServiceImpl; -import cn.iocoder.yudao.module.crm.framework.excel.service.CrmCustomerIndustryExcelColumnSelectDataServiceImpl; -import cn.iocoder.yudao.module.crm.framework.excel.service.CrmCustomerLevelExcelColumnSelectDataServiceImpl; -import cn.iocoder.yudao.module.crm.framework.excel.service.CrmCustomerSourceExcelColumnSelectDataServiceImpl; +import cn.iocoder.yudao.module.crm.framework.excel.core.AreaExcelColumnSelectFunctionImpl; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -46,7 +43,7 @@ public class CrmCustomerImportExcelVO { private String email; @ExcelProperty(value = "地区", converter = AreaConvert.class) - @ExcelColumnSelect(AreaExcelColumnSelectDataServiceImpl.FUNCTION_NAME) + @ExcelColumnSelect(functionName = AreaExcelColumnSelectFunctionImpl.NAME) private Integer areaId; @ExcelProperty("详细地址") @@ -54,17 +51,17 @@ public class CrmCustomerImportExcelVO { @ExcelProperty(value = "所属行业", converter = DictConvert.class) @DictFormat(CRM_CUSTOMER_INDUSTRY) - @ExcelColumnSelect(CrmCustomerIndustryExcelColumnSelectDataServiceImpl.FUNCTION_NAME) + @ExcelColumnSelect(dictType = CRM_CUSTOMER_INDUSTRY) private Integer industryId; @ExcelProperty(value = "客户等级", converter = DictConvert.class) @DictFormat(CRM_CUSTOMER_LEVEL) - @ExcelColumnSelect(CrmCustomerLevelExcelColumnSelectDataServiceImpl.FUNCTION_NAME) + @ExcelColumnSelect(dictType = CRM_CUSTOMER_LEVEL) private Integer level; @ExcelProperty(value = "客户来源", converter = DictConvert.class) @DictFormat(CRM_CUSTOMER_SOURCE) - @ExcelColumnSelect(CrmCustomerSourceExcelColumnSelectDataServiceImpl.FUNCTION_NAME) + @ExcelColumnSelect(dictType = CRM_CUSTOMER_SOURCE) private Integer source; @ExcelProperty("备注") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunctionImpl.java similarity index 56% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunctionImpl.java index bd2bbd9e99..9df93ac6d0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/AreaExcelColumnSelectDataServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunctionImpl.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.module.crm.framework.excel.service; +package cn.iocoder.yudao.module.crm.framework.excel.core; -import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; +import cn.iocoder.yudao.framework.excel.core.function.ExcelColumnSelectFunction; import cn.iocoder.yudao.framework.ip.core.Area; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import org.springframework.stereotype.Service; @@ -13,17 +13,17 @@ import java.util.List; * @author HUIHUI */ @Service -public class AreaExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { +public class AreaExcelColumnSelectFunctionImpl implements ExcelColumnSelectFunction { - public static final String FUNCTION_NAME = "getCrmAreaNameList"; // 防止和别的模块重名 + public static final String NAME = "getCrmAreaNameList"; // 防止和别的模块重名 @Override - public String getFunctionName() { - return FUNCTION_NAME; + public String getName() { + return NAME; } @Override - public List getSelectDataList() { + public List getOptions() { // 获取地区下拉数据 // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? Area area = AreaUtils.getArea(Area.ID_CHINA); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java index bd9cb957a7..8b54b9f555 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java @@ -1,2 +1 @@ -// TODO @puhui999:在 framework 目录,保持 config 和 core 目录的风格哈; package cn.iocoder.yudao.module.crm.framework.excel; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java deleted file mode 100644 index 8a78104bf3..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerIndustryExcelColumnSelectDataServiceImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.excel.service; - -import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; - -import java.util.List; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; - -/** - * Excel 客户所属行业列下拉数据源获取接口实现类 - * - * @author HUIHUI - */ -@Service -public class CrmCustomerIndustryExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { - - public static final String FUNCTION_NAME = "getCrmCustomerIndustryList"; - - @Resource - private DictDataApi dictDataApi; - - @Override - public String getFunctionName() { - return FUNCTION_NAME; - } - - @Override - public List getSelectDataList() { - return dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java deleted file mode 100644 index 5948aa4270..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerLevelExcelColumnSelectDataServiceImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.excel.service; - -import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; - -import java.util.List; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL; - -/** - * Excel 客户等级列下拉数据源获取接口实现类 - * - * @author HUIHUI - */ -@Service -public class CrmCustomerLevelExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { - - public static final String FUNCTION_NAME = "getCrmCustomerLevelList"; - - @Resource - private DictDataApi dictDataApi; - - @Override - public String getFunctionName() { - return FUNCTION_NAME; - } - - @Override - public List getSelectDataList() { - return dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java deleted file mode 100644 index c160ed90fd..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/service/CrmCustomerSourceExcelColumnSelectDataServiceImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.excel.service; - -import cn.iocoder.yudao.framework.excel.core.service.ExcelColumnSelectDataService; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; - -import java.util.List; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE; - -/** - * Excel 客户来源列下拉数据源获取接口实现类 - * - * @author HUIHUI - */ -@Service -public class CrmCustomerSourceExcelColumnSelectDataServiceImpl implements ExcelColumnSelectDataService { - - public static final String FUNCTION_NAME = "getCrmCustomerSourceList"; - - @Resource - private DictDataApi dictDataApi; - - @Override - public String getFunctionName() { - return FUNCTION_NAME; - } - - @Override - public List getSelectDataList() { - return dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index 1a8772415b..fdab61428d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -229,7 +229,7 @@ public class CrmContractServiceImpl implements CrmContractService { // 1.1 校验存在 CrmContractDO contract = validateContractExists(id); // 1.2 如果被 CrmReceivableDO 所使用,则不允许删除 - if (CollUtil.isNotEmpty(receivableService.getReceivableByContractId(contract.getId()))) { + if (receivableService.getReceivableByContractId(contract.getId()) != 0) { throw exception(CONTRACT_DELETE_FAIL); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java index ed84ad03f9..c4a68fd708 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java @@ -122,13 +122,12 @@ public interface CrmReceivableService { */ Map getReceivablePriceMapByContractId(Collection contractIds); - // TODO @puhui999:这个搞成根据数量判断,会更好一点哈; /** * 更具合同编号查询回款列表 * * @param contractId 合同编号 * @return 回款 */ - List getReceivableByContractId(Long contractId); + Long getReceivableByContractId(Long contractId); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index 52db93273e..889d94e1f4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -302,8 +302,8 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { } @Override - public List getReceivableByContractId(Long contractId) { - return receivableMapper.selectList(CrmReceivableDO::getContractId, contractId); + public Long getReceivableByContractId(Long contractId) { + return receivableMapper.selectCount(CrmReceivableDO::getContractId, contractId); } } From ba1b02800187705b09d043a6dc772aafd19f5e90 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 3 Mar 2024 20:10:30 +0800 Subject: [PATCH 19/86] =?UTF-8?q?CRM=EF=BC=9A=E5=AE=8C=E5=96=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=99=90=EF=BC=8C=E5=AE=9E=E7=8E=B0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=99=90=E5=90=8C=E6=97=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E3=80=81=E5=90=8C=E6=97=B6=E8=BD=AC=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vo/business/CrmBusinessTransferReqVO.java | 6 +- .../admin/clue/vo/CrmClueTransferReqVO.java | 2 +- .../contact/vo/CrmContactTransferReqVO.java | 6 +- .../vo/contract/CrmContractTransferReqVO.java | 6 +- .../admin/customer/CrmCustomerController.java | 2 - .../vo/customer/CrmCustomerTransferReqVO.java | 10 +++- .../permission/CrmPermissionController.java | 58 ++++++++++++++++--- .../vo/CrmPermissionCreateReqVO.java | 14 ----- .../permission/vo/CrmPermissionRespVO.java | 24 +++++++- ...aseVO.java => CrmPermissionSaveReqVO.java} | 17 +++--- .../dal/mysql/business/CrmBusinessMapper.java | 8 +++ .../dal/mysql/contact/CrmContactMapper.java | 6 ++ .../dal/mysql/contract/CrmContractMapper.java | 6 ++ .../service/business/CrmBusinessService.java | 15 ++++- .../business/CrmBusinessServiceImpl.java | 21 ++++--- .../crm/service/clue/CrmClueServiceImpl.java | 10 ++-- .../service/contact/CrmContactService.java | 13 ++++- .../contact/CrmContactServiceImpl.java | 17 ++++-- .../service/contract/CrmContractService.java | 15 ++++- .../contract/CrmContractServiceImpl.java | 17 ++++-- .../customer/CrmCustomerServiceImpl.java | 52 +++++++++++++++-- 21 files changed, 253 insertions(+), 72 deletions(-) delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionCreateReqVO.java rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/{CrmPermissionBaseVO.java => CrmPermissionSaveReqVO.java} (74%) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java index a76c48cae9..083ea35706 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java @@ -3,15 +3,19 @@ package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Schema(description = "管理后台 - 商机转移 Request VO") @Data +@NoArgsConstructor +@AllArgsConstructor public class CrmBusinessTransferReqVO { @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "商机编号不能为空") - private Long id; + private Long bizId; /** * 新负责人的用户编号 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java index 63bdc1838f..7e6b8f0dd4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java @@ -12,7 +12,7 @@ public class CrmClueTransferReqVO { @Schema(description = "线索编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "线索编号不能为空") - private Long id; + private Long bizId; @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "新负责人的用户编号不能为空") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java index c65b205c8b..8b5a6a6f4b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java @@ -2,17 +2,21 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; import lombok.Data; import jakarta.validation.constraints.NotNull; +import lombok.NoArgsConstructor; @Schema(description = "管理后台 - CRM 联系人转移 Request VO") @Data +@NoArgsConstructor +@AllArgsConstructor public class CrmContactTransferReqVO { @Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "联系人编号不能为空") - private Long id; + private Long bizId; /** * 新负责人的用户编号 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java index 4b8245c409..b59e21e160 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java @@ -3,17 +3,21 @@ package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; import lombok.Data; import jakarta.validation.constraints.NotNull; +import lombok.NoArgsConstructor; @Schema(description = "管理后台 - CRM 合同转移 Request VO") @Data +@NoArgsConstructor +@AllArgsConstructor public class CrmContractTransferReqVO { @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "联系人编号不能为空") - private Long id; + private Long bizId; @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "新负责人的用户编号不能为空") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index 7745a6e6cb..9111c26f7c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -62,8 +62,6 @@ public class CrmCustomerController { private DeptApi deptApi; @Resource private AdminUserApi adminUserApi; - @Resource - private DictDataApi dictDataApi; @PostMapping("/create") @Operation(summary = "创建客户") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java index e62a84fd7a..98d0d4a647 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java @@ -5,13 +5,15 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; +import java.util.List; + @Schema(description = "管理后台 - CRM 客户转移 Request VO") @Data public class CrmCustomerTransferReqVO { @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "客户编号不能为空") - private Long id; + private Long bizId; /** * 新负责人的用户编号 @@ -28,4 +30,10 @@ public class CrmCustomerTransferReqVO { @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer oldOwnerPermissionLevel; + /** + * 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择 + */ + @Schema(description = "同时转移", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + private List toBizTypes; + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java index 428bd07ad8..1cf8d7591f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java @@ -5,12 +5,19 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; +import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -27,13 +34,11 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -50,7 +55,12 @@ public class CrmPermissionController { @Resource private CrmPermissionService permissionService; - + @Resource + private CrmContactService contactService; + @Resource + private CrmBusinessService businessService; + @Resource + private CrmContractService contractService; @Resource private AdminUserApi adminUserApi; @Resource @@ -60,13 +70,47 @@ public class CrmPermissionController { @PostMapping("/create") @Operation(summary = "创建数据权限") + @Transactional(rollbackFor = Exception.class) @PreAuthorize("@ss.hasPermission('crm:permission:create')") @CrmPermission(bizTypeValue = "#reqVO.bizType", bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) - public CommonResult addPermission(@Valid @RequestBody CrmPermissionCreateReqVO reqVO) { + public CommonResult addPermission(@Valid @RequestBody CrmPermissionSaveReqVO reqVO) { permissionService.createPermission(BeanUtils.toBean(reqVO, CrmPermissionCreateReqBO.class)); + if (CollUtil.isNotEmpty(reqVO.getToBizTypes())) { + createBizTypePermissions(reqVO); + } return success(true); } + + private void createBizTypePermissions(CrmPermissionSaveReqVO reqVO) { + List createPermissions = new ArrayList<>(); + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTACT.getType())) { + List contactList = contactService.getContactListByCustomerIdOwnerUserId(reqVO.getBizId(), getLoginUserId()); + contactList.forEach(item -> { + createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CONTACT.getType()) + .setBizId(item.getId()).setUserId(reqVO.getUserId()).setLevel(reqVO.getLevel())); + }); + } + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_BUSINESS.getType())) { + List businessList = businessService.getBusinessListByCustomerIdOwnerUserId(reqVO.getBizId(), getLoginUserId()); + businessList.forEach(item -> { + createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()) + .setBizId(item.getId()).setUserId(reqVO.getUserId()).setLevel(reqVO.getLevel())); + }); + } + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTRACT.getType())) { + List contractList = contractService.getContractListByCustomerIdOwnerUserId(reqVO.getBizId(), getLoginUserId()); + contractList.forEach(item -> { + createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()) + .setBizId(item.getId()).setUserId(reqVO.getUserId()).setLevel(reqVO.getLevel())); + }); + } + if (CollUtil.isEmpty(createPermissions)) { + return; + } + permissionService.createPermissionBatch(createPermissions); + } + @PutMapping("/update") @Operation(summary = "编辑数据权限") @PreAuthorize("@ss.hasPermission('crm:permission:update')") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionCreateReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionCreateReqVO.java deleted file mode 100644 index 99793389ba..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionCreateReqVO.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.permission.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - CRM 数据权限创建 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmPermissionCreateReqVO extends CrmPermissionBaseVO { - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java index 10f1ce1985..aeddf1a5de 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.module.crm.controller.admin.permission.vo; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; import lombok.Data; import java.time.LocalDateTime; @@ -8,11 +12,29 @@ import java.util.Set; @Schema(description = "管理后台 - CRM 数据权限 Response VO") @Data -public class CrmPermissionRespVO extends CrmPermissionBaseVO { +public class CrmPermissionRespVO { @Schema(description = "数据权限编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") private Long id; + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "CRM 类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmBizTypeEnum.class) + @NotNull(message = "CRM 类型不能为空") + private Integer bizType; + + @Schema(description = "CRM 类型数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "CRM 类型数据编号不能为空") + private Long bizId; + + @Schema(description = "权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @InEnum(CrmPermissionLevelEnum.class) + @NotNull(message = "权限级别不能为空") + private Integer level; + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") private String nickname; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionBaseVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java similarity index 74% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionBaseVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java index 796b3cd469..9635cc627f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionBaseVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java @@ -8,14 +8,11 @@ import lombok.Data; import jakarta.validation.constraints.NotNull; -/** - * 数据权限 Base VO,提供给添加、修改、详细的子 VO 使用 - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 - * - * @author HUIHUI - */ +import java.util.List; + +@Schema(description = "管理后台 - CRM 数据权限创建/更新 Request VO") @Data -public class CrmPermissionBaseVO { +public class CrmPermissionSaveReqVO { @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") @NotNull(message = "用户编号不能为空") @@ -35,4 +32,10 @@ public class CrmPermissionBaseVO { @NotNull(message = "权限级别不能为空") private Integer level; + /** + * 添加客户团队成员时,需要额外有【联系人】【商机】【合同】的 checkbox 选择 + */ + @Schema(description = "同时添加", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") + private List toBizTypes; + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java index 4718a8d7ae..fc5b070f46 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java @@ -6,12 +6,14 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import java.util.Collection; +import java.util.List; /** * 商机 Mapper @@ -57,4 +59,10 @@ public interface CrmBusinessMapper extends BaseMapperX { return selectCount(CrmBusinessDO::getStatusTypeId, statusTypeId); } + default List selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId){ + return selectList(new LambdaQueryWrapperX() + .eq(CrmBusinessDO::getCustomerId, customerId) + .eq(CrmBusinessDO::getOwnerUserId, ownerUserId)); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java index 4a77665ad7..d4244bce0b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java @@ -73,4 +73,10 @@ public interface CrmContactMapper extends BaseMapperX { return selectList(CrmContactDO::getCustomerId, customerId); } + default List selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmContactDO::getCustomerId, customerId) + .eq(CrmContactDO::getOwnerUserId, ownerUserId)); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java index e06afb2571..14d743291b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java @@ -117,4 +117,10 @@ public interface CrmContractMapper extends BaseMapperX { return selectCount(query); } + default List selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return selectList(new LambdaQueryWrapperX() + .eq(CrmContractDO::getCustomerId, customerId) + .eq(CrmContractDO::getOwnerUserId, ownerUserId)); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java index ab7982024c..7bd899b64c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java @@ -46,8 +46,8 @@ public interface CrmBusinessService { /** * 更新商机相关跟进信息 * - * @param id 编号 - * @param contactNextTime 下次联系时间 + * @param id 编号 + * @param contactNextTime 下次联系时间 * @param contactLastContent 最后联系内容 */ void updateBusinessFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); @@ -55,7 +55,7 @@ public interface CrmBusinessService { /** * 更新商机的下次联系时间 * - * @param ids 编号数组 + * @param ids 编号数组 * @param contactNextTime 下次联系时间 */ void updateBusinessContactNextTime(Collection ids, LocalDateTime contactNextTime); @@ -185,4 +185,13 @@ public interface CrmBusinessService { return status.getName(); } + /** + * 获得商机列表 + * + * @param customerId 客户编号 + * @param ownerUserId 负责人编号 + * @return 商机列表 + */ + List getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java index e709b65472..9f2e4ceb62 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.service.business; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -23,6 +24,7 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerServiceImpl; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; @@ -204,7 +206,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { private List validateBusinessProducts(List list) { // 1. 校验产品存在 - productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.Product::getProductId)); + productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.Product::getProductId)); // 2. 转化为 CrmBusinessProductDO 列表 return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount())))); @@ -234,7 +236,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { } // 1.4 校验是不是状态没变更 if ((reqVO.getStatusId() != null && reqVO.getStatusId().equals(business.getStatusId())) - || (reqVO.getEndStatus() != null && reqVO.getEndStatus().equals(business.getEndStatus()))) { + || (reqVO.getEndStatus() != null && reqVO.getEndStatus().equals(business.getEndStatus()))) { throw exception(BUSINESS_UPDATE_STATUS_FAIL_STATUS_EQUALS); } @@ -292,18 +294,18 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.bizId}}", success = CRM_BUSINESS_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) public void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId) { // 1 校验商机是否存在 - CrmBusinessDO business = validateBusinessExists(reqVO.getId()); + CrmBusinessDO business = validateBusinessExists(reqVO.getBizId()); // 2.1 数据权限转移 permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_BUSINESS.getType(), - reqVO.getNewOwnerUserId(), reqVO.getId(), CrmPermissionLevelEnum.OWNER.getLevel())); + reqVO.getBizId(), reqVO.getNewOwnerUserId(), CrmPermissionLevelEnum.OWNER.getLevel())); // 2.2 设置新的负责人 - businessMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + businessMapper.updateOwnerUserIdById(reqVO.getBizId(), reqVO.getNewOwnerUserId()); // 记录操作日志上下文 LogRecordContext.putVariable("business", business); @@ -370,4 +372,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { return businessMapper.selectCountByStatusTypeId(statusTypeId); } + @Override + public List getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return businessMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java index 70ebeb44da..3b4f0bc349 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java @@ -159,18 +159,18 @@ public class CrmClueServiceImpl implements CrmClueService { @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.bizId}}", success = CRM_CLUE_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) public void transferClue(CrmClueTransferReqVO reqVO, Long userId) { // 1 校验线索是否存在 - CrmClueDO clue = validateClueExists(reqVO.getId()); + CrmClueDO clue = validateClueExists(reqVO.getBizId()); // 2.1 数据权限转移 crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CLUE.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + reqVO.getBizId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); // 2.2 设置新的负责人 - clueMapper.updateById(new CrmClueDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); + clueMapper.updateById(new CrmClueDO().setId(reqVO.getBizId()).setOwnerUserId(reqVO.getNewOwnerUserId())); // 3. 记录转移日志 LogRecordContext.putVariable("clue", clue); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java index 23c29d3bcd..971d413afd 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java @@ -75,8 +75,8 @@ public interface CrmContactService { /** * 更新联系人的下次联系时间 * - * @param ids 编号数组 - * @param contactNextTime 下次联系时间 + * @param ids 编号数组 + * @param contactNextTime 下次联系时间 */ void updateContactContactNextTime(Collection ids, LocalDateTime contactNextTime); @@ -160,4 +160,13 @@ public interface CrmContactService { */ Long getContactCountByCustomerId(Long customerId); + /** + * 获得联系人列表 + * + * @param customerId 客户编号 + * @param ownerUserId 负责人编号 + * @return 联系人列表 + */ + List getContactListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java index d8e356124e..ea46edf112 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.service.contact; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; @@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerServiceImpl; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; @@ -177,18 +179,18 @@ public class CrmContactServiceImpl implements CrmContactService { @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.bizId}}", success = CRM_CONTACT_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) public void transferContact(CrmContactTransferReqVO reqVO, Long userId) { // 1 校验联系人是否存在 - CrmContactDO contact = validateContactExists(reqVO.getId()); + CrmContactDO contact = validateContactExists(reqVO.getBizId()); // 2.1 数据权限转移 permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTACT.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + reqVO.getBizId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); // 2.2 设置新的负责人 - contactMapper.updateById(new CrmContactDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); + contactMapper.updateById(new CrmContactDO().setId(reqVO.getBizId()).setOwnerUserId(reqVO.getNewOwnerUserId())); // 3. 记录转移日志 LogRecordContext.putVariable("contact", contact); @@ -298,4 +300,9 @@ public class CrmContactServiceImpl implements CrmContactService { return contactMapper.selectCount(CrmContactDO::getCustomerId, customerId); } + @Override + public List getContactListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return contactMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId); + } + } \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java index 25f5537dc3..0d8964f189 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java @@ -58,8 +58,8 @@ public interface CrmContractService { /** * 更新合同相关的更进信息 * - * @param id 合同编号 - * @param contactNextTime 下次联系时间 + * @param id 合同编号 + * @param contactNextTime 下次联系时间 * @param contactLastContent 最后联系内容 */ void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); @@ -75,7 +75,7 @@ public interface CrmContractService { /** * 更新合同流程审批结果 * - * @param id 合同编号 + * @param id 合同编号 * @param bpmResult BPM 审批结果 */ void updateContractAuditStatus(Long id, Integer bpmResult); @@ -193,4 +193,13 @@ public interface CrmContractService { */ Long getRemindContractCount(Long userId); + /** + * 获得合同列表 + * + * @param customerId 客户编号 + * @param ownerUserId 负责人编号 + * @return 合同列表 + */ + List getContractListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index fdab61428d..39ad8f5df4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -26,6 +27,7 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerServiceImpl; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; @@ -252,18 +254,18 @@ public class CrmContractServiceImpl implements CrmContractService { @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.bizId}}", success = CRM_CONTRACT_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) public void transferContract(CrmContractTransferReqVO reqVO, Long userId) { // 1. 校验合同是否存在 - CrmContractDO contract = validateContractExists(reqVO.getId()); + CrmContractDO contract = validateContractExists(reqVO.getBizId()); // 2.1 数据权限转移 crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + reqVO.getBizId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); // 2.2 设置负责人 - contractMapper.updateById(new CrmContractDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); + contractMapper.updateById(new CrmContractDO().setId(reqVO.getBizId()).setOwnerUserId(reqVO.getNewOwnerUserId())); // 3. 记录转移日志 LogRecordContext.putVariable("contract", contract); @@ -407,4 +409,9 @@ public class CrmContractServiceImpl implements CrmContractService { return contractMapper.selectCountByRemind(userId, config); } + @Override + public List getContractListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + return contractMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java index 314349865b..d314b823c1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java @@ -9,7 +9,13 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactTransferReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; @@ -193,26 +199,60 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.bizId}}", success = CRM_CUSTOMER_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { // 1.1 校验客户是否存在 - CrmCustomerDO customer = validateCustomerExists(reqVO.getId()); + CrmCustomerDO customer = validateCustomerExists(reqVO.getBizId()); // 1.2 校验拥有客户是否到达上限 validateCustomerExceedOwnerLimit(reqVO.getNewOwnerUserId(), 1); - // 2.1 数据权限转移 permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); + reqVO.getBizId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); // 2.2 转移后重新设置负责人 - customerMapper.updateById(new CrmCustomerDO().setId(reqVO.getId()) + customerMapper.updateById(new CrmCustomerDO().setId(reqVO.getBizId()) .setOwnerUserId(reqVO.getNewOwnerUserId()).setOwnerTime(LocalDateTime.now())); + // 2.3 同时转移 + if (CollUtil.isNotEmpty(reqVO.getToBizTypes())) { + transfer(reqVO, userId); + } + // 3. 记录转移日志 LogRecordContext.putVariable("customer", customer); } + /** + * 转移客户时,需要额外有【联系人】【商机】【合同】 + * + * @param reqVO 请求 + * @param userId 用户编号 + */ + private void transfer(CrmCustomerTransferReqVO reqVO, Long userId) { + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTACT.getType())) { + List contactList = contactService.getContactListByCustomerIdOwnerUserId(reqVO.getBizId(), userId); + contactList.forEach(item -> { + contactService.transferContact(new CrmContactTransferReqVO(item.getId(), reqVO.getNewOwnerUserId(), + reqVO.getOldOwnerPermissionLevel()), userId); + }); + } + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_BUSINESS.getType())) { + List businessList = businessService.getBusinessListByCustomerIdOwnerUserId(reqVO.getBizId(), userId); + businessList.forEach(item -> { + businessService.transferBusiness(new CrmBusinessTransferReqVO(item.getId(), reqVO.getNewOwnerUserId(), + reqVO.getOldOwnerPermissionLevel()), userId); + }); + } + if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTRACT.getType())) { + List contractList = contractService.getContractListByCustomerIdOwnerUserId(reqVO.getBizId(), userId); + contractList.forEach(item -> { + contractService.transferContract(new CrmContractTransferReqVO(item.getId(), reqVO.getNewOwnerUserId(), + reqVO.getOldOwnerPermissionLevel()), userId); + }); + } + } + @Override @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_LOCK_SUB_TYPE, bizNo = "{{#lockReqVO.id}}", success = CRM_CUSTOMER_LOCK_SUCCESS) From a23ea45632640ec50c5472aa89796b8fcb160531 Mon Sep 17 00:00:00 2001 From: dhb52 Date: Mon, 4 Mar 2024 23:51:25 +0800 Subject: [PATCH 20/86] =?UTF-8?q?fix:=20[CRM-=E5=AE=A2=E6=88=B7=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1]=E6=A0=B9=E6=8D=AECode-Review=20=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.http | 61 ++- .../CrmStatisticsCustomerController.java | 72 ++-- ...CrmStatisticsCustomerByUserBaseRespVO.java | 18 + ...atisticsCustomerContractSummaryRespVO.java | 51 +++ .../CrmStatisticsCustomerCountVO.java | 34 -- ...atisticsCustomerDealCycleByDateRespVO.java | 16 + ...atisticsCustomerDealCycleByUserRespVO.java | 16 + ...StatisticsCustomerSummaryByDateRespVO.java | 19 + ...StatisticsCustomerSummaryByUserRespVO.java | 24 ++ ...StatisticsFollowupSummaryByDateRespVO.java | 19 + ...StatisticsFollowupSummaryByTypeRespVO.java | 17 + ...StatisticsFollowupSummaryByUserRespVO.java | 16 + .../CrmStatisticsCustomerMapper.java | 31 +- .../CrmStatisticsCustomerService.java | 58 ++- .../CrmStatisticsCustomerServiceImpl.java | 375 +++++++++++++----- .../CrmStatisticsCustomerMapper.xml | 325 ++++++++++----- 16 files changed, 847 insertions(+), 305 deletions(-) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http index 13ae812286..0c422f9868 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http @@ -1,39 +1,68 @@ -### 新建客户总量分析(按日) -GET {{baseUrl}}/crm/statistics-customer/get-total-customer-count?deptId=100×[0]=2024-12-01 00:00:00×[1]=2024-12-12 23:59:59 +# == 1. 客户总量分析 == +### 1.1 客户总量分析(按日) +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} -### 新建客户总量分析(按月) -GET {{baseUrl}}/crm/statistics-customer/get-total-customer-count?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +### 1.2 客户总量分析(按月) +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} -### 成交客户总量分析(按日) -GET {{baseUrl}}/crm/statistics-customer/get-deal-total-customer-count?deptId=100×[0]=2024-12-01 00:00:00×[1]=2024-12-12 23:59:59 +### 1.3 客户总量统计(按用户) +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} -### 成交客户总量分析(按月) -GET {{baseUrl}}/crm/statistics-customer/get-deal-total-customer-count?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 + +# == 2. 客户跟进次数分析 == +### 2.1 客户跟进次数分析(按日) +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} -### 获取客户跟进次数(按日) -GET {{baseUrl}}/crm/statistics-customer/get-record-count?deptId=100×[0]=2024-12-01 00:00:00×[1]=2024-12-12 23:59:59 +### 2.2 客户跟进次数分析(按月) +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} -### 获取客户跟进次数(按月) -GET {{baseUrl}}/crm/statistics-customer/get-record-count?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +### 2.3 客户总量统计(按用户) +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} -### 获取已跟进客户数(按日) -GET {{baseUrl}}/crm/statistics-customer/get-distinct-record-count?deptId=100×[0]=2024-12-01 00:00:00×[1]=2024-12-12 23:59:59 + +# == 3. 客户跟进方式分析 == +### 3.1 客户跟进方式分析 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-type?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} +tenant-id: {{adminTenentId}} -### 获取已跟进客户数(按月) -GET {{baseUrl}}/crm/statistics-customer/get-distinct-record-count?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 + +# == 4. 客户成交周期 == +### 4.1 合同摘要信息(客户转化率页面) +GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} +tenant-id: {{adminTenentId}} + + +# == 5. 客户成交周期 == +### 5.1 客户成交周期(按日) +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} +tenant-id: {{adminTenentId}} + +### 5.2 客户成交周期(按月) +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} +tenant-id: {{adminTenentId}} + +### 5.3 获取客户成交周期(按用户) +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index b51740dafa..4a0b2e760e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -1,8 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -18,8 +17,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -// TODO @dhb52:数据统计 员工客户分析,改成“客户统计” -@Tag(name = "管理后台 - CRM 数据统计 员工客户分析") +@Tag(name = "管理后台 - CRM 客户统计") @RestController @RequestMapping("/crm/statistics-customer") @Validated @@ -28,50 +26,60 @@ public class CrmStatisticsCustomerController { @Resource private CrmStatisticsCustomerService customerService; - // TODO @dhb52:建议 getCustomerCount 和 getDealTotalCustomerCount 搞成一个接口; - // 1. 数量接口:【方法:getCustomerSummaryByDate】,VO:CrmStatisticsCustomerSummaryByDateRespVO,然后里面是 time、customerCreateCount customerDealCount - // 2. 按人统计:【方法:getCustomerSummaryByUser】,VO:CrmStatisticsCustomerSummaryByOwnerRespVO,然后里面是 ownerUserId、ownerUserName、customerCreateCount customerDealCount、contractPrice、receivablePrice;客户成交率、未回款金额、回款完成率,交给前端计算; - - @GetMapping("/get-total-customer-count") - @Operation(summary = "获得新建客户数量") + @GetMapping("/get-customer-summary-by-date") + @Operation(summary = "获取客户总量分析(按日期)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getTotalCustomerCount(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getTotalCustomerCount(reqVO)); + public CommonResult> getCustomerSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerSummaryByDate(reqVO)); } - @GetMapping("/get-deal-total-customer-count") - @Operation(summary = "获得成交客户数量") + @GetMapping("/get-customer-summary-by-user") + @Operation(summary = "获取客户总量分析(按用户)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getDealTotalCustomerCount(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getDealTotalCustomerCount(reqVO)); + public CommonResult> getCustomerSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerSummaryByUser(reqVO)); } - @GetMapping("/get-record-count") - @Operation(summary = "获取客户跟进次数") + @GetMapping("/get-followup-summary-by-date") + @Operation(summary = "获取客户跟进次数分析(按日期)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getRecordCount(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getRecordCount(reqVO)); + public CommonResult> getFollowupSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowupSummaryByDate(reqVO)); } - @GetMapping("/get-distinct-record-count") - @Operation(summary = "获取已跟进客户数") + @GetMapping("/get-followup-summary-by-user") + @Operation(summary = "获取客户跟进次数分析(按用户)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getDistinctRecordCount(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getDistinctRecordCount(reqVO)); + public CommonResult> getFollowupSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowupSummaryByUser(reqVO)); } - @GetMapping("/get-record-type-count") - @Operation(summary = "获取客户跟进方式统计数") + @GetMapping("/get-followup-summary-by-type") + @Operation(summary = "获取客户跟进次数分析(按类型)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getRecordTypeCount(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getRecordTypeCount(reqVO)); + public CommonResult> getFollowupSummaryByType(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowupSummaryByType(reqVO)); } - @GetMapping("/get-customer-cycle") - @Operation(summary = "获取客户成交周期") + @GetMapping("/get-contract-summary") + @Operation(summary = "获取合同摘要信息(客户转化率页面)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getCustomerCycle(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getCustomerCycle(reqVO)); + public CommonResult> getContractSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getContractSummary(reqVO)); + } + + @GetMapping("/get-customer-deal-cycle-by-date") + @Operation(summary = "获取客户成交周期(按日期)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerDealCycleByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerDealCycleByDate(reqVO)); + } + + @GetMapping("/get-customer-deal-cycle-by-user") + @Operation(summary = "获取客户成交周期(按用户)") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerDealCycleByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerDealCycleByUser(reqVO)); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java new file mode 100644 index 0000000000..82f74f2304 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户客户统计响应 Base VO + */ +@Data +public class CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long ownerUserId; + + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String ownerUserName; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java new file mode 100644 index 0000000000..7cb02e521e --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 客户转化率分析 VO") +@Data +public class CrmStatisticsCustomerContractSummaryRespVO { + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String customerName; + + @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "演示合同") + private String contractName; + + @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00") + private BigDecimal totalPrice; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00") + private BigDecimal receivablePrice; + + @Schema(description = "客户行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "金融") + private String customerType; + + @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "外呼") + private String customerSource; + + @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long ownerUserId; + + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") + private String ownerUserName; + + @Schema(description = "创建人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long creatorUserId; + + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "源码") + private String creatorUserName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-01 13:24:26") + private LocalDateTime createTime; + + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02 00:00:00") + private LocalDate orderDate; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java deleted file mode 100644 index a2537db9aa..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - - -@Schema(description = "管理后台 - CRM 数据统计 员工客户分析 VO") -@Data -public class CrmStatisticsCustomerCountVO { - - /** - * 时间轴 - *

- * group by DATE_FORMAT(create_date, '%Y%m') - */ - @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") - private String category; - - /** - * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义 - *

- * 1. 金额:合同金额排行、回款金额排行 - * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 - */ - @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer count = 0; - - /** - * 成交周期(天) - */ - @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") - private Double cycle = 0.0; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java new file mode 100644 index 0000000000..44b2526e85 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户成交周期分析(按日期) VO") +@Data +public class CrmStatisticsCustomerDealCycleByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") + private Double customerDealCycle = 0.0; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java new file mode 100644 index 0000000000..6c8137983d --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 成交周期分析(按用户) VO") +@Data +public class CrmStatisticsCustomerDealCycleByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") + private Double customerDealCycle = 0.0; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount = 0; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java new file mode 100644 index 0000000000..866a58f1e6 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户总量分析(按日期) VO") +@Data +public class CrmStatisticsCustomerSummaryByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCreateCount = 0; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount = 0; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java new file mode 100644 index 0000000000..ffa5e21ae1 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 客户总量分析(按用户) VO") +@Data +public class CrmStatisticsCustomerSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCreateCount = 0; + + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerDealCount = 0; + + @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal contractPrice = BigDecimal.valueOf(0); + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal receivablePrice = BigDecimal.valueOf(0); + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java new file mode 100644 index 0000000000..6bd6f1d4db --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 跟进次数分析(按日期) VO") +@Data +public class CrmStatisticsFollowupSummaryByDateRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followupRecordCount = 0; + + @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followupCustomerCount = 0; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java new file mode 100644 index 0000000000..c722305a5f --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 跟进次数分析(按类型) VO") +@Data +public class CrmStatisticsFollowupSummaryByTypeRespVO { + + @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String followupType; + + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followupRecordCount = 0; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java new file mode 100644 index 0000000000..5cd610c360 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 跟进次数分析(按用户) VO") +@Data +public class CrmStatisticsFollowupSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { + + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followupRecordCount = 0; + + @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer followupCustomerCount = 0; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 464c521c61..6bababa26a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -14,16 +13,32 @@ import java.util.List; @Mapper public interface CrmStatisticsCustomerMapper { - List selectCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); - List selectDealCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); - List selectRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); - List selectDistinctRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); - List selectRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO); + List selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); - List selectCustomerCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + List selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); + + List selectFollowupRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + + List selectFollowupCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + + List selectFollowupRecordCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); + + List selectFollowupCustomerCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); + + List selectContractSummary(CrmStatisticsCustomerReqVO reqVO); + + List selectFollowupRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO); + + List selectCustomerDealCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + + List selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index e568816d6a..546124701a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -1,64 +1,80 @@ package cn.iocoder.yudao.module.crm.service.statistics; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import java.util.List; /** - * CRM 数据统计 员工客户分析 Service 接口 + * CRM 客户分析 Service 接口 * * @author dhb52 */ public interface CrmStatisticsCustomerService { /** - * 获取新建客户数量 + * 总量分析(按日期) * * @param reqVO 请求参数 - * @return 新建客户数量统计 + * @return 统计数据 */ - List getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO); + List getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO); /** - * 获取成交客户数量 + * 总量分析(按用户) * * @param reqVO 请求参数 - * @return 成交客户数量统计 + * @return 统计数据 */ - List getDealTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO); + List getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO); /** - * 获取客户跟进次数 + * 跟进次数分析(按日期) * * @param reqVO 请求参数 - * @return 客户跟进次数 + * @return 统计数据 */ - List getRecordCount(CrmStatisticsCustomerReqVO reqVO); + List getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO); /** - * 获取已跟进客户数 + * 跟进次数分析(按用户) * * @param reqVO 请求参数 - * @return 已跟进客户数 + * @return 统计数据 */ - List getDistinctRecordCount(CrmStatisticsCustomerReqVO reqVO); + List getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO); /** - * 获取客户跟进方式统计数 + * 客户跟进次数分析(按类型) * * @param reqVO 请求参数 - * @return 客户跟进方式统计数 + * @return 统计数据 */ - List getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO); + List getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO); + /** - * 获取客户成交周期 + * 获取合同摘要信息(客户转化率页面) * * @param reqVO 请求参数 - * @return 客户成交周期 + * @return 合同摘要列表 */ - List getCustomerCycle(CrmStatisticsCustomerReqVO reqVO); + List getContractSummary(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 客户成交周期(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index 94eb560d1e..77bd0fcf67 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -17,17 +17,14 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Function; +import java.util.*; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; /** - * CRM 数据统计 员工客户分析 Service 实现类 + * CRM 客户分析 Service 实现类 * * @author dhb52 */ @@ -35,6 +32,13 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @Validated public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerService { + private static final String SQL_DATE_FORMAT_BY_MONTH = "%Y%m"; + private static final String SQL_DATE_FORMAT_BY_DAY = "%Y%m%d"; + + private static final String TIME_FORMAT_BY_MONTH = "yyyyMM"; + private static final String TIME_FORMAT_BY_DAY = "yyyyMMdd"; + + @Resource private CrmStatisticsCustomerMapper customerMapper; @@ -45,130 +49,315 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @Resource private DictDataApi dictDataApi; - @Override - public List getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) { - return getStat(reqVO, customerMapper::selectCustomerCountGroupbyDate); - } @Override - public List getDealTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) { - return getStat(reqVO, customerMapper::selectDealCustomerCountGroupbyDate); - } - - @Override - public List getRecordCount(CrmStatisticsCustomerReqVO reqVO) { - reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); - return getStat(reqVO, customerMapper::selectRecordCountGroupbyDate); - } - - @Override - public List getDistinctRecordCount(CrmStatisticsCustomerReqVO reqVO) { - reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); - return getStat(reqVO, customerMapper::selectDistinctRecordCountGroupbyDate); - } - - @Override - public List getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组: 如果用户编号为空, 则获得部门下的用户编号数组 - if (ObjUtil.isNotNull(reqVO.getUserId())) { - reqVO.setUserIds(List.of(reqVO.getUserId())); - } else { - reqVO.setUserIds(getUserIds(reqVO.getDeptId())); - } - if (CollUtil.isEmpty(reqVO.getUserIds())) { + public List getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { return Collections.emptyList(); } + reqVO.setUserIds(userIds); + + // 2. 获取分项统计数据 + reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); + final List customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyDate(reqVO); + final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyDate(reqVO); + + // 3. 获取时间序列 + final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); + + // 4. 合并统计数据 + List result = new ArrayList<>(times.size()); + final Map customerCreateCountMap = convertMap(customerCreateCount, CrmStatisticsCustomerSummaryByDateRespVO::getTime, CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); + final Map customerDealCountMap = convertMap(customerDealCount, CrmStatisticsCustomerSummaryByDateRespVO::getTime, CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); + times.forEach(time -> result.add( + new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time) + .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0)) + .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)) + )); + + return result; + } + + @Override + public List getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取分项统计数据 + final List customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyUser(reqVO); + final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO); + final List contractPrice = customerMapper.selectContractPriceGroupbyUser(reqVO); + final List receivablePrice = customerMapper.selectReceivablePriceGroupbyUser(reqVO); + + // 3. 合并统计数据 + final Map customerCreateCountMap = convertMap(customerCreateCount, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); + final Map customerDealCountMap = convertMap(customerDealCount, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); + final Map contractPriceMap = convertMap(contractPrice, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); + final Map receivablePriceMap = convertMap(receivablePrice, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); + List result = new ArrayList<>(userIds.size()); + userIds.forEach(userId -> { + final CrmStatisticsCustomerSummaryByUserRespVO respVO = new CrmStatisticsCustomerSummaryByUserRespVO(); + respVO.setOwnerUserId(userId); + respVO.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0)) + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)) + .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.valueOf(0))) + .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.valueOf(0))); + result.add(respVO); + }); + + // 4. 拼接用户信息 + appendUserInfo(result); + + return result; + } + + @Override + public List getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取分项统计数据 + reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); + reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); + final List followupRecordCount = customerMapper.selectFollowupRecordCountGroupbyDate(reqVO); + final List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyDate(reqVO); + + // 3. 获取时间序列 + final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); + + // 4. 合并统计数据 + List result = new ArrayList<>(times.size()); + final Map followupRecordCountMap = convertMap(followupRecordCount, CrmStatisticsFollowupSummaryByDateRespVO::getTime, CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); + final Map followupCustomerCountMap = convertMap(followupCustomerCount, CrmStatisticsFollowupSummaryByDateRespVO::getTime, CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); + times.forEach(time -> result.add( + new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time) + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0)) + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0)) + )); + + return result; + } + + @Override + public List getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取分项统计数据 + reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); + final List followupRecordCount = customerMapper.selectFollowupRecordCountGroupbyUser(reqVO); + final List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyUser(reqVO); + + // 3. 合并统计数据 + final Map followupRecordCountMap = convertMap(followupRecordCount, CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); + final Map followupCustomerCountMap = convertMap(followupCustomerCount, CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); + List result = new ArrayList<>(userIds.size()); + userIds.forEach(userId -> { + final CrmStatisticsFollowupSummaryByUserRespVO stat = new CrmStatisticsFollowupSummaryByUserRespVO() + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0)) + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0)); + stat.setOwnerUserId(userId); + result.add(stat); + }); + + // 4. 拼接用户信息 + appendUserInfo(result); + + return result; + } + + @Override + public List getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); // 2. 获得排行数据 reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); - List stats = customerMapper.selectRecordCountGroupbyType(reqVO); + List stats = customerMapper.selectFollowupRecordCountGroupbyType(reqVO); // 3. 获取字典数据 List followUpTypes = dictDataApi.getDictDataList("crm_follow_up_type"); final Map followUpTypeMap = convertMap(followUpTypes, DictDataRespDTO::getValue, DictDataRespDTO::getLabel); stats.forEach(stat -> { - stat.setCategory(followUpTypeMap.get(stat.getCategory())); + stat.setFollowupType(followUpTypeMap.get(stat.getFollowupType())); }); return stats; } @Override - public List getCustomerCycle(CrmStatisticsCustomerReqVO reqVO) { - return getStat(reqVO, customerMapper::selectCustomerCycleGroupbyDate); + public List getContractSummary(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + List contractSummary = customerMapper.selectContractSummary(reqVO); + + // 2. 拼接用户信息 + final Set userIdSet = new HashSet<>(); + userIdSet.addAll(userIds); + userIdSet.addAll(convertSet(contractSummary, CrmStatisticsCustomerContractSummaryRespVO::getCreatorUserId)); + final Map userMap = adminUserApi.getUserMap(userIdSet); + contractSummary.forEach(contract -> contract.setCreatorUserName(userMap.get(contract.getCreatorUserId()).getNickname()) + .setOwnerUserName(userMap.get(contract.getOwnerUserId()).getNickname())); + + return contractSummary; + } + + @Override + public List getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取分项统计数据 + reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); + reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); + final List customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyDate(reqVO); + + // 3. 获取时间序列 + final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); + + // 4. 合并统计数据 + List result = new ArrayList<>(times.size()); + final Map customerDealCycleMap = convertMap(customerDealCycle, CrmStatisticsCustomerDealCycleByDateRespVO::getTime, CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); + times.forEach(time -> result.add( + new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time) + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, Double.valueOf(0))) + )); + + return result; + } + + @Override + public List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + final List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + + // 2. 获取分项统计数据 + reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); + final List customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyUser(reqVO); + final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO); + + // 3. 合并统计数据 + final Map customerDealCycleMap = convertMap(customerDealCycle, CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId, CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); + final Map customerDealCountMap = convertMap(customerDealCount, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); + List result = new ArrayList<>(userIds.size()); + userIds.forEach(userId -> { + final CrmStatisticsCustomerDealCycleByUserRespVO stat = new CrmStatisticsCustomerDealCycleByUserRespVO() + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0)) + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)); + stat.setOwnerUserId(userId); + result.add(stat); + }); + + // 4. 拼接用户信息 + appendUserInfo(result); + + return result; } /** - * 获得统计数据 + * 拼接用户信息(昵称) * - * @param reqVO 参数 - * @param statFunction 统计方法 - * @return 统计数据 + * @param stats 统计数据 */ - private List getStat(CrmStatisticsCustomerReqVO reqVO, Function> statFunction) { - // 1. 获得用户编号数组: 如果用户编号为空, 则获得部门下的用户编号数组 + private void appendUserInfo(List stats) { + Map userMap = adminUserApi.getUserMap(convertSet(stats, CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); + stats.forEach(stat -> MapUtils.findAndThen(userMap, stat.getOwnerUserId(), user -> { + stat.setOwnerUserName(user.getNickname()); + })); + } + + /** + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsCustomerReqVO reqVO) { if (ObjUtil.isNotNull(reqVO.getUserId())) { - reqVO.setUserIds(List.of(reqVO.getUserId())); + return List.of(reqVO.getUserId()); } else { - reqVO.setUserIds(getUserIds(reqVO.getDeptId())); - } - if (CollUtil.isEmpty(reqVO.getUserIds())) { - return Collections.emptyList(); + // 1. 获得部门列表 + final Long deptId = reqVO.getDeptId(); + List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); + deptIds.add(deptId); + // 2. 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); } + } - // 2. 生成日期格式 - LocalDateTime startTime = reqVO.getTimes()[0]; - final LocalDateTime endTime = reqVO.getTimes()[1]; - final long days = LocalDateTimeUtil.between(startTime, endTime).toDays(); - boolean byMonth = days > 31; - if (byMonth) { - // 按月 - reqVO.setSqlDateFormat("%Y%m"); - } else { - // 按日 - reqVO.setSqlDateFormat("%Y%m%d"); - } - // 3. 获得排行数据 - List stats = statFunction.apply(reqVO); + /** + * 判断是否按照 月粒度 统计 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 是, 按月粒度, 否则按天粒度统计。 + */ + private boolean queryByMonth(LocalDateTime startTime, LocalDateTime endTime) { + return LocalDateTimeUtil.between(startTime, endTime).toDays() > 31; + } - // 4. 生成时间序列 - List result = CollUtil.newArrayList(); + /** + * 生成时间序列 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 时间序列 + */ + private List generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) { + boolean byMonth = queryByMonth(startTime, endTime); + List times = CollUtil.newArrayList(); while (!startTime.isAfter(endTime)) { - final String category = LocalDateTimeUtil.format(startTime, byMonth ? "yyyyMM" : "yyyyMMdd"); - result.add(new CrmStatisticsCustomerCountVO().setCategory(category)); + times.add(LocalDateTimeUtil.format(startTime, byMonth ? TIME_FORMAT_BY_MONTH : TIME_FORMAT_BY_DAY)); if (byMonth) startTime = startTime.plusMonths(1); else startTime = startTime.plusDays(1); } - // 5. 使用时间序列填充结果 - final Map statMap = convertMap(stats, - CrmStatisticsCustomerCountVO::getCategory, - Function.identity()); - result.forEach(r -> { - if (statMap.containsKey(r.getCategory())) { - r.setCount(statMap.get(r.getCategory()).getCount()) - .setCycle(statMap.get(r.getCategory()).getCycle()); - } - }); - - return result; + return times; } - /** - * 获得部门下的用户编号数组,包括子部门的 + * 获取 SQL 查询 GROUP BY 的时间格式 * - * @param deptId 部门编号 - * @return 用户编号数组 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return SQL 查询 GROUP BY 的时间格式 */ - public List getUserIds(Long deptId) { - // 1. 获得部门列表 - List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); - deptIds.add(deptId); - // 2. 获得用户编号 - return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + private String getSqlDateFormat(LocalDateTime startTime, LocalDateTime endTime) { + return queryByMonth(startTime, endTime) ? SQL_DATE_FORMAT_BY_MONTH : SQL_DATE_FORMAT_BY_DAY; } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index 06affccabb..c612d4a241 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -2,115 +2,238 @@ - - SELECT - DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) AS category, - count(*) AS count + DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time, + count(*) AS customerCreateCount + FROM crm_customer + WHERE deleted = 0 + AND owner_user_id IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND + #{times[1],javaType=java.time.LocalDateTime} + GROUP BY time + + + + + + + + + + + + + + + + + + + + + + + + - SELECT - DATE_FORMAT( b.order_date, #{sqlDateFormat,javaType=java.lang.String} ) AS category, - count( DISTINCT a.id ) AS count - FROM - crm_customer AS a - LEFT JOIN crm_contract AS b ON b.customer_id = a.id - WHERE - a.deleted = 0 AND b.deleted = 0 - AND b.audit_status = 20 - AND a.owner_user_id IN - - #{userId} - - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND - #{times[1],javaType=java.time.LocalDateTime} - GROUP BY category + DATE_FORMAT( b.order_date, #{sqlDateFormat} ) AS time, + IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, a.create_time, b.order_date )), 1 ), 0 ) AS customer_deal_cycle + FROM crm_customer AS a + LEFT JOIN crm_contract AS b ON b.customer_id = a.id + WHERE a.deleted = 0 AND b.deleted = 0 + AND b.audit_status = 20 + AND a.owner_user_id IN + + #{userId} + + AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND + #{times[1],javaType=java.time.LocalDateTime} + GROUP BY time - SELECT - DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) AS category, - count(*) AS count - FROM - crm_follow_up_record - WHERE - creator IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND - #{times[1],javaType=java.time.LocalDateTime} - AND biz_type = #{bizType,javaType=java.lang.Integer} - GROUP BY category - - - - - - - From 06c0d865447c8065a06d5d1dfce327a195ad91f6 Mon Sep 17 00:00:00 2001 From: dhb52 Date: Tue, 5 Mar 2024 15:08:40 +0000 Subject: [PATCH 21/86] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8convertSetByFlat?= =?UTF-8?q?Map=E9=81=BF=E5=85=8D=20ID=20=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dhb52 --- .../crm/controller/admin/customer/CrmCustomerController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index 7745a6e6cb..f5a0a4e50e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -137,7 +137,7 @@ public class CrmCustomerController { return java.util.Collections.emptyList(); } // 1.1 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, + Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(list, contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 1.2 获取距离进入公海的时间 From 0386820a1c80354917afe20e31cc5048a1f5be3d Mon Sep 17 00:00:00 2001 From: dhb52 Date: Tue, 5 Mar 2024 23:16:16 +0800 Subject: [PATCH 22/86] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0[=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E8=A1=8C=E4=B8=9A=E3=80=81=E5=AE=A2=E6=88=B7=E6=9D=A5?= =?UTF-8?q?=E6=BA=90]=E7=AD=89=E5=AD=97=E6=AE=B5=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E6=9E=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/customer/CrmCustomerController.java | 2 +- ...CrmStatisticsCustomerByUserBaseRespVO.java | 2 + ...atisticsCustomerContractSummaryRespVO.java | 22 ++- ...StatisticsCustomerSummaryByUserRespVO.java | 4 +- .../CrmStatisticsCustomerServiceImpl.java | 177 +++++++++++------- .../CrmStatisticsCustomerMapper.xml | 4 +- 6 files changed, 138 insertions(+), 73 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index 36b3ee8132..a4adeee3e3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -142,7 +142,7 @@ public class CrmCustomerController { return java.util.Collections.emptyList(); } // 1.1 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, + Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(list, contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 1.2 获取距离进入公海的时间 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java index 82f74f2304..340e930663 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -10,6 +11,7 @@ import lombok.Data; public class CrmStatisticsCustomerByUserBaseRespVO { @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @JsonIgnore private Long ownerUserId; @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java index 7cb02e521e..019309f8e0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java @@ -1,13 +1,18 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; + @Schema(description = "管理后台 - CRM 客户转化率分析 VO") @Data public class CrmStatisticsCustomerContractSummaryRespVO { @@ -24,20 +29,30 @@ public class CrmStatisticsCustomerContractSummaryRespVO { @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00") private BigDecimal receivablePrice; + @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @JsonIgnore + private String industryId; + @Schema(description = "客户行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "金融") - private String customerType; + private String industryName; + + @Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @JsonIgnore + private String source; @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "外呼") - private String customerSource; + private String sourceName; @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @JsonIgnore private Long ownerUserId; @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") private String ownerUserName; @Schema(description = "创建人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long creatorUserId; + @JsonIgnore + private String creatorUserId; @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "源码") private String creatorUserName; @@ -46,6 +61,7 @@ public class CrmStatisticsCustomerContractSummaryRespVO { private LocalDateTime createTime; @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02 00:00:00") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT) private LocalDate orderDate; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java index ffa5e21ae1..bd719a1b8a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java @@ -16,9 +16,9 @@ public class CrmStatisticsCustomerSummaryByUserRespVO extends CrmStatisticsCusto private Integer customerDealCount = 0; @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") - private BigDecimal contractPrice = BigDecimal.valueOf(0); + private BigDecimal contractPrice = BigDecimal.ZERO; @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") - private BigDecimal receivablePrice = BigDecimal.valueOf(0); + private BigDecimal receivablePrice = BigDecimal.ZERO; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index 77bd0fcf67..6b664dce55 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; @@ -19,9 +20,14 @@ import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; /** * CRM 客户分析 Service 实现类 @@ -68,16 +74,20 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); // 4. 合并统计数据 - List result = new ArrayList<>(times.size()); - final Map customerCreateCountMap = convertMap(customerCreateCount, CrmStatisticsCustomerSummaryByDateRespVO::getTime, CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); - final Map customerDealCountMap = convertMap(customerDealCount, CrmStatisticsCustomerSummaryByDateRespVO::getTime, CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); - times.forEach(time -> result.add( + List respVoList = new ArrayList<>(times.size()); + final Map customerCreateCountMap = convertMap(customerCreateCount, + CrmStatisticsCustomerSummaryByDateRespVO::getTime, + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); + final Map customerDealCountMap = convertMap(customerDealCount, + CrmStatisticsCustomerSummaryByDateRespVO::getTime, + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); + times.forEach(time -> respVoList.add( new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time) .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0)) .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)) )); - return result; + return respVoList; } @Override @@ -96,25 +106,33 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe final List receivablePrice = customerMapper.selectReceivablePriceGroupbyUser(reqVO); // 3. 合并统计数据 - final Map customerCreateCountMap = convertMap(customerCreateCount, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); - final Map customerDealCountMap = convertMap(customerDealCount, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); - final Map contractPriceMap = convertMap(contractPrice, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); - final Map receivablePriceMap = convertMap(receivablePrice, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); - List result = new ArrayList<>(userIds.size()); + final Map customerCreateCountMap = convertMap(customerCreateCount, + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); + final Map customerDealCountMap = convertMap(customerDealCount, + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); + final Map contractPriceMap = convertMap(contractPrice, + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); + final Map receivablePriceMap = convertMap(receivablePrice, + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); + List respVoList = new ArrayList<>(userIds.size()); userIds.forEach(userId -> { - final CrmStatisticsCustomerSummaryByUserRespVO respVO = new CrmStatisticsCustomerSummaryByUserRespVO(); - respVO.setOwnerUserId(userId); - respVO.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0)) + final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO(); + vo.setOwnerUserId(userId); + vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0)) .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)) - .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.valueOf(0))) - .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.valueOf(0))); - result.add(respVO); + .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO)) + .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO)); + respVoList.add(vo); }); // 4. 拼接用户信息 - appendUserInfo(result); + appendUserInfo(respVoList); - return result; + return respVoList; } @Override @@ -136,16 +154,20 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); // 4. 合并统计数据 - List result = new ArrayList<>(times.size()); - final Map followupRecordCountMap = convertMap(followupRecordCount, CrmStatisticsFollowupSummaryByDateRespVO::getTime, CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); - final Map followupCustomerCountMap = convertMap(followupCustomerCount, CrmStatisticsFollowupSummaryByDateRespVO::getTime, CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); - times.forEach(time -> result.add( + List respVoList = new ArrayList<>(times.size()); + final Map followupRecordCountMap = convertMap(followupRecordCount, + CrmStatisticsFollowupSummaryByDateRespVO::getTime, + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); + final Map followupCustomerCountMap = convertMap(followupCustomerCount, + CrmStatisticsFollowupSummaryByDateRespVO::getTime, + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); + times.forEach(time -> respVoList.add( new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time) .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0)) .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0)) )); - return result; + return respVoList; } @Override @@ -163,21 +185,25 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe final List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyUser(reqVO); // 3. 合并统计数据 - final Map followupRecordCountMap = convertMap(followupRecordCount, CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); - final Map followupCustomerCountMap = convertMap(followupCustomerCount, CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); - List result = new ArrayList<>(userIds.size()); + final Map followupRecordCountMap = convertMap(followupRecordCount, + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); + final Map followupCustomerCountMap = convertMap(followupCustomerCount, + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); + List respVoList = new ArrayList<>(userIds.size()); userIds.forEach(userId -> { - final CrmStatisticsFollowupSummaryByUserRespVO stat = new CrmStatisticsFollowupSummaryByUserRespVO() + final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO() .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0)) .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0)); - stat.setOwnerUserId(userId); - result.add(stat); + vo.setOwnerUserId(userId); + respVoList.add(vo); }); // 4. 拼接用户信息 - appendUserInfo(result); + appendUserInfo(respVoList); - return result; + return respVoList; } @Override @@ -191,16 +217,17 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 2. 获得排行数据 reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); - List stats = customerMapper.selectFollowupRecordCountGroupbyType(reqVO); + List respVoList = customerMapper.selectFollowupRecordCountGroupbyType(reqVO); // 3. 获取字典数据 - List followUpTypes = dictDataApi.getDictDataList("crm_follow_up_type"); - final Map followUpTypeMap = convertMap(followUpTypes, DictDataRespDTO::getValue, DictDataRespDTO::getLabel); - stats.forEach(stat -> { - stat.setFollowupType(followUpTypeMap.get(stat.getFollowupType())); + List followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE); + final Map followUpTypeMap = convertMap(followUpTypes, + DictDataRespDTO::getValue, DictDataRespDTO::getLabel); + respVoList.forEach(vo -> { + vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType())); }); - return stats; + return respVoList; } @Override @@ -212,17 +239,29 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe } reqVO.setUserIds(userIds); - List contractSummary = customerMapper.selectContractSummary(reqVO); + // 2. 获取统计数据 + List respVoList = customerMapper.selectContractSummary(reqVO); - // 2. 拼接用户信息 - final Set userIdSet = new HashSet<>(); - userIdSet.addAll(userIds); - userIdSet.addAll(convertSet(contractSummary, CrmStatisticsCustomerContractSummaryRespVO::getCreatorUserId)); - final Map userMap = adminUserApi.getUserMap(userIdSet); - contractSummary.forEach(contract -> contract.setCreatorUserName(userMap.get(contract.getCreatorUserId()).getNickname()) - .setOwnerUserName(userMap.get(contract.getOwnerUserId()).getNickname())); + // 3. 设置 创建人、负责人、行业、来源 + // 获取客户所属行业 + Map industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY), + DictDataRespDTO::getValue, DictDataRespDTO::getLabel); + // 获取客户来源 + Map sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE), + DictDataRespDTO::getValue, DictDataRespDTO::getLabel); + // 获取创建人、负责人列表 + Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList, + vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); - return contractSummary; + respVoList.forEach(vo -> { + MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName); + MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName); + MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()), + user -> vo.setCreatorUserName(user.getNickname())); + MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); + }); + + return respVoList; } @Override @@ -243,14 +282,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); // 4. 合并统计数据 - List result = new ArrayList<>(times.size()); - final Map customerDealCycleMap = convertMap(customerDealCycle, CrmStatisticsCustomerDealCycleByDateRespVO::getTime, CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); - times.forEach(time -> result.add( + List respVoList = new ArrayList<>(times.size()); + final Map customerDealCycleMap = convertMap(customerDealCycle, + CrmStatisticsCustomerDealCycleByDateRespVO::getTime, + CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); + times.forEach(time -> respVoList.add( new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time) - .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, Double.valueOf(0))) + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D)) )); - return result; + return respVoList; } @Override @@ -268,33 +309,37 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO); // 3. 合并统计数据 - final Map customerDealCycleMap = convertMap(customerDealCycle, CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId, CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); - final Map customerDealCountMap = convertMap(customerDealCount, CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); - List result = new ArrayList<>(userIds.size()); + final Map customerDealCycleMap = convertMap(customerDealCycle, + CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); + final Map customerDealCountMap = convertMap(customerDealCount, + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); + List respVoList = new ArrayList<>(userIds.size()); userIds.forEach(userId -> { - final CrmStatisticsCustomerDealCycleByUserRespVO stat = new CrmStatisticsCustomerDealCycleByUserRespVO() + final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO() .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0)) .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)); - stat.setOwnerUserId(userId); - result.add(stat); + vo.setOwnerUserId(userId); + respVoList.add(vo); }); // 4. 拼接用户信息 - appendUserInfo(result); + appendUserInfo(respVoList); - return result; + return respVoList; } /** * 拼接用户信息(昵称) * - * @param stats 统计数据 + * @param respVoList 统计数据 */ - private void appendUserInfo(List stats) { - Map userMap = adminUserApi.getUserMap(convertSet(stats, CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); - stats.forEach(stat -> MapUtils.findAndThen(userMap, stat.getOwnerUserId(), user -> { - stat.setOwnerUserName(user.getNickname()); - })); + private void appendUserInfo(List respVoList) { + Map userMap = adminUserApi.getUserMap(convertSet(respVoList, + CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); + respVoList.forEach(vo -> MapUtils.findAndThen(userMap, + vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); } /** diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index c612d4a241..3fd52f3e72 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -180,8 +180,10 @@ SELECT a.`name` AS customer_name, b.`name` AS contract_name, - b.total_price AS contract_price, + b.total_price, IFNULL( c.price, 0 ) AS receivable_price, + a.industry_id, + a.source, a.owner_user_id, a.creator AS creator_user_id, a.create_time, From d30700d06003ed72dfed27b547ad2544f088c2ee Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 9 Mar 2024 11:03:17 +0800 Subject: [PATCH 23/86] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98=E6=97=B6=EF=BC=8C=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E4=BF=9D=E8=AF=81=E7=88=B6=E7=BA=BF=E7=A8=8B=E7=9A=84?= =?UTF-8?q?=20ThreadLocal=20=E4=BC=A0=E5=85=A5=E5=AD=90=E7=BA=BF=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/framework/common/util/cache/CacheUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java index 41f75405e8..acd48aa121 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java @@ -7,6 +7,7 @@ import com.google.common.cache.LoadingCache; import java.time.Duration; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** @@ -17,8 +18,11 @@ import java.util.concurrent.Executors; public class CacheUtils { public static LoadingCache buildAsyncReloadingCache(Duration duration, CacheLoader loader) { - Executor executor = Executors.newCachedThreadPool( // TODO 芋艿:可能要思考下,未来要不要做成可配置 - TtlExecutors.getDefaultDisableInheritableThreadFactory()); // TTL 保证 ThreadLocal 可以透传 + // 1. 使用 TTL 包装 ExecutorService,实现 ThreadLocal 的透传 + // https://github.com/YunaiV/ruoyi-vue-pro/issues/432 + ExecutorService executorService = Executors.newCachedThreadPool(); // TODO 芋艿:可能要思考下,未来要不要做成可配置 + Executor executor = TtlExecutors.getTtlExecutorService(executorService); + // 2. 创建 Guava LoadingCache return CacheBuilder.newBuilder() // 只阻塞当前数据加载线程,其他线程返回旧值 .refreshAfterWrite(duration) From 89fc83c41938d0fd88337507c0190fdcaba6ff41 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 9 Mar 2024 11:58:05 +0800 Subject: [PATCH 24/86] =?UTF-8?q?CRM=EF=BC=9Acode=20review=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E6=9D=83=E9=99=90=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/mysql/ruoyi-vue-pro.sql | 2 +- yudao-dependencies/pom.xml | 4 +- .../common/util/collection/MapUtils.java | 4 +- .../dict/core/DictFrameworkUtils.java | 3 +- .../core/annotations/ExcelColumnSelect.java | 4 +- .../core/handler/SelectSheetWriteHandler.java | 46 +++++++++++-------- .../vo/business/CrmBusinessTransferReqVO.java | 1 + .../vo/customer/CrmCustomerImportExcelVO.java | 4 +- .../vo/customer/CrmCustomerTransferReqVO.java | 2 +- .../permission/CrmPermissionController.java | 6 ++- .../permission/vo/CrmPermissionSaveReqVO.java | 3 +- .../dal/mysql/contact/CrmContactMapper.java | 1 + .../mysql/receivable/CrmReceivableMapper.java | 4 ++ ...ava => AreaExcelColumnSelectFunction.java} | 4 +- .../crm/framework/excel/package-info.java | 3 ++ .../framework/operatelog/package-info.java | 3 ++ .../framework/permission/package-info.java | 3 ++ .../crm/framework/web/package-info.java | 2 +- .../contract/CrmContractServiceImpl.java | 4 +- .../receivable/CrmReceivableService.java | 6 +-- .../receivable/CrmReceivableServiceImpl.java | 4 +- 21 files changed, 71 insertions(+), 42 deletions(-) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/{AreaExcelColumnSelectFunctionImpl.java => AreaExcelColumnSelectFunction.java} (79%) diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 49da40058b..bdc70b63fc 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -11,7 +11,7 @@ Target Server Version : 80200 (8.2.0) File Encoding : 65001 - Date: 01/03/2024 19:39:45 + Date: 05/03/2024 23:36:35 */ SET NAMES utf8mb4; diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index c9667aea2d..3a024933b6 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -627,11 +627,11 @@ ureport2-console ${ureport2.version} - + org.apache.poi poi - + org.apache.poi poi-ooxml diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java index f4a17b5233..a59b53fd4b 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.util.collection; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; @@ -40,6 +41,7 @@ public class MapUtils { /** * 从哈希表查找到 key 对应的 value,然后进一步处理 + * key 为 null 时, 不处理 * 注意,如果查找到的 value 为 null 时,不进行处理 * * @param map 哈希表 @@ -47,7 +49,7 @@ public class MapUtils { * @param consumer 进一步处理的逻辑 */ public static void findAndThen(Map map, K key, Consumer consumer) { - if (CollUtil.isEmpty(map)) { + if (ObjUtil.isNull(key) || CollUtil.isEmpty(map)) { return; } V value = map.get(key); diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java index e51ef16e7f..8dada3f752 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java @@ -13,8 +13,6 @@ import lombok.extern.slf4j.Slf4j; import java.time.Duration; import java.util.List; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; - /** * 字典工具类 * @@ -27,6 +25,7 @@ public class DictFrameworkUtils { private static final DictDataRespDTO DICT_DATA_NULL = new DictDataRespDTO(); + // TODO @puhui999:GET_DICT_DATA_CACHE、GET_DICT_DATA_LIST_CACHE、PARSE_DICT_DATA_CACHE 这 3 个缓存是有点重叠,可以思考下,有没可能减少 1 个。微信讨论好私聊,再具体改哈 /** * 针对 {@link #getDictDataLabel(String, String)} 的缓存 */ diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java index 5daa1e0642..b4ff140aff 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java @@ -3,7 +3,9 @@ package cn.iocoder.yudao.framework.excel.core.annotations; import java.lang.annotation.*; /** - * 给列添加下拉选择数据 + * 给 Excel 列添加下拉选择数据 + * + * 其中 {@link #dictType()} 和 {@link #functionName()} 二选一 * * @author HUIHUI */ diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java index df4601b94c..fd66c40189 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java @@ -1,8 +1,9 @@ package cn.iocoder.yudao.framework.excel.core.handler; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.hutool.poi.excel.ExcelUtil; @@ -59,7 +60,6 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { } // 解析下拉数据 - // TODO @puhui999:感觉可以 head 循环 field,如果有 ExcelColumnSelect 则进行处理;而 ExcelProperty 可能是非必须的。回答:主要是用于定位到列索引 Map excelPropertyFields = getFieldsWithAnnotation(head, ExcelProperty.class); Map excelColumnSelectFields = getFieldsWithAnnotation(head, ExcelColumnSelect.class); int colIndex = 0; @@ -71,39 +71,47 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { if (index != -1) { colIndex = index; } - getSelectDataList(colIndex, field); + buildSelectDataList(colIndex, field); } colIndex++; } + // TODO @puhui999:感觉可以 head 循环 field,如果有 ExcelColumnSelect 则进行处理;而 ExcelProperty 可能是非必须的。回答:主要是用于定位到列索引;补充:可以看看下面这样写? +// for (Field field : head.getDeclaredFields()) { +// if (field.isAnnotationPresent(ExcelColumnSelect.class)) { +// ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); +// if (excelProperty != null) { +// colIndex = excelProperty.index(); +// } +// getSelectDataList(colIndex, field); +// } +// colIndex++; +// } } /** - * 获得下拉数据 + * 获得下拉数据,并添加到 {@link #selectMap} 中 * * @param colIndex 列索引 * @param field 字段 */ - private void getSelectDataList(int colIndex, Field field) { - // 获得下拉注解信息 + private void buildSelectDataList(int colIndex, Field field) { ExcelColumnSelect columnSelect = field.getAnnotation(ExcelColumnSelect.class); String dictType = columnSelect.dictType(); + String functionName = columnSelect.functionName(); + Assert.isTrue(ObjectUtil.isNotEmpty(dictType) || ObjectUtil.isNotEmpty(functionName), + "Field({}) 的 @ExcelColumnSelect 注解,dictType 和 functionName 不能同时为空", field.getName()); + + // 情况一:使用 dictType 获得下拉数据 if (StrUtil.isNotEmpty(dictType)) { // 情况一: 字典数据 (默认) selectMap.put(colIndex, DictFrameworkUtils.getDictDataLabelList(dictType)); return; } - String functionName = columnSelect.functionName(); - if (StrUtil.isEmpty(functionName)) { // 情况二: 获取自定义数据 - log.warn("[getSelectDataList]解析下拉数据失败,参数信息 dictType[{}] functionName[{}]", dictType, functionName); - return; - } - // 获得所有的下拉数据源获取方法 + + // 情况二:使用 functionName 获得下拉数据 Map functionMap = SpringUtil.getApplicationContext().getBeansOfType(ExcelColumnSelectFunction.class); - functionMap.values().forEach(func -> { - if (ObjUtil.notEqual(func.getName(), functionName)) { - return; - } - selectMap.put(colIndex, func.getOptions()); - }); + ExcelColumnSelectFunction function = CollUtil.findOne(functionMap.values(), item -> item.getName().equals(functionName)); + Assert.notNull(function, "未找到对应的 function({})", functionName); + selectMap.put(colIndex, function.getOptions()); } @Override @@ -121,7 +129,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); for (KeyValue> keyValue : keyValues) { int rowLength = keyValue.getValue().size(); - // 2.1 设置字典 sheet 页的值 每一列一个字典项 + // 2.1 设置字典 sheet 页的值,每一列一个字典项 for (int i = 0; i < rowLength; i++) { Row row = dictSheet.getRow(i); if (row == null) { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java index 083ea35706..9fe7e23169 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java @@ -13,6 +13,7 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class CrmBusinessTransferReqVO { + // TODO @puhui999:这里最好还是用 id 哈,主要还是在 Business 业务里 @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") @NotNull(message = "商机编号不能为空") private Long bizId; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java index f06122c3b4..a45e9115fe 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.crm.framework.excel.core.AreaExcelColumnSelectFunctionImpl; +import cn.iocoder.yudao.module.crm.framework.excel.core.AreaExcelColumnSelectFunction; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -43,7 +43,7 @@ public class CrmCustomerImportExcelVO { private String email; @ExcelProperty(value = "地区", converter = AreaConvert.class) - @ExcelColumnSelect(functionName = AreaExcelColumnSelectFunctionImpl.NAME) + @ExcelColumnSelect(functionName = AreaExcelColumnSelectFunction.NAME) private Integer areaId; @ExcelProperty("详细地址") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java index 98d0d4a647..38f6f1756f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java @@ -31,7 +31,7 @@ public class CrmCustomerTransferReqVO { private Integer oldOwnerPermissionLevel; /** - * 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择 + * 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择。选中时,也一起转移 */ @Schema(description = "同时转移", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") private List toBizTypes; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java index 1cf8d7591f..11289b0ed9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java @@ -68,22 +68,24 @@ public class CrmPermissionController { @Resource private PostApi postApi; + // TODO @puhui999:是不是还是叫 create 好点哈。 @PostMapping("/create") @Operation(summary = "创建数据权限") @Transactional(rollbackFor = Exception.class) @PreAuthorize("@ss.hasPermission('crm:permission:create')") @CrmPermission(bizTypeValue = "#reqVO.bizType", bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) - public CommonResult addPermission(@Valid @RequestBody CrmPermissionSaveReqVO reqVO) { + public CommonResult savePermission(@Valid @RequestBody CrmPermissionSaveReqVO reqVO) { permissionService.createPermission(BeanUtils.toBean(reqVO, CrmPermissionCreateReqBO.class)); + // 处理【同时添加至】的权限 if (CollUtil.isNotEmpty(reqVO.getToBizTypes())) { createBizTypePermissions(reqVO); } return success(true); } - private void createBizTypePermissions(CrmPermissionSaveReqVO reqVO) { List createPermissions = new ArrayList<>(); + // TODO @puhui999:需要考虑,被添加人,是不是应该有对应的权限了; if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTACT.getType())) { List contactList = contactService.getContactListByCustomerIdOwnerUserId(reqVO.getBizId(), getLoginUserId()); contactList.forEach(item -> { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java index 9635cc627f..2ec7ed8db6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java @@ -33,7 +33,8 @@ public class CrmPermissionSaveReqVO { private Integer level; /** - * 添加客户团队成员时,需要额外有【联系人】【商机】【合同】的 checkbox 选择 + * 添加客户团队成员时,需要额外有【联系人】【商机】【合同】的 checkbox 选择。 + * 选中时,同时添加对应的权限 */ @Schema(description = "同时添加", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") private List toBizTypes; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java index d4244bce0b..f94b50f490 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java @@ -74,6 +74,7 @@ public interface CrmContactMapper extends BaseMapperX { } default List selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) { + // TODO @puhui999:父类有 selectList,查询 2 个字段的简化方法哈,可以用下 return selectList(new LambdaQueryWrapperX() .eq(CrmContactDO::getCustomerId, customerId) .eq(CrmContactDO::getOwnerUserId, ownerUserId)); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java index 5a5e9ce2b6..0c821c8c23 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java @@ -99,4 +99,8 @@ public interface CrmReceivableMapper extends BaseMapperX { return convertMap(result, obj -> (Long) obj.get("contract_id"), obj -> (BigDecimal) obj.get("total_price")); } + default Long selectCountByContractId(Long contractId) { + return selectCount(CrmReceivableDO::getContractId, contractId); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunctionImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java similarity index 79% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunctionImpl.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java index 9df93ac6d0..b407ed4702 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunctionImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java @@ -10,10 +10,12 @@ import java.util.List; /** * Excel 所属地区列下拉数据源获取接口实现类 * + * // TODO @puhui999:类名叫:地区下拉框数据源的 {@link ExcelColumnSelectFunction} 实现类,这样看起来会更简洁一点哈 + * * @author HUIHUI */ @Service -public class AreaExcelColumnSelectFunctionImpl implements ExcelColumnSelectFunction { +public class AreaExcelColumnSelectFunction implements ExcelColumnSelectFunction { public static final String NAME = "getCrmAreaNameList"; // 防止和别的模块重名 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java index 8b54b9f555..c2deef8b8b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java @@ -1 +1,4 @@ +/** + * crm 模块的 excel 拓展封装 + */ package cn.iocoder.yudao.module.crm.framework.excel; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java index 975a2eb51d..413b652c1f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java @@ -1 +1,4 @@ +/** + * crm 模块的 operatelog 拓展封装 + */ package cn.iocoder.yudao.module.crm.framework.operatelog; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java index 44f4080160..97f76dbe12 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java @@ -1 +1,4 @@ +/** + * crm 模块的 permission 拓展封装 + */ package cn.iocoder.yudao.module.crm.framework.permission; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java index e18c3cdb51..09de7263c5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java @@ -1,4 +1,4 @@ /** - * trade 模块的 web 配置 + * crm 模块的 web 拓展封装 */ package cn.iocoder.yudao.module.crm.framework.web; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index 39ad8f5df4..beb3ef1a8f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjUtil; -import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -27,7 +26,6 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerServiceImpl; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; @@ -231,7 +229,7 @@ public class CrmContractServiceImpl implements CrmContractService { // 1.1 校验存在 CrmContractDO contract = validateContractExists(id); // 1.2 如果被 CrmReceivableDO 所使用,则不允许删除 - if (receivableService.getReceivableByContractId(contract.getId()) != 0) { + if (receivableService.getReceivableCountByContractId(contract.getId()) > 0) { throw exception(CONTRACT_DELETE_FAIL); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java index c4a68fd708..f6ac8c3fd4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java @@ -123,11 +123,11 @@ public interface CrmReceivableService { Map getReceivablePriceMapByContractId(Collection contractIds); /** - * 更具合同编号查询回款列表 + * 根据合同编号查询回款数量 * * @param contractId 合同编号 - * @return 回款 + * @return 回款数量 */ - Long getReceivableByContractId(Long contractId); + Long getReceivableCountByContractId(Long contractId); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index 889d94e1f4..94e1bfb412 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -302,8 +302,8 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { } @Override - public Long getReceivableByContractId(Long contractId) { - return receivableMapper.selectCount(CrmReceivableDO::getContractId, contractId); + public Long getReceivableCountByContractId(Long contractId) { + return receivableMapper.selectCountByContractId(contractId); } } From 0043d02d0a10027ba0151a6e7ff4aef51c55e64c Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 9 Mar 2024 14:31:43 +0800 Subject: [PATCH 25/86] =?UTF-8?q?fix=EF=BC=9A=E5=95=86=E6=9C=BA=20api=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E7=94=9F=E6=88=90=E4=B8=8D=E5=AF=B9=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/vo/business/CrmBusinessSaveReqVO.java | 4 ++-- .../crm/service/business/CrmBusinessServiceImpl.java | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java index a9ebaae05e..fa86692e7b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java @@ -66,13 +66,13 @@ public class CrmBusinessSaveReqVO { private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 @Schema(description = "产品列表") - private List products; + private List businessProducts; @Schema(description = "产品列表") @Data @NoArgsConstructor @AllArgsConstructor - public static class Product { + public static class BusinessProduct { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") @NotNull(message = "产品编号不能为空") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java index 9f2e4ceb62..5ec0a4b417 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.crm.service.business; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; -import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -24,7 +23,6 @@ import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerServiceImpl; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; @@ -90,7 +88,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { success = CRM_BUSINESS_CREATE_SUCCESS) public Long createBusiness(CrmBusinessSaveReqVO createReqVO, Long userId) { // 1.1 校验产品项的有效性 - List businessProducts = validateBusinessProducts(createReqVO.getProducts()); + List businessProducts = validateBusinessProducts(createReqVO.getBusinessProducts()); // 1.2 校验关联字段 validateRelationDataExists(createReqVO); @@ -131,7 +129,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { // 1.1 校验存在 CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); // 1.2 校验产品项的有效性 - List businessProducts = validateBusinessProducts(updateReqVO.getProducts()); + List businessProducts = validateBusinessProducts(updateReqVO.getBusinessProducts()); // 1.3 校验关联字段 validateRelationDataExists(updateReqVO); @@ -204,9 +202,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { } } - private List validateBusinessProducts(List list) { + private List validateBusinessProducts(List list) { // 1. 校验产品存在 - productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.Product::getProductId)); + productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.BusinessProduct::getProductId)); // 2. 转化为 CrmBusinessProductDO 列表 return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount())))); From 8dcc12f21560c6c3e6b617795227d87d4cb3de0c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 9 Mar 2024 16:32:18 +0800 Subject: [PATCH 26/86] =?UTF-8?q?CRM=EF=BC=9Acode=20review=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E6=80=BB=E9=87=8F=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 +-- ...CrmStatisticsCustomerByUserBaseRespVO.java | 6 ++-- ...atisticsCustomerContractSummaryRespVO.java | 8 ++--- .../customer/CrmStatisticsCustomerReqVO.java | 6 +++- .../CrmStatisticsCustomerMapper.java | 13 ++++---- .../CrmStatisticsCustomerServiceImpl.java | 29 +++++++++--------- .../CrmStatisticsCustomerMapper.xml | 13 +++++++- yudao-server/pom.xml | 30 +++++++++---------- 8 files changed, 63 insertions(+), 46 deletions(-) diff --git a/pom.xml b/pom.xml index 3a66524bc1..9cf34eb372 100644 --- a/pom.xml +++ b/pom.xml @@ -16,12 +16,12 @@ yudao-module-system yudao-module-infra - + yudao-module-bpm - + yudao-module-crm diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java index 340e930663..41fa9152e9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java @@ -5,12 +5,14 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** - * 用户客户统计响应 Base VO + * 用户客户统计响应 Base Response VO + * + * 目的:可以统一拼接子 VO 的 ownerUserId、ownerUserName 属性 */ @Data public class CrmStatisticsCustomerByUserBaseRespVO { - @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @JsonIgnore private Long ownerUserId; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java index 019309f8e0..ec1d273034 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java @@ -5,13 +5,13 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; @Schema(description = "管理后台 - CRM 客户转化率分析 VO") @Data @@ -43,14 +43,14 @@ public class CrmStatisticsCustomerContractSummaryRespVO { @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "外呼") private String sourceName; - @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @JsonIgnore private Long ownerUserId; @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") private String ownerUserName; - @Schema(description = "创建人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @JsonIgnore private String creatorUserId; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java index a7aaa4da54..c5d5acbc34 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java @@ -12,7 +12,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -@Schema(description = "管理后台 - CRM 数据统计 员工客户分析 Request VO") +@Schema(description = "管理后台 - CRM 数据统计的员工客户分析 Request VO") @Data public class CrmStatisticsCustomerReqVO { @@ -39,12 +39,16 @@ public class CrmStatisticsCustomerReqVO { @NotEmpty(message = "时间范围不能为空") private LocalDateTime[] times; + // TODO @dhb52:这个时间间隔,建议前端传递;例如说:字段叫 interval,枚举有天、周、月、季度、年。因为一般分析类的系统,都是交给用户选择筛选时间间隔,而我们这里是默认根据日期选项,默认对应的 interval 而已 + // 然后实现上,可以在 common 包的 enums 加个 DateIntervalEnum,里面一个是 interval 字段,枚举过去,然后有个 pattern 字段,用于格式化时间格式; + // 这样的话,可以通过 interval 获取到 pattern,然后前端就可以根据 pattern 格式化时间,计算还是交给数据库 /** * group by DATE_FORMAT(field, #{dateFormat}) */ @Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m") private String sqlDateFormat; + // TODO @dhb52:这个字段,目前是不是没啥用呀? /** * 数据类型 {@link CrmBizTypeEnum} */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 6bababa26a..19bd76fc32 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -13,17 +13,18 @@ import java.util.List; @Mapper public interface CrmStatisticsCustomerMapper { - List selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + // TODO @dhb52:拼写,GroupBy。一般 idea 如果出现绿色的警告,可能是单词拼写错误,建议是要修改的哈; + List selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review - List selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review - List selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); // 已经 review - List selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); + List selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review - List selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); + List selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review - List selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); + List selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review List selectFollowupRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index 6b664dce55..c9654a68eb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -55,7 +55,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @Resource private DictDataApi dictDataApi; - @Override public List getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 @@ -66,14 +65,17 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取分项统计数据 + // TODO @dhb52:如果是 list 变量,要么 List 要么 s 后缀 reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); final List customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyDate(reqVO); final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyDate(reqVO); // 3. 获取时间序列 + // TODO @dhb52:3 和 4 其实做的是一类事情,所以可以考虑 3.1 获取时间序列、3.2 合并统计数据 这样注释;然后中间就不空行了;就是说,一般空行的目的,是让逻辑分片,看着整体性更好,但是不能让逻辑感觉碎碎的; final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); // 4. 合并统计数据 + // TODO @dhb52:这个是不是要 add 到 respVoList 里?或者还可以 convertList(times, time -> new CrmStatisticsCustomerDealCycleByDateRespVO()...) List respVoList = new ArrayList<>(times.size()); final Map customerCreateCountMap = convertMap(customerCreateCount, CrmStatisticsCustomerSummaryByDateRespVO::getTime, @@ -86,7 +88,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0)) .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)) )); - return respVoList; } @@ -131,7 +132,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 4. 拼接用户信息 appendUserInfo(respVoList); - return respVoList; } @@ -202,7 +202,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 4. 拼接用户信息 appendUserInfo(respVoList); - return respVoList; } @@ -290,7 +289,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time) .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D)) )); - return respVoList; } @@ -337,9 +335,8 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe */ private void appendUserInfo(List respVoList) { Map userMap = adminUserApi.getUserMap(convertSet(respVoList, - CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); - respVoList.forEach(vo -> MapUtils.findAndThen(userMap, - vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); + CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); + respVoList.forEach(vo -> MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); } /** @@ -349,16 +346,17 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe * @return 用户编号数组 */ private List getUserIds(CrmStatisticsCustomerReqVO reqVO) { + // 情况一:选中某个用户 if (ObjUtil.isNotNull(reqVO.getUserId())) { return List.of(reqVO.getUserId()); - } else { - // 1. 获得部门列表 - final Long deptId = reqVO.getDeptId(); - List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); - deptIds.add(deptId); - // 2. 获得用户编号 - return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + final Long deptId = reqVO.getDeptId(); + List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); + deptIds.add(deptId); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); } @@ -380,6 +378,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe * @param endTime 结束时间 * @return 时间序列 */ + // TODO @dhb52:可以抽象到 DateUtils 里,开始时间、结束时间,事件间隔,然后返回这个哈; private List generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) { boolean byMonth = queryByMonth(startTime, endTime); List times = CollUtil.newArrayList(); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index 3fd52f3e72..fce255651f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -2,11 +2,14 @@ + + @@ -21,6 +25,8 @@ + + + + SELECT - - DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time, - COUNT(*) AS customerCreateCount - FROM crm_customer - WHERE deleted = 0 - AND owner_user_id IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND - - #{times[1],javaType=java.time.LocalDateTime} - GROUP BY time + DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time, + COUNT(*) AS customerCreateCount + FROM crm_customer + WHERE deleted = 0 + AND owner_user_id IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + GROUP BY time - - - - - - - - - - - - - - + + - - - - From 4ac28603b8df276a6f402dc170e8a3330888e0cd Mon Sep 17 00:00:00 2001 From: dhb52 Date: Sun, 10 Mar 2024 10:30:25 +0800 Subject: [PATCH 31/86] =?UTF-8?q?feat:=20[CRM-=E5=AE=A2=E6=88=B7=E5=88=86?= =?UTF-8?q?=E6=9E=90]=E5=A2=9E=E5=8A=A0[=E6=97=B6=E9=97=B4=E9=97=B4?= =?UTF-8?q?=E9=9A=94]=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/DateIntervalEnum.java | 48 ++++++++++++ .../module/crm/enums/ErrorCodeConstants.java | 3 + .../customer/CrmStatisticsCustomerReqVO.java | 19 +++-- .../CrmStatisticsCustomerServiceImpl.java | 75 ++++++++++++++++++- 4 files changed, 134 insertions(+), 11 deletions(-) create mode 100644 yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java new file mode 100644 index 0000000000..9a614ddc9d --- /dev/null +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.framework.common.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 时间间隔类型枚举 + * + * @author dhb52 + */ +@Getter +@AllArgsConstructor +public enum DateIntervalEnum implements IntArrayValuable { + + TODAY(1, "今天"), + YESTERDAY(2, "昨天"), + THIS_WEEK(3, "本周"), + LAST_WEEK(4, "上周"), + THIS_MONTH(5, "本月"), + LAST_MONTH(6, "上月"), + THIS_QUARTER(7, "本季度"), + LAST_QUARTER(8, "上季度"), + THIS_YEAR(9, "本年"), + LAST_YEAR(10, "去年"), + CUSTOMER(11, "自定义"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + + /** + * 名称 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index 4a0976bb18..d49f6068cf 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -103,4 +103,7 @@ public interface ErrorCodeConstants { ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); + // ========== 数据统计 1_020_014_000 ========== + ErrorCode STATISTICS_CUSTOMER_TIMES_NOT_SET = new ErrorCode(1_020_014_000, "自定义时间间隔,必须输入时间区间"); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java index 13b3adda7d..38f15cf034 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java @@ -1,7 +1,8 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -27,22 +28,26 @@ public class CrmStatisticsCustomerReqVO { /** * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 - *

* 后续,可能会支持选择部分用户进行查询 */ @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") private List userIds; - @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}") + private Integer intervalType; + + /** + * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间 + * 并作为参数传递给Mapper + */ + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @NotEmpty(message = "时间范围不能为空") private LocalDateTime[] times; - // TODO @dhb52:这个时间间隔,建议前端传递;例如说:字段叫 interval,枚举有天、周、月、季度、年。因为一般分析类的系统,都是交给用户选择筛选时间间隔,而我们这里是默认根据日期选项,默认对应的 interval 而已 - // 然后实现上,可以在 common 包的 enums 加个 DateIntervalEnum,里面一个是 interval 字段,枚举过去,然后有个 pattern 字段,用于格式化时间格式; - // 这样的话,可以通过 interval 获取到 pattern,然后前端就可以根据 pattern 格式化时间,计算还是交给数据库 /** * group by DATE_FORMAT(field, #{dateFormat}) + * 非前端传递, 由Service计算后传递给Mapper的参数 */ @Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m") private String sqlDateFormat; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index a4c3f4ddfa..f951e25f54 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; @@ -24,8 +27,10 @@ import java.util.List; import java.util.Map; import java.util.stream.Stream; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.STATISTICS_CUSTOMER_TIMES_NOT_SET; /** * CRM 客户分析 Service 实现类 @@ -63,7 +68,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取分项统计数据 - reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); + initParams(reqVO); List customerCreateCountVoList = customerMapper.selectCustomerCreateCountGroupByDate(reqVO); List customerDealCountVoList = customerMapper.selectCustomerDealCountGroupByDate(reqVO); @@ -94,6 +99,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取分项统计数据 + initParams(reqVO); List customerCreateCount = customerMapper.selectCustomerCreateCountGroupByUser(reqVO); List customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO); List contractPrice = customerMapper.selectContractPriceGroupByUser(reqVO); @@ -139,7 +145,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取分项统计数据 - reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); + initParams(reqVO); List followupRecordCount = customerMapper.selectFollowupRecordCountGroupByDate(reqVO); List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByDate(reqVO); @@ -170,6 +176,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取分项统计数据 + initParams(reqVO); List followupRecordCount = customerMapper.selectFollowupRecordCountGroupByUser(reqVO); List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByUser(reqVO); @@ -204,6 +211,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获得排行数据 + initParams(reqVO); List respVoList = customerMapper.selectFollowupRecordCountGroupByType(reqVO); // 3. 获取字典数据 @@ -227,6 +235,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取统计数据 + initParams(reqVO); List respVoList = customerMapper.selectContractSummary(reqVO); // 3. 设置 创建人、负责人、行业、来源 @@ -261,7 +270,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取分项统计数据 - reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); + initParams(reqVO); List customerDealCycle = customerMapper.selectCustomerDealCycleGroupByDate(reqVO); // 3. 合并统计数据 @@ -287,6 +296,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取分项统计数据 + initParams(reqVO); List customerDealCycle = customerMapper.selectCustomerDealCycleGroupByUser(reqVO); List customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO); @@ -363,7 +373,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe * @param endTime 结束时间 * @return 时间序列 */ - // TODO @dhb52:可以抽象到 DateUtils 里,开始时间、结束时间,事件间隔,然后返回这个哈; private List generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) { boolean byMonth = queryByMonth(startTime, endTime); List times = CollUtil.newArrayList(); @@ -389,4 +398,62 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe return queryByMonth(startTime, endTime) ? SQL_DATE_FORMAT_BY_MONTH : SQL_DATE_FORMAT_BY_DAY; } + private void initParams(CrmStatisticsCustomerReqVO reqVO) { + final Integer intervalType = reqVO.getIntervalType(); + + // 1. 自定义时间间隔,必须输入起始日期-结束日期 + if (DateIntervalEnum.CUSTOMER.getType().equals(intervalType)) { + if (ObjUtil.isEmpty(reqVO.getTimes()) || reqVO.getTimes().length != 2) { + throw exception(STATISTICS_CUSTOMER_TIMES_NOT_SET); + } + // 设置 mapper sqlDateFormat 参数 + reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); + // 自定义日期无需计算日期参数 + return; + } + + // 2. 根据时间区间类型计算时间段区间日期 + DateTime beginDate = null; + DateTime endDate = null; + if (DateIntervalEnum.TODAY.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfDay(DateUtil.date()); + endDate = DateUtil.endOfDay(DateUtil.date()); + } else if (DateIntervalEnum.YESTERDAY.getType().equals(intervalType)) { + beginDate = DateUtil.offsetDay(DateUtil.date(), -1); + endDate = DateUtil.offsetDay(DateUtil.date(), -1); + } else if (DateIntervalEnum.THIS_WEEK.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfWeek(DateUtil.date()); + endDate = DateUtil.endOfWeek(DateUtil.date()); + } else if (DateIntervalEnum.LAST_WEEK.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1)); + endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1)); + } else if (DateIntervalEnum.THIS_MONTH.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfMonth(DateUtil.date()); + endDate = DateUtil.endOfMonth(DateUtil.date()); + } else if (DateIntervalEnum.LAST_MONTH.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1)); + endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1)); + } else if (DateIntervalEnum.THIS_QUARTER.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfQuarter(DateUtil.date()); + endDate = DateUtil.endOfQuarter(DateUtil.date()); + } else if (DateIntervalEnum.LAST_QUARTER.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3)); + endDate = DateUtil.endOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3)); + } else if (DateIntervalEnum.THIS_YEAR.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfYear(DateUtil.date()); + endDate = DateUtil.endOfYear(DateUtil.date()); + } else if (DateIntervalEnum.LAST_YEAR.getType().equals(intervalType)) { + beginDate = DateUtil.beginOfYear(DateUtil.offsetMonth(DateUtil.date(), -12)); + endDate = DateUtil.endOfYear(DateUtil.offsetMonth(DateUtil.date(), -12)); + } + + // 3. 计算开始、结束日期时间,并设置reqVo + LocalDateTime[] times = new LocalDateTime[2]; + times[0] = LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.of(beginDate)); + times[1] = LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.of(endDate)); + // 3.1 设置 mapper 时间区间 参数 + reqVO.setTimes(times); + // 3.2 设置 mapper sqlDateFormat 参数 + reqVO.setSqlDateFormat(getSqlDateFormat(times[0], times[1])); + } } From 03213e3254a798101189a9560d1a62bf6f1587ff Mon Sep 17 00:00:00 2001 From: dhb52 Date: Sun, 10 Mar 2024 14:30:59 +0800 Subject: [PATCH 32/86] =?UTF-8?q?fix:=20[CRM-=E5=AE=A2=E6=88=B7=E5=88=86?= =?UTF-8?q?=E6=9E=90]=E6=9B=B4=E6=96=B0http-client=E8=84=9A=E6=9C=AC,?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0intervalType=E8=AF=B7=E6=B1=82=E5=8F=82?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.http | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http index 0c422f9868..9d96e159aa 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http @@ -1,40 +1,40 @@ # == 1. 客户总量分析 == ### 1.1 客户总量分析(按日) -GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&intervalType=11×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} ### 1.2 客户总量分析(按月) -GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} ### 1.3 客户总量统计(按用户) -GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} # == 2. 客户跟进次数分析 == ### 2.1 客户跟进次数分析(按日) -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&intervalType=11×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} ### 2.2 客户跟进次数分析(按月) -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} ### 2.3 客户总量统计(按用户) -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-user?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} # == 3. 客户跟进方式分析 == ### 3.1 客户跟进方式分析 -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-type?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-type?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}} @@ -42,7 +42,7 @@ tenant-id: {{adminTenentId}} # == 4. 客户成交周期 == ### 4.1 合同摘要信息(客户转化率页面) -GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}} @@ -50,19 +50,19 @@ tenant-id: {{adminTenentId}} # == 5. 客户成交周期 == ### 5.1 客户成交周期(按日) -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&intervalType=11×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}} ### 5.2 客户成交周期(按月) -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}} ### 5.3 获取客户成交周期(按用户) -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}} \ No newline at end of file From 0dd36f6c5c563f922d484f74b9a45df73e50e93e Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 10 Mar 2024 19:07:24 +0800 Subject: [PATCH 33/86] =?UTF-8?q?MALL:=20fix=20=E8=AE=A2=E5=8D=95=E4=BB=B7?= =?UTF-8?q?=E6=A0=BC=E5=88=86=E6=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/service/order/TradeOrderUpdateServiceImpl.java | 8 +++++--- .../price/calculator/TradePriceCalculatorHelper.java | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index 13fe2f0c2d..4065ed05ea 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -624,7 +624,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY); } // 1.3 支付价格不能为 0 - int newPayPrice = order.getPayPrice() + order.getAdjustPrice(); + int newPayPrice = order.getPayPrice() + reqVO.getAdjustPrice(); if (newPayPrice <= 0) { throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR); } @@ -635,12 +635,14 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // 3. 更新 TradeOrderItem,需要做 adjustPrice 的分摊 List orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); - List dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, newPayPrice); + List dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, reqVO.getAdjustPrice()); List updateItems = new ArrayList<>(); for (int i = 0; i < orderOrderItems.size(); i++) { TradeOrderItemDO item = orderOrderItems.get(i); + // TODO puhui999: 已有分摊记录的情况下价格是否会不对,也就是说之前订单项 1 分摊了 10 块这次是 -100 + // 那么 setPayPrice 是否改为 (item.getPayPrice()-item.getAdjustPrice()) + dividePrices.get(i) 先减掉原来的价格再加上调价。经过验证可行,修改后订单价格增减都能正确分摊 updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(dividePrices.get(i)) - .setPayPrice(item.getPayPrice() + dividePrices.get(i))); + .setPayPrice((item.getPayPrice() - item.getAdjustPrice()) + dividePrices.get(i))); } tradeOrderItemMapper.updateBatch(updateItems); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java index 7def3e34ef..850226fbb9 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java @@ -254,12 +254,15 @@ public class TradePriceCalculatorHelper { TradeOrderItemDO orderItem = items.get(i); int partPrice; if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 - partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); + // partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); + // pr fix: 改为了使用订单原价来计算比例 + partPrice = (int) (price * (1.0D * orderItem.getPrice() / total)); remainPrice -= partPrice; } else { partPrice = remainPrice; } - Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); + // TODO puhui999: 如果是减价的情况这里过不了 + // Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); prices.add(partPrice); } return prices; From 705a3e53cae4df60995c9e27274bcdf6e5a7607d Mon Sep 17 00:00:00 2001 From: scholar <1145227973@qq.com> Date: Fri, 15 Mar 2024 12:09:19 +0800 Subject: [PATCH 34/86] =?UTF-8?q?CRM=E5=91=98=E5=B7=A5=E4=B8=9A=E7=BB=A9?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1PR=20v2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsPerformanceController.java | 52 ++++++ .../CrmStatisticsPerformanceReqVO.java | 41 +++++ .../CrmStatisticsPerformanceRespVO.java | 24 +++ .../CrmStatisticsPerformanceMapper.java | 41 +++++ .../CrmStatisticsPerformanceService.java | 42 +++++ .../CrmStatisticsPerformanceServiceImpl.java | 99 ++++++++++++ .../CrmStatisticsPerformanceMapper.xml | 152 ++++++++++++++++++ 7 files changed, 451 insertions(+) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceReqVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPerformanceMapper.xml diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java new file mode 100644 index 0000000000..1438a12dba --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsPerformanceService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + + +@Tag(name = "管理后台 - CRM 员工业绩统计") +@RestController +@RequestMapping("/crm/statistics-performance") +@Validated +public class CrmStatisticsPerformanceController { + + @Resource + private CrmStatisticsPerformanceService performanceService; + + @GetMapping("/get-contract-count-performance") + @Operation(summary = "员工业绩-签约合同数量") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance:query')") + public CommonResult> getContractCountPerformance(@Valid CrmStatisticsPerformanceReqVO performanceReqVO) { + return success(performanceService.getContractCountPerformance(performanceReqVO)); + } + + @GetMapping("/get-contract-price-performance") + @Operation(summary = "员工业绩-获得合同金额") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance:query')") + public CommonResult> getContractPriceStaffPerformance(@Valid CrmStatisticsPerformanceReqVO performanceReqVO) { + return success(performanceService.getContractPricePerformance(performanceReqVO)); + } + + @GetMapping("/get-receivable-price-performance") + @Operation(summary = "员工业绩-获得回款金额") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance:query')") + public CommonResult> getReceivablePriceStaffPerformance(@Valid CrmStatisticsPerformanceReqVO performanceReqVO) { + return success(performanceService.getReceivablePricePerformance(performanceReqVO)); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceReqVO.java new file mode 100644 index 0000000000..bfb5c840f5 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceReqVO.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 员工业绩统计 Request VO") +@Data +public class CrmStatisticsPerformanceReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * 负责人用户 id, 当用户为空, 则计算部门下用户 + */ + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + *

+ * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") + private List userIds; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotEmpty(message = "时间范围不能为空") + private LocalDateTime[] times; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceRespVO.java new file mode 100644 index 0000000000..8b217fd41c --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.math.BigDecimal; + + +@Schema(description = "管理后台 - CRM 员工业绩统计 Response VO") +@Data +public class CrmStatisticsPerformanceRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "当月统计结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private BigDecimal currentMonthCount; + + @Schema(description = "上月统计结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private BigDecimal lastMonthCount; + + @Schema(description = "去年同期统计结果", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + private BigDecimal lastYearCount; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java new file mode 100644 index 0000000000..09702f2904 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 员工业绩分析 Mapper + * + * @author scholar + */ +@Mapper +public interface CrmStatisticsPerformanceMapper { + + /** + * 员工签约合同数量 + * + * @param performanceReqVO 参数 + * @return 员工签约合同数量 + */ + List selectContractCountPerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工签约合同金额 + * + * @param performanceReqVO 参数 + * @return 员工签约合同金额 + */ + List selectContractPricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工回款金额 + * + * @param performanceReqVO 参数 + * @return 员工回款金额 + */ + List selectReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java new file mode 100644 index 0000000000..354bbab256 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + + + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; + +import java.util.List; + +/** + * CRM 员工绩效统计 Service 接口 + * + * @author scholar + */ +public interface CrmStatisticsPerformanceService { + + /** + * 员工签约合同数量分析 + * + * @param performanceReqVO 排行参数 + * @return 员工签约合同数量排行分析 + */ + List getContractCountPerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工签约合同金额分析 + * + * @param performanceReqVO 排行参数 + * @return 员工签约合同金额分析 + */ + List getContractPricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + /** + * 员工获得回款金额分析 + * + * @param performanceReqVO 排行参数 + * @return 员工获得回款金额分析 + */ + List getReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java new file mode 100644 index 0000000000..067be4f431 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPerformanceMapper; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import jakarta.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * CRM 员工业绩分析 Service 实现类 + * + * @author scholar + */ +@Service +@Validated +public class CrmStatisticsPerformanceServiceImpl implements CrmStatisticsPerformanceService { + + @Resource + private CrmStatisticsPerformanceMapper performanceMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + + @Override + public List getContractCountPerformance(CrmStatisticsPerformanceReqVO performanceReqVO) { + return getPerformance(performanceReqVO, performanceMapper::selectContractCountPerformance); + } + + @Override + public List getContractPricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO) { + return getPerformance(performanceReqVO, performanceMapper::selectContractPricePerformance); + } + + @Override + public List getReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO) { + return getPerformance(performanceReqVO, performanceMapper::selectReceivablePricePerformance); + } + + /** + * 获得员工业绩数据 + * + * @param performanceReqVO 参数 + * @param performanceFunction 排行榜方法 + * @return 排行版数据 + */ + private List getPerformance(CrmStatisticsPerformanceReqVO performanceReqVO, Function> performanceFunction) { + + // 1. 获得用户编号数组 + final List userIds = getUserIds(performanceReqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + performanceReqVO.setUserIds(userIds); + // 2. 获得排行数据 + List performance = performanceFunction.apply(performanceReqVO); + if (CollUtil.isEmpty(performance)) { + return Collections.emptyList(); + } + return performance; + } + + /** + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsPerformanceReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return List.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + final Long deptId = reqVO.getDeptId(); + List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); + deptIds.add(deptId); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPerformanceMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPerformanceMapper.xml new file mode 100644 index 0000000000..10b952bac2 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPerformanceMapper.xml @@ -0,0 +1,152 @@ + + + + + + + + + + + From ce013a2562883f22884ce267ac8f980dd86c73d4 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 24 Mar 2024 17:15:56 +0800 Subject: [PATCH 35/86] =?UTF-8?q?CRM:=20=E6=96=B0=E5=A2=9E=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E8=A1=8C=E4=B8=9A=E3=80=81=E6=9D=A5=E6=BA=90=E3=80=81?= =?UTF-8?q?=E7=BA=A7=E5=88=AB=E7=BB=9F=E8=AE=A1=E6=95=B0=E6=8D=AE=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.java | 24 +++ .../CrmStatisticCustomerIndustryRespVO.java | 27 +++ .../CrmStatisticCustomerLevelRespVO.java | 27 +++ .../CrmStatisticCustomerSourceRespVO.java | 27 +++ .../CrmStatisticsCustomerMapper.java | 9 + .../CrmStatisticsCustomerService.java | 27 +++ .../CrmStatisticsCustomerServiceImpl.java | 164 +++++++++++++----- .../CrmStatisticsCustomerMapper.xml | 64 +++++++ .../module/system/api/dict/DictDataApi.java | 17 ++ yudao-server/pom.xml | 10 +- 10 files changed, 345 insertions(+), 51 deletions(-) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index 4a0b2e760e..4b45a9c280 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -82,4 +85,25 @@ public class CrmStatisticsCustomerController { return success(customerService.getCustomerDealCycleByUser(reqVO)); } + @GetMapping("/get-customer-industry-summary") + @Operation(summary = "获取客户行业统计数据") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerIndustry(reqVO)); + } + + @GetMapping("/get-customer-source-summary") + @Operation(summary = "获取客户来源统计数据") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerSource(reqVO)); + } + + @GetMapping("/get-customer-level-summary") + @Operation(summary = "获取客户级别统计数据") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerLevel(reqVO)); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java new file mode 100644 index 0000000000..4811740923 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户行业分析 VO") +@Data +public class CrmStatisticCustomerIndustryRespVO { + + @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer industryId; + @Schema(description = "客户行业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String industryName; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + + @Schema(description = "行业占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double industryPortion; + + @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double dealPortion; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java new file mode 100644 index 0000000000..74e06918c9 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户级别分析 VO") +@Data +public class CrmStatisticCustomerLevelRespVO { + + @Schema(description = "客户级别ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer level; + @Schema(description = "客户级别名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String levelName; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + + @Schema(description = "级别占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double levelPortion; + + @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double dealPortion; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java new file mode 100644 index 0000000000..2edba39edb --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户来源分析 VO") +@Data +public class CrmStatisticCustomerSourceRespVO { + + @Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer source; + @Schema(description = "客户来源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private String sourceName; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + + @Schema(description = "来源占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double sourcePortion; + + @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double dealPortion; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 19bd76fc32..0e8df55657 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -42,4 +45,10 @@ public interface CrmStatisticsCustomerMapper { List selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); + + List selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); + + List selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index 546124701a..5402c706de 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import java.util.List; @@ -77,4 +80,28 @@ public interface CrmStatisticsCustomerService { */ List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); + /** + * 获取客户行业统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取客户来源统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSource(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取客户级别统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index c9654a68eb..e2a3752911 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -6,6 +6,9 @@ import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -78,15 +81,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // TODO @dhb52:这个是不是要 add 到 respVoList 里?或者还可以 convertList(times, time -> new CrmStatisticsCustomerDealCycleByDateRespVO()...) List respVoList = new ArrayList<>(times.size()); final Map customerCreateCountMap = convertMap(customerCreateCount, - CrmStatisticsCustomerSummaryByDateRespVO::getTime, - CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); + CrmStatisticsCustomerSummaryByDateRespVO::getTime, + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); final Map customerDealCountMap = convertMap(customerDealCount, - CrmStatisticsCustomerSummaryByDateRespVO::getTime, - CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); + CrmStatisticsCustomerSummaryByDateRespVO::getTime, + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); times.forEach(time -> respVoList.add( - new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time) - .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0)) - .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)) + new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time) + .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0)) + .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)) )); return respVoList; } @@ -108,25 +111,25 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 3. 合并统计数据 final Map customerCreateCountMap = convertMap(customerCreateCount, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); final Map customerDealCountMap = convertMap(customerDealCount, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); final Map contractPriceMap = convertMap(contractPrice, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); final Map receivablePriceMap = convertMap(receivablePrice, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); List respVoList = new ArrayList<>(userIds.size()); userIds.forEach(userId -> { final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO(); vo.setOwnerUserId(userId); vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0)) - .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)) - .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO)) - .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO)); + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)) + .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO)) + .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO)); respVoList.add(vo); }); @@ -156,15 +159,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 4. 合并统计数据 List respVoList = new ArrayList<>(times.size()); final Map followupRecordCountMap = convertMap(followupRecordCount, - CrmStatisticsFollowupSummaryByDateRespVO::getTime, - CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); + CrmStatisticsFollowupSummaryByDateRespVO::getTime, + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); final Map followupCustomerCountMap = convertMap(followupCustomerCount, - CrmStatisticsFollowupSummaryByDateRespVO::getTime, - CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); + CrmStatisticsFollowupSummaryByDateRespVO::getTime, + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); times.forEach(time -> respVoList.add( - new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time) - .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0)) - .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0)) + new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time) + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0)) + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0)) )); return respVoList; @@ -186,16 +189,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 3. 合并统计数据 final Map followupRecordCountMap = convertMap(followupRecordCount, - CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); final Map followupCustomerCountMap = convertMap(followupCustomerCount, - CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); List respVoList = new ArrayList<>(userIds.size()); userIds.forEach(userId -> { final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO() - .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0)) - .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0)); + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0)) + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0)); vo.setOwnerUserId(userId); respVoList.add(vo); }); @@ -221,7 +224,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 3. 获取字典数据 List followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE); final Map followUpTypeMap = convertMap(followUpTypes, - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); + DictDataRespDTO::getValue, DictDataRespDTO::getLabel); respVoList.forEach(vo -> { vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType())); }); @@ -244,19 +247,19 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 3. 设置 创建人、负责人、行业、来源 // 获取客户所属行业 Map industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY), - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); + DictDataRespDTO::getValue, DictDataRespDTO::getLabel); // 获取客户来源 Map sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE), - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); + DictDataRespDTO::getValue, DictDataRespDTO::getLabel); // 获取创建人、负责人列表 Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList, - vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); + vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); respVoList.forEach(vo -> { MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName); MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName); MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()), - user -> vo.setCreatorUserName(user.getNickname())); + user -> vo.setCreatorUserName(user.getNickname())); MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); }); @@ -283,11 +286,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 4. 合并统计数据 List respVoList = new ArrayList<>(times.size()); final Map customerDealCycleMap = convertMap(customerDealCycle, - CrmStatisticsCustomerDealCycleByDateRespVO::getTime, - CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); + CrmStatisticsCustomerDealCycleByDateRespVO::getTime, + CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); times.forEach(time -> respVoList.add( - new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time) - .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D)) + new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time) + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D)) )); return respVoList; } @@ -308,16 +311,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe // 3. 合并统计数据 final Map customerDealCycleMap = convertMap(customerDealCycle, - CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); + CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); final Map customerDealCountMap = convertMap(customerDealCount, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); List respVoList = new ArrayList<>(userIds.size()); userIds.forEach(userId -> { final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO() - .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0)) - .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)); + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0)) + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)); vo.setOwnerUserId(userId); respVoList.add(vo); }); @@ -328,6 +331,75 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe return respVoList; } + @Override + public List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 + List industryRespVOList = customerMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO); + if (CollUtil.isEmpty(industryRespVOList)) { + return Collections.emptyList(); + } + + return convertList(industryRespVOList, item -> { + if (ObjUtil.isNull(item.getIndustryId())) { + return item; + } + item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId())); + return item; + }); + } + + @Override + public List getCustomerSource(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 + List sourceRespVOList = customerMapper.selectCustomerSourceListGroupbySource(reqVO); + if (CollUtil.isEmpty(sourceRespVOList)) { + return Collections.emptyList(); + } + + return convertList(sourceRespVOList, item -> { + if (ObjUtil.isNull(item.getSource())) { + return item; + } + item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource())); + return item; + }); + } + + @Override + public List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 + List levelRespVOList = customerMapper.selectCustomerLevelListGroupbyLevel(reqVO); + if (CollUtil.isEmpty(levelRespVOList)) { + return Collections.emptyList(); + } + + return convertList(levelRespVOList, item -> { + if (ObjUtil.isNull(item.getLevel())) { + return item; + } + item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel())); + return item; + }); + } + /** * 拼接用户信息(昵称) * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index fce255651f..758da4fcd0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -249,4 +249,68 @@ GROUP BY a.owner_user_id + + + + diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java index 5c47f4de3c..b75684de05 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.system.api.dict; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import java.util.Collection; @@ -33,6 +35,21 @@ public interface DictDataApi { */ DictDataRespDTO getDictData(String type, String value); + /** + * 获得指定的字典标签,从缓存中 + * + * @param type 字典类型 + * @param value 字典数据值 + * @return 字典标签 + */ + default String getDictDataLabel(String type, Integer value) { + DictDataRespDTO dictData = getDictData(type, String.valueOf(value)); + if (ObjUtil.isNull(dictData)) { + return StrUtil.EMPTY; + } + return dictData.getLabel(); + } + /** * 解析获得指定的字典数据,从缓存中 * diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index ff17b298d3..ade54c0685 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -95,11 +95,11 @@ - - cn.iocoder.boot - yudao-module-erp-biz - ${revision} - + + + + + From 22191e81e3a74f90dd20efe5d4db2d7938aa91de Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 24 Mar 2024 22:24:46 +0800 Subject: [PATCH 36/86] =?UTF-8?q?CRM:=20=E6=96=B0=E5=A2=9E=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E5=8C=BA=E5=9F=9F=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.java | 8 ++++ .../CrmStatisticCustomerAreaRespVO.java | 27 ++++++++++++ .../CrmStatisticsCustomerMapper.java | 3 ++ .../CrmStatisticsCustomerService.java | 9 ++++ .../CrmStatisticsCustomerServiceImpl.java | 44 ++++++++++++++++--- .../CrmStatisticsCustomerMapper.xml | 21 +++++++++ 6 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index 4b45a9c280..0422bff4b9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; @@ -106,4 +107,11 @@ public class CrmStatisticsCustomerController { return success(customerService.getCustomerLevel(reqVO)); } + @GetMapping("/get-customer-area-summary") + @Operation(summary = "获取客户地区统计数据") + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") + public CommonResult> getCustomerArea(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getCustomerArea(reqVO)); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java new file mode 100644 index 0000000000..5f6924d58d --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - CRM 客户省份分析 VO") +@Data +public class CrmStatisticCustomerAreaRespVO { + + @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer areaId; + @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省") + private String areaName; + + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer customerCount; + + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer dealCount; + + @Schema(description = "省份占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double areaPortion; + + @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Double dealPortion; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 0e8df55657..168d0fb515 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; @@ -51,4 +52,6 @@ public interface CrmStatisticsCustomerMapper { List selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); + List selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index 5402c706de..73bd437d6c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; @@ -104,4 +105,12 @@ public interface CrmStatisticsCustomerService { */ List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); + /** + * 获取客户地区统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerArea(CrmStatisticsCustomerReqVO reqVO); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index e2a3752911..69cbd64421 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -5,7 +5,11 @@ import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; @@ -30,6 +34,7 @@ import java.util.Map; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; /** @@ -256,11 +261,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); respVoList.forEach(vo -> { - MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName); - MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName); - MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()), + findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName); + findAndThen(sourceMap, vo.getSource(), vo::setSourceName); + findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()), user -> vo.setCreatorUserName(user.getNickname())); - MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); + findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); }); return respVoList; @@ -400,6 +405,35 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe }); } + @Override + public List getCustomerArea(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户地区统计数据 + List list = customerMapper.selectSummaryListByAreaId(reqVO); + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + + // 拼接数据 + List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); + areaList.add(new Area().setId(null).setName("未知")); + Map areaMap = convertMap(areaList, Area::getId); + List customerAreaRespVOList = convertList(list, item -> { + Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); + if (parentId == null) { + return item; + } + findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); + return item; + }); + return customerAreaRespVOList; + } + /** * 拼接用户信息(昵称) * @@ -408,7 +442,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe private void appendUserInfo(List respVoList) { Map userMap = adminUserApi.getUserMap(convertSet(respVoList, CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); - respVoList.forEach(vo -> MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); + respVoList.forEach(vo -> findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); } /** diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index 758da4fcd0..e843d1dee6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -312,5 +312,26 @@ GROUP BY level; + From 210b4e54d703cd639435689266a19e35ae1e3ea9 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Wed, 27 Mar 2024 09:16:12 +0800 Subject: [PATCH 37/86] =?UTF-8?q?=E4=BB=BF=E9=92=89=E9=92=89=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AE=BE=E8=AE=A1-=E5=90=8E=E7=AB=AF=E5=AE=9E?= =?UTF-8?q?=E7=8E=B010%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmSimpleModelNodeType.java | 44 +++++ .../definition/BpmSimpleModelController.java | 31 ++++ .../vo/simple/BpmSimpleModelNodeVO.java | 37 +++++ .../vo/simple/BpmSimpleModelSaveReqVO.java | 21 +++ .../core/enums/BpmnModelConstants.java | 10 ++ .../flowable/core/util/BpmnModelUtils.java | 156 +++++++++++++++++- .../service/definition/BpmModelService.java | 9 + .../definition/BpmModelServiceImpl.java | 9 +- .../definition/BpmSimpleModelService.java | 18 ++ .../definition/BpmSimpleModelServiceImpl.java | 44 +++++ 10 files changed, 374 insertions(+), 5 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java new file mode 100644 index 0000000000..357804fecb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.enums.definition; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Objects; + +/** + * 仿钉钉的流程器设计器的模型节点类型 + * + * @author jason + */ +@Getter +@AllArgsConstructor +public enum BpmSimpleModelNodeType implements IntArrayValuable { + + START_NODE(-1, "开始节点"), + START_USER_NODE(0, "发起人结点"), + APPROVE_USER_NODE (1, "审批人节点"), + EXCLUSIVE_GATEWAY_NODE(4, "排他网关"), + END_NODE(-2, "结束节点"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); + + private final Integer type; + private final String name; + + public static boolean isGatewayNode(Integer type) { + // TODO 后续增加并行网关的支持 + return Objects.equals(EXCLUSIVE_GATEWAY_NODE.getType(), type); + } + + public static BpmSimpleModelNodeType valueOf(Integer type) { + return ArrayUtil.firstMatch(nodeType -> nodeType.getType().equals(type), values()); + } + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java new file mode 100644 index 0000000000..f6fb33e167 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmSimpleModelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - BPM 仿钉钉流程设计器") +@RestController +@RequestMapping("/bpm/simple") +public class BpmSimpleModelController { + @Resource + private BpmSimpleModelService bpmSimpleModelService; + + @PostMapping("/save") + @Operation(summary = "保存仿钉钉流程设计模型") + @PreAuthorize("@ss.hasPermission('bpm:model:update')") + public CommonResult saveSimpleModel(@Valid @RequestBody BpmSimpleModelSaveReqVO reqVO) { + return success(bpmSimpleModelService.saveSimpleModel(reqVO)); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java new file mode 100644 index 0000000000..19152bd2a6 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - 仿钉钉流程设计模型节点 VO") +@Data +public class BpmSimpleModelNodeVO { + + @Schema(description = "模型节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartEvent_1") + @NotEmpty(message = "模型节点编号不能为空") + private String id; + + @Schema(description = "模型节点类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "模型节点类型不能为空") + @InEnum(BpmSimpleModelNodeType.class) + private Integer type; + + @Schema(description = "模型节点名称", example = "领导审批") + private String name; + + @Schema(description = "孩子节点") + private BpmSimpleModelNodeVO childNode; + + @Schema(description = "网关节点的条件节点") + private List conditionNodes; + + @Schema(description = "节点的属性") + private Map attributes; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java new file mode 100644 index 0000000000..881adc89f2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - 仿钉钉流程设计模型的新增/修改 Request VO") +@Data +public class BpmSimpleModelSaveReqVO { + + @Schema(description = "流程模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "流程模型编号不能为空") + private String modelId; // 对应 Flowable act_re_model 表 ID_ 字段 + + @Schema(description = "仿钉钉流程设计模型对象", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "仿钉钉流程设计模型对象不能为空") + @Valid + private BpmSimpleModelNodeVO simpleModelBody; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java index 3eb6981ef9..5283baa251 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java @@ -23,4 +23,14 @@ public interface BpmnModelConstants { */ String USER_TASK_CANDIDATE_PARAM = "candidateParam"; + /** + * BPMN Start Event 节点 Id, 用于后端生成 Start Event 节点 + */ + String START_EVENT_ID = "StartEvent_1"; + + /** + * BPMN End Event 节点 Id, 用于后端生成 End Event 节点 + */ + String END_EVENT_ID = "EndEvent_1"; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index bcf82d731c..b66ef6a97e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -1,15 +1,25 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.TypeReference; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import org.flowable.bpmn.BpmnAutoLayout; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; import org.flowable.common.engine.impl.util.io.BytesStreamSource; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * 流程模型转操作工具类 @@ -326,4 +336,148 @@ public class BpmnModelUtils { return userTaskList; } + /** + * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善) + * @param processId 流程标识 + * @param processName 流程名称 + * @param simpleModelNode 仿钉钉流程设计模型数据结构 + * @return Bpmn Model + */ + public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName,BpmSimpleModelNodeVO simpleModelNode) { + BpmnModel bpmnModel = new BpmnModel(); + Process mainProcess = new Process(); + mainProcess.setId(processId); + mainProcess.setName(processName); + mainProcess.setExecutable(Boolean.TRUE); + bpmnModel.addProcess(mainProcess); + // 目前前端传进来的节点。 没有 start event 节点 和 end event 节点。 + // 在最前面加上 start event node + BpmSimpleModelNodeVO startEventNode = new BpmSimpleModelNodeVO(); + startEventNode.setId(BpmnModelConstants.START_EVENT_ID); + startEventNode.setName("开始"); + startEventNode.setType(BpmSimpleModelNodeType.START_NODE.getType()); + startEventNode.setChildNode(simpleModelNode); + // 添加 FlowNode + addBpmnFlowNode(mainProcess, startEventNode); + // 单独添加 end event 节点 + addBpmnEndEventNode(mainProcess); + // 添加节点之间的连线 Sequence Flow + addBpmnSequenceFlow(mainProcess, startEventNode); + // 自动布局 + new BpmnAutoLayout(bpmnModel).execute(); + + return bpmnModel; + } + + private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node) { + // 节点为 null 退出 + if (node == null) { + return; + } + BpmSimpleModelNodeVO childNode = node.getChildNode(); + // 如果后续节点为 null. 添加与结束节点的连线 + if (childNode == null) { + addBpmnSequenceFlowElement(mainProcess, node.getId(),BpmnModelConstants.END_EVENT_ID, null); + return; + } + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); + Assert.notNull(nodeType, "模型节点类型不支持"); + switch(nodeType){ + case START_NODE : + case START_USER_NODE : + case APPROVE_USER_NODE : + addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null); + break; + default : { + // TODO 其它节点类型的实现 + } + } + // 递归调用后续节点 + addBpmnSequenceFlow(mainProcess, childNode); + } + + private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String conditionExpression) { + SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); + if (StrUtil.isNotEmpty(conditionExpression)) { + sequenceFlow.setConditionExpression(conditionExpression); + } + mainProcess.addFlowElement(sequenceFlow); + + } + + private static void addBpmnFlowNode(Process mainProcess, BpmSimpleModelNodeVO simpleModelNode) { + // 节点为 null 退出 + if (simpleModelNode == null) { + return; + } + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); + Assert.notNull(nodeType, "模型节点类型不支持"); + switch(nodeType){ + case START_NODE : + addBpmnStartEventNode(mainProcess, simpleModelNode); + break; + case START_USER_NODE : + case APPROVE_USER_NODE : + addBpmnUserTaskEventNode(mainProcess, simpleModelNode); + break; + default : { + // TODO 其它节点类型的实现 + } + } + + // 如果不是网关类型的接口, 并且chileNode为空退出 + if (!BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) { + return; + } + + // 如果是网关类型接口. 递归添加条件节点 + if (BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) { + for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) { + addBpmnFlowNode(mainProcess, node); + } + } + + // chileNode不为空,递归添加子节点 + if (simpleModelNode.getChildNode() != null) { + addBpmnFlowNode(mainProcess, simpleModelNode.getChildNode()); + } + } + + private static void addBpmnEndEventNode(Process mainProcess) { + EndEvent endEvent = new EndEvent(); + endEvent.setId(BpmnModelConstants.END_EVENT_ID); + endEvent.setName("结束"); + mainProcess.addFlowElement(endEvent); + } + + private static void addBpmnUserTaskEventNode(Process mainProcess, BpmSimpleModelNodeVO node) { + UserTask userTask = new UserTask(); + userTask.setId(node.getId()); + userTask.setName(node.getName()); + Integer candidateStrategy = MapUtil.getInt(node.getAttributes(),BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); + List candidateParam = MapUtil.get(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, new TypeReference<>() {}); + // 添加自定义属性 + addExtensionAttribute(userTask, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, + candidateStrategy == null ? null : String.valueOf(candidateStrategy)); + addExtensionAttribute(userTask, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, + CollUtil.join(candidateParam, ",")); + mainProcess.addFlowElement(userTask); + } + + private static void addExtensionAttribute(FlowElement element, String namespace, String name, String value) { + if (value == null) { + return; + } + ExtensionAttribute extensionAttribute = new ExtensionAttribute(name, value); + extensionAttribute.setNamespace(namespace); + element.addAttribute(extensionAttribute); + } + + private static void addBpmnStartEventNode(Process mainProcess, BpmSimpleModelNodeVO node) { + StartEvent startEvent = new StartEvent(); + startEvent.setId(node.getId()); + startEvent.setName(node.getName()); + mainProcess.addFlowElement(startEvent); + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java index e1acce0649..2e0927e7be 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java @@ -46,6 +46,15 @@ public interface BpmModelService { */ byte[] getModelBpmnXML(String id); + + /** + * 保存流程模型的 BPMN XML + * + * @param id 编号 + * @param bpmnXml BPMN XML + */ + void saveModelBpmnXml(String id, String bpmnXml); + /** * 修改流程模型 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index eb392ace2f..b85b5e0664 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -103,7 +103,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 保存流程定义 repositoryService.saveModel(model); // 保存 BPMN XML - saveModelBpmnXml(model, bpmnXml); + saveModelBpmnXml(model.getId(), bpmnXml); return model.getId(); } @@ -121,7 +121,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 更新模型 repositoryService.saveModel(model); // 更新 BPMN XML - saveModelBpmnXml(model, updateReqVO.getBpmnXml()); + saveModelBpmnXml(model.getId(), updateReqVO.getBpmnXml()); } @Override @@ -236,11 +236,12 @@ public class BpmModelServiceImpl implements BpmModelService { } } - private void saveModelBpmnXml(Model model, String bpmnXml) { + @Override + public void saveModelBpmnXml(String id, String bpmnXml) { if (StrUtil.isEmpty(bpmnXml)) { return; } - repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml)); + repositoryService.addModelEditorSource(id, StrUtil.utf8Bytes(bpmnXml)); } /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java new file mode 100644 index 0000000000..1761ba3ffc --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; +import jakarta.validation.Valid; + +/** + * 仿钉钉流程设计 Service 接口 + * + * @author jason + */ +public interface BpmSimpleModelService { + + /** + * 保存仿钉钉流程设计模型 + * @param reqVO 请求信息 + */ + Boolean saveSimpleModel(@Valid BpmSimpleModelSaveReqVO reqVO); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java new file mode 100644 index 0000000000..8273ca1760 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.service.definition; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; +import jakarta.annotation.Resource; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.engine.repository.Model; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; + +/** + * 仿钉钉流程设计 Service 实现类 + * + * @author jason + */ +@Service +@Validated +public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { + @Resource + private BpmModelService bpmModelService; + + @Override + public Boolean saveSimpleModel(BpmSimpleModelSaveReqVO reqVO) { + Model model = bpmModelService.getModel(reqVO.getModelId()); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + byte[] bpmnBytes = bpmModelService.getModelBpmnXML(reqVO.getModelId()); + + if (ArrayUtil.isEmpty(bpmnBytes)) { + // BPMN XML 不存在。新增 + BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); + bpmModelService.saveModelBpmnXml(model.getId(),BpmnModelUtils.getBpmnXml(bpmnModel)); + return Boolean.TRUE; + } else { + // TODO BPMN XML 已经存在。如何修改 ?? + return Boolean.FALSE; + } + } +} From 2ea56b51eba1854345259e9e1c347b355d0324bd Mon Sep 17 00:00:00 2001 From: dhb52 Date: Wed, 27 Mar 2024 14:30:28 +0000 Subject: [PATCH 38/86] =?UTF-8?q?=E3=80=90=E8=BD=BB=E9=87=8F=E7=BA=A7=20PR?= =?UTF-8?q?=E3=80=91=EF=BC=9Afix:=20convertXxxByFlatMap,=20=E5=BD=93map?= =?UTF-8?q?=E5=90=8E=E5=86=85=E5=AE=B9=E4=B8=BAnull=E6=97=B6,=20flatMap?= =?UTF-8?q?=E4=BC=9A=E5=87=BA=E7=8E=B0NPE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dhb52 --- .../common/util/collection/CollectionUtils.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java index cb4ddec34a..0d06bc799f 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java @@ -78,7 +78,7 @@ public class CollectionUtils { if (CollUtil.isEmpty(from)) { return new ArrayList<>(); } - return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList()); + return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList()); } public static List convertListByFlatMap(Collection from, @@ -87,7 +87,7 @@ public class CollectionUtils { if (CollUtil.isEmpty(from)) { return new ArrayList<>(); } - return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList()); + return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList()); } public static List mergeValuesFromMap(Map> map) { @@ -123,7 +123,7 @@ public class CollectionUtils { if (CollUtil.isEmpty(from)) { return new HashSet<>(); } - return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet()); + return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet()); } public static Set convertSetByFlatMap(Collection from, @@ -132,7 +132,7 @@ public class CollectionUtils { if (CollUtil.isEmpty(from)) { return new HashSet<>(); } - return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet()); + return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet()); } public static Map convertMap(Collection from, Function keyFunc) { @@ -315,4 +315,4 @@ public class CollectionUtils { return list.stream().flatMap(Collection::stream).collect(Collectors.toList()); } -} +} \ No newline at end of file From a80ba4888911f770ed09e3143dead2eba467aa8d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 28 Mar 2024 19:05:16 +0800 Subject: [PATCH 39/86] =?UTF-8?q?bugfix=EF=BC=9A=E5=90=8C=E6=AD=A5=20maste?= =?UTF-8?q?r=20=E4=BF=AE=E6=94=B9=E7=9A=84=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../receivable/CrmReceivablePlanServiceImpl.java | 6 +----- .../admin/purchase/ErpPurchaseOrderController.java | 14 +++++++------- .../app/spu/AppProductSpuController.java | 2 +- .../controller/app/cart/vo/AppCartAddReqVO.java | 5 +++-- .../order/handler/TradeBrokerageOrderHandler.java | 2 +- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java index 93ecb47462..dd3de19b1a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java @@ -20,7 +20,6 @@ import com.mzt.logapi.context.LogRecordContext; import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -46,9 +45,6 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { @Resource private CrmReceivablePlanMapper receivablePlanMapper; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private CrmReceivableService receivableService; @Resource private CrmContractService contractService; @Resource @@ -144,7 +140,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { // 2. 删除 receivablePlanMapper.deleteById(id); // 3. 删除数据权限 - permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); + permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), id); // 4. 记录操作日志上下文 LogRecordContext.putVariable("receivablePlan", receivablePlan); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java index 203d2fec0b..bbaf2edf7f 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java @@ -61,14 +61,14 @@ public class ErpPurchaseOrderController { @PostMapping("/create") @Operation(summary = "创建采购订单") - @PreAuthorize("@ss.hasPermission('erp:purchase-create:create')") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:create')") public CommonResult createPurchaseOrder(@Valid @RequestBody ErpPurchaseOrderSaveReqVO createReqVO) { return success(purchaseOrderService.createPurchaseOrder(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新采购订单") - @PreAuthorize("@ss.hasPermission('erp:purchase-create:update')") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:update')") public CommonResult updatePurchaseOrder(@Valid @RequestBody ErpPurchaseOrderSaveReqVO updateReqVO) { purchaseOrderService.updatePurchaseOrder(updateReqVO); return success(true); @@ -76,7 +76,7 @@ public class ErpPurchaseOrderController { @PutMapping("/update-status") @Operation(summary = "更新采购订单的状态") - @PreAuthorize("@ss.hasPermission('erp:purchase-create:update-status')") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:update-status')") public CommonResult updatePurchaseOrderStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) { purchaseOrderService.updatePurchaseOrderStatus(id, status); @@ -86,7 +86,7 @@ public class ErpPurchaseOrderController { @DeleteMapping("/delete") @Operation(summary = "删除采购订单") @Parameter(name = "ids", description = "编号数组", required = true) - @PreAuthorize("@ss.hasPermission('erp:purchase-create:delete')") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:delete')") public CommonResult deletePurchaseOrder(@RequestParam("ids") List ids) { purchaseOrderService.deletePurchaseOrder(ids); return success(true); @@ -95,7 +95,7 @@ public class ErpPurchaseOrderController { @GetMapping("/get") @Operation(summary = "获得采购订单") @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('erp:purchase-create:query')") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:query')") public CommonResult getPurchaseOrder(@RequestParam("id") Long id) { ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(id); if (purchaseOrder == null) { @@ -115,7 +115,7 @@ public class ErpPurchaseOrderController { @GetMapping("/page") @Operation(summary = "获得采购订单分页") - @PreAuthorize("@ss.hasPermission('erp:purchase-create:query')") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:query')") public CommonResult> getPurchaseOrderPage(@Valid ErpPurchaseOrderPageReqVO pageReqVO) { PageResult pageResult = purchaseOrderService.getPurchaseOrderPage(pageReqVO); return success(buildPurchaseOrderVOPageResult(pageResult)); @@ -123,7 +123,7 @@ public class ErpPurchaseOrderController { @GetMapping("/export-excel") @Operation(summary = "导出采购订单 Excel") - @PreAuthorize("@ss.hasPermission('erp:purchase-create:export')") + @PreAuthorize("@ss.hasPermission('erp:purchase-order:export')") @OperateLog(type = EXPORT) public void exportPurchaseOrderExcel(@Valid ErpPurchaseOrderPageReqVO pageReqVO, HttpServletResponse response) throws IOException { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java index 57fc47d45d..d8d6f29ef0 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java @@ -101,7 +101,7 @@ public class AppProductSpuController { throw exception(SPU_NOT_EXISTS); } if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { - throw exception(SPU_NOT_ENABLE); + throw exception(SPU_NOT_ENABLE, spu.getName()); } // 获得商品 SKU List skus = productSkuService.getSkuListBySpuId(spu.getId()); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java index 26d774234b..0c33b86269 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppCartAddReqVO.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.trade.controller.app.cart.vo; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - +import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import lombok.Data; @Schema(description = "用户 App - 购物车添加购物项 Request VO") @Data @@ -15,6 +15,7 @@ public class AppCartAddReqVO { @Schema(description = "新增商品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "数量不能为空") + @Min(value = 1, message = "商品数量必须大于等于 1") private Integer count; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java index d0a3afd5fb..e1ceaa505f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBrokerageOrderHandler.java @@ -83,7 +83,7 @@ public class TradeBrokerageOrderHandler implements TradeOrderHandler { if (order.getBrokerageUserId() == null) { return; } - cancelBrokerage(order.getBrokerageUserId(), orderItem.getOrderId()); + cancelBrokerage(order.getBrokerageUserId(), orderItem.getId()); } /** From b504d9841e37c23cfed48640d641d47529fb4314 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Fri, 29 Mar 2024 19:49:47 +0800 Subject: [PATCH 40/86] =?UTF-8?q?=E4=BB=BF=E9=92=89=E9=92=89=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AE=BE=E8=AE=A1-=E5=90=8E=E7=AB=AF=E5=AE=9E?= =?UTF-8?q?=E7=8E=B030%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 2 + .../definition/BpmSimpleModelController.java | 15 +- .../core/enums/BpmnModelConstants.java | 15 +- .../flowable/core/util/BpmnModelUtils.java | 57 +++---- .../definition/BpmSimpleModelService.java | 8 + .../definition/BpmSimpleModelServiceImpl.java | 142 ++++++++++++++++-- 6 files changed, 187 insertions(+), 52 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index ec167719cc..ba6b8c4543 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -75,4 +75,6 @@ public interface ErrorCodeConstants { // ========== BPM 流程表达式 1-009-014-000 ========== ErrorCode PROCESS_EXPRESSION_NOT_EXISTS = new ErrorCode(1_009_014_000, "流程表达式不存在"); + // ========== BPM 仿钉钉流程设计器 1-009-015-000 ========== + ErrorCode CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT = new ErrorCode(1_009_015_000, "该流程模型不支持仿钉钉设计流程"); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java index f6fb33e167..40745513e9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java @@ -1,17 +1,16 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; import cn.iocoder.yudao.module.bpm.service.definition.BpmSimpleModelService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -28,4 +27,12 @@ public class BpmSimpleModelController { public CommonResult saveSimpleModel(@Valid @RequestBody BpmSimpleModelSaveReqVO reqVO) { return success(bpmSimpleModelService.saveSimpleModel(reqVO)); } + + @GetMapping("/get") + @Operation(summary = "获得仿钉钉流程设计模型") + @Parameter(name = "modelId", description = "流程模型编号", required = true, example = "a2c5eee0-eb6c-11ee-abf4-0c37967c420a") + public CommonResult getSimpleModel(@RequestParam("modelId") String modelId){ + return success(bpmSimpleModelService.getSimpleModel(modelId)); + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java index 5283baa251..72d4e59ed6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java @@ -1,5 +1,10 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; +import com.google.common.collect.ImmutableSet; +import org.flowable.bpmn.model.*; + +import java.util.Set; + /** * BPMN XML 常量信息 * @@ -23,14 +28,14 @@ public interface BpmnModelConstants { */ String USER_TASK_CANDIDATE_PARAM = "candidateParam"; - /** - * BPMN Start Event 节点 Id, 用于后端生成 Start Event 节点 - */ - String START_EVENT_ID = "StartEvent_1"; - /** * BPMN End Event 节点 Id, 用于后端生成 End Event 节点 */ String END_EVENT_ID = "EndEvent_1"; + /** + * 支持转仿钉钉设计模型的 Bpmn 节点 + */ + Set> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class); + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index b66ef6a97e..501cfb6a5c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.lang.TypeReference; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; @@ -338,31 +337,26 @@ public class BpmnModelUtils { /** * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善) - * @param processId 流程标识 - * @param processName 流程名称 + * + * @param processId 流程标识 + * @param processName 流程名称 * @param simpleModelNode 仿钉钉流程设计模型数据结构 * @return Bpmn Model */ - public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName,BpmSimpleModelNodeVO simpleModelNode) { + public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { BpmnModel bpmnModel = new BpmnModel(); Process mainProcess = new Process(); mainProcess.setId(processId); mainProcess.setName(processName); mainProcess.setExecutable(Boolean.TRUE); bpmnModel.addProcess(mainProcess); - // 目前前端传进来的节点。 没有 start event 节点 和 end event 节点。 - // 在最前面加上 start event node - BpmSimpleModelNodeVO startEventNode = new BpmSimpleModelNodeVO(); - startEventNode.setId(BpmnModelConstants.START_EVENT_ID); - startEventNode.setName("开始"); - startEventNode.setType(BpmSimpleModelNodeType.START_NODE.getType()); - startEventNode.setChildNode(simpleModelNode); + // 前端模型数据结构。 有 start event 节点. 没有 end event 节点。 // 添加 FlowNode - addBpmnFlowNode(mainProcess, startEventNode); + addBpmnFlowNode(mainProcess, simpleModelNode); // 单独添加 end event 节点 addBpmnEndEventNode(mainProcess); // 添加节点之间的连线 Sequence Flow - addBpmnSequenceFlow(mainProcess, startEventNode); + addBpmnSequenceFlow(mainProcess, simpleModelNode); // 自动布局 new BpmnAutoLayout(bpmnModel).execute(); @@ -371,24 +365,24 @@ public class BpmnModelUtils { private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node) { // 节点为 null 退出 - if (node == null) { + if (node == null || node.getId() == null) { return; } BpmSimpleModelNodeVO childNode = node.getChildNode(); // 如果后续节点为 null. 添加与结束节点的连线 - if (childNode == null) { - addBpmnSequenceFlowElement(mainProcess, node.getId(),BpmnModelConstants.END_EVENT_ID, null); + if (childNode == null || childNode.getId() == null) { + addBpmnSequenceFlowElement(mainProcess, node.getId(), BpmnModelConstants.END_EVENT_ID, null); return; } BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); Assert.notNull(nodeType, "模型节点类型不支持"); - switch(nodeType){ - case START_NODE : - case START_USER_NODE : - case APPROVE_USER_NODE : + switch (nodeType) { + case START_NODE: + case START_USER_NODE: + case APPROVE_USER_NODE: addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null); break; - default : { + default: { // TODO 其它节点类型的实现 } } @@ -396,7 +390,7 @@ public class BpmnModelUtils { addBpmnSequenceFlow(mainProcess, childNode); } - private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String conditionExpression) { + private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String conditionExpression) { SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); if (StrUtil.isNotEmpty(conditionExpression)) { sequenceFlow.setConditionExpression(conditionExpression); @@ -407,20 +401,20 @@ public class BpmnModelUtils { private static void addBpmnFlowNode(Process mainProcess, BpmSimpleModelNodeVO simpleModelNode) { // 节点为 null 退出 - if (simpleModelNode == null) { + if (simpleModelNode == null || simpleModelNode.getId() == null) { return; } BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); Assert.notNull(nodeType, "模型节点类型不支持"); - switch(nodeType){ - case START_NODE : + switch (nodeType) { + case START_NODE: addBpmnStartEventNode(mainProcess, simpleModelNode); break; - case START_USER_NODE : - case APPROVE_USER_NODE : + case START_USER_NODE: + case APPROVE_USER_NODE: addBpmnUserTaskEventNode(mainProcess, simpleModelNode); break; - default : { + default: { // TODO 其它节点类型的实现 } } @@ -454,17 +448,16 @@ public class BpmnModelUtils { UserTask userTask = new UserTask(); userTask.setId(node.getId()); userTask.setName(node.getName()); - Integer candidateStrategy = MapUtil.getInt(node.getAttributes(),BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); - List candidateParam = MapUtil.get(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, new TypeReference<>() {}); + Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); // 添加自定义属性 addExtensionAttribute(userTask, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, candidateStrategy == null ? null : String.valueOf(candidateStrategy)); addExtensionAttribute(userTask, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, - CollUtil.join(candidateParam, ",")); + MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); mainProcess.addFlowElement(userTask); } - private static void addExtensionAttribute(FlowElement element, String namespace, String name, String value) { + private static void addExtensionAttribute(FlowElement element, String namespace, String name, String value) { if (value == null) { return; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java index 1761ba3ffc..2d6865d243 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.service.definition; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; import jakarta.validation.Valid; @@ -15,4 +16,11 @@ public interface BpmSimpleModelService { * @param reqVO 请求信息 */ Boolean saveSimpleModel(@Valid BpmSimpleModelSaveReqVO reqVO); + + /** + * 获取仿钉钉流程设计模型结构 + * @param modelId 流程模型编号 + * @return 仿钉钉流程设计模型结构 + */ + BpmSimpleModelNodeVO getSimpleModel(String modelId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java index 8273ca1760..eca3da1845 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java @@ -1,16 +1,28 @@ package cn.iocoder.yudao.module.bpm.service.definition; -import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import jakarta.annotation.Resource; -import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.*; import org.flowable.engine.repository.Model; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.List; +import java.util.Map; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_NODE; +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM; +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY; /** * 仿钉钉流程设计 Service 实现类 @@ -29,16 +41,124 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { if (model == null) { throw exception(MODEL_NOT_EXISTS); } - byte[] bpmnBytes = bpmModelService.getModelBpmnXML(reqVO.getModelId()); +// byte[] bpmnBytes = bpmModelService.getModelBpmnXML(reqVO.getModelId()); +// if (ArrayUtil.isEmpty(bpmnBytes)) { +// // BPMN XML 不存在。新增 +// BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); +// bpmModelService.saveModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel)); +// return Boolean.TRUE; +// } else { +// // TODO BPMN XML 已经存在。如何修改 ?? +// return Boolean.FALSE; +// } + // 暂时直接修改 + BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); + bpmModelService.saveModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel)); + return Boolean.TRUE; + } - if (ArrayUtil.isEmpty(bpmnBytes)) { - // BPMN XML 不存在。新增 - BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); - bpmModelService.saveModelBpmnXml(model.getId(),BpmnModelUtils.getBpmnXml(bpmnModel)); - return Boolean.TRUE; - } else { - // TODO BPMN XML 已经存在。如何修改 ?? - return Boolean.FALSE; + @Override + public BpmSimpleModelNodeVO getSimpleModel(String modelId) { + Model model = bpmModelService.getModel(modelId); + if (model == null) { + throw exception(MODEL_NOT_EXISTS); + } + byte[] bpmnBytes = bpmModelService.getModelBpmnXML(modelId); + BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); + return convertBpmnModelToSimpleModel(bpmnModel); + + } + + /** + * Bpmn Model 转换成 仿钉钉流程设计模型数据结构(json) 待完善 + * + * @param bpmnModel Bpmn Model + * @return 仿钉钉流程设计模型数据结构 + */ + private BpmSimpleModelNodeVO convertBpmnModelToSimpleModel(BpmnModel bpmnModel) { + if (bpmnModel == null) { + return null; + } + StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel); + if (startEvent == null) { + return null; + } + BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO(); + rootNode.setType(START_NODE.getType()); + rootNode.setId(startEvent.getId()); + rootNode.setName(startEvent.getName()); + recursiveBuildSimpleModelNode(startEvent, rootNode); + return rootNode; + + } + + private void recursiveBuildSimpleModelNode(FlowNode currentFlowNode, BpmSimpleModelNodeVO currentSimpleModeNode) { + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(currentSimpleModeNode.getType()); + Assert.notNull(nodeType, "节点类型不支持"); + // 校验节点是否支持转仿钉钉的流程模型 + List outgoingFlows = validateCanConvertSimpleNode(nodeType, currentFlowNode); + if (CollUtil.isEmpty(outgoingFlows) || outgoingFlows.get(0).getTargetFlowElement() == null) { + return; + } + FlowElement targetElement = outgoingFlows.get(0).getTargetFlowElement(); + // 如果是 EndEvent 直接退出 + if (targetElement instanceof EndEvent) { + return; + } + if (targetElement instanceof UserTask) { + BpmSimpleModelNodeVO childNode = convertUserTaskToSimpleModelNode((UserTask) targetElement); + currentSimpleModeNode.setChildNode(childNode); + recursiveBuildSimpleModelNode((FlowNode) targetElement, childNode); + } + // TODO 其它节点类型待实现 + } + + + private BpmSimpleModelNodeVO convertUserTaskToSimpleModelNode(UserTask userTask) { + BpmSimpleModelNodeVO simpleModelNodeVO = new BpmSimpleModelNodeVO(); + simpleModelNodeVO.setType(BpmSimpleModelNodeType.APPROVE_USER_NODE.getType()); + simpleModelNodeVO.setName(userTask.getName()); + simpleModelNodeVO.setId(userTask.getId()); + Map attributes = MapUtil.newHashMap(); + // TODO 暂时是普通审批,需要加会签 + attributes.put("approveMethod", 1); + attributes.computeIfAbsent(USER_TASK_CANDIDATE_STRATEGY, (key) -> BpmnModelUtils.parseCandidateStrategy(userTask)); + attributes.computeIfAbsent(USER_TASK_CANDIDATE_PARAM, (key) -> BpmnModelUtils.parseCandidateParam(userTask)); + simpleModelNodeVO.setAttributes(attributes); + return simpleModelNodeVO; + } + + private List validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) { + switch (nodeType) { + case START_NODE: + case APPROVE_USER_NODE: { + List outgoingFlows = currentFlowNode.getOutgoingFlows(); + if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) { + throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); + } + validIsSupportFlowNode(outgoingFlows.get(0).getTargetFlowElement()); + return outgoingFlows; + } + default: { + // TODO 其它节点类型待实现 + throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); + } + } + } + + private void validIsSupportFlowNode(FlowElement targetElement) { + if (targetElement == null) { + return; + } + boolean isSupport = false; + for (Class item : BpmnModelConstants.SUPPORT_CONVERT_SIMPLE_FlOW_NODES) { + if (item.isInstance(targetElement)) { + isSupport = true; + break; + } + } + if (!isSupport) { + throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); } } } From 90f82b157de162ecf07cb904ce2fe632d6bdb6ea Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 Mar 2024 09:22:54 +0800 Subject: [PATCH 41/86] =?UTF-8?q?CRM=EF=BC=9A=E4=BC=98=E5=8C=96=E3=80=90?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=BB=9F=E8=AE=A1=E3=80=91=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/DateIntervalEnum.java | 28 +- .../framework/common/util/date/DateUtils.java | 39 -- .../common/util/date/LocalDateTimeUtils.java | 144 +++++- .../module/crm/enums/ErrorCodeConstants.java | 1 - .../CrmStatisticsCustomerController.http | 2 +- .../CrmStatisticsCustomerController.java | 18 +- ...CrmStatisticsCustomerByUserBaseRespVO.java | 2 - ...atisticsCustomerContractSummaryRespVO.java | 31 +- ...atisticsCustomerDealCycleByDateRespVO.java | 2 +- ...atisticsCustomerDealCycleByUserRespVO.java | 4 +- .../customer/CrmStatisticsCustomerReqVO.java | 7 +- ...StatisticsCustomerSummaryByDateRespVO.java | 4 +- ...StatisticsCustomerSummaryByUserRespVO.java | 8 +- ...tatisticsFollowUpSummaryByDateRespVO.java} | 6 +- ...tatisticsFollowUpSummaryByTypeRespVO.java} | 6 +- ...tatisticsFollowUpSummaryByUserRespVO.java} | 6 +- .../vo/rank/CrmStatisticsRankRespVO.java | 1 + .../CrmStatisticsCustomerMapper.java | 24 +- .../CrmStatisticsCustomerService.java | 8 +- .../CrmStatisticsCustomerServiceImpl.java | 454 +++++------------- .../CrmStatisticsCustomerMapper.xml | 288 +++++------ 21 files changed, 483 insertions(+), 600 deletions(-) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/{CrmStatisticsFollowupSummaryByDateRespVO.java => CrmStatisticsFollowUpSummaryByDateRespVO.java} (79%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/{CrmStatisticsFollowupSummaryByTypeRespVO.java => CrmStatisticsFollowUpSummaryByTypeRespVO.java} (76%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/{CrmStatisticsFollowupSummaryByUserRespVO.java => CrmStatisticsFollowUpSummaryByUserRespVO.java} (75%) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java index 9a614ddc9d..498b671242 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.common.enums; +import cn.hutool.core.util.ArrayUtil; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; @@ -7,7 +8,7 @@ import lombok.Getter; import java.util.Arrays; /** - * 时间间隔类型枚举 + * 时间间隔的枚举 * * @author dhb52 */ @@ -15,26 +16,19 @@ import java.util.Arrays; @AllArgsConstructor public enum DateIntervalEnum implements IntArrayValuable { - TODAY(1, "今天"), - YESTERDAY(2, "昨天"), - THIS_WEEK(3, "本周"), - LAST_WEEK(4, "上周"), - THIS_MONTH(5, "本月"), - LAST_MONTH(6, "上月"), - THIS_QUARTER(7, "本季度"), - LAST_QUARTER(8, "上季度"), - THIS_YEAR(9, "本年"), - LAST_YEAR(10, "去年"), - CUSTOMER(11, "自定义"), + DAY(1, "天"), + WEEK(2, "周"), + MONTH(3, "月"), + QUARTER(4, "季度"), + YEAR(5, "年") ; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getInterval).toArray(); /** * 类型 */ - private final Integer type; - + private final Integer interval; /** * 名称 */ @@ -45,4 +39,8 @@ public enum DateIntervalEnum implements IntArrayValuable { return ARRAYS; } + public static DateIntervalEnum valueOf(Integer interval) { + return ArrayUtil.firstMatch(item -> item.getInterval().equals(interval), DateIntervalEnum.values()); + } + } \ No newline at end of file diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java index 60b3f1e1e9..b51a838c69 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java @@ -65,19 +65,11 @@ public class DateUtils { return new Date(System.currentTimeMillis() + duration.toMillis()); } - public static boolean isExpired(Date time) { - return System.currentTimeMillis() > time.getTime(); - } - public static boolean isExpired(LocalDateTime time) { LocalDateTime now = LocalDateTime.now(); return now.isAfter(time); } - public static long diff(Date endTime, Date startTime) { - return endTime.getTime() - startTime.getTime(); - } - /** * 创建指定时间 * @@ -134,37 +126,6 @@ public class DateUtils { return a.isAfter(b) ? a : b; } - /** - * 计算当期时间相差的日期 - * - * @param field 日历字段.
eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,
Calendar.HOUR_OF_DAY等. - * @param amount 相差的数值 - * @return 计算后的日志 - */ - public static Date addDate(int field, int amount) { - return addDate(null, field, amount); - } - - /** - * 计算当期时间相差的日期 - * - * @param date 设置时间 - * @param field 日历字段 例如说,{@link Calendar#DAY_OF_MONTH} 等 - * @param amount 相差的数值 - * @return 计算后的日志 - */ - public static Date addDate(Date date, int field, int amount) { - if (amount == 0) { - return date; - } - Calendar c = Calendar.getInstance(); - if (date != null) { - c.setTime(date); - } - c.add(field, amount); - return c.getTime(); - } - /** * 是否今天 * diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java index 87c20798ea..cf978d81a2 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java @@ -1,13 +1,18 @@ package cn.iocoder.yudao.framework.common.util.date; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; +import java.time.*; +import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAdjusters; +import java.util.ArrayList; +import java.util.List; /** * 时间工具类,用于 {@link java.time.LocalDateTime} @@ -21,6 +26,22 @@ public class LocalDateTimeUtils { */ public static LocalDateTime EMPTY = buildTime(1970, 1, 1); + /** + * 解析时间 + * + * 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功 + * + * @param time 时间 + * @return 时间字符串 + */ + public static LocalDateTime parse(String time) { + try { + return LocalDateTimeUtil.parse(time, DatePattern.NORM_DATE_PATTERN); + } catch (DateTimeParseException e) { + return LocalDateTimeUtil.parse(time); + } + } + public static LocalDateTime addTime(Duration duration) { return LocalDateTime.now().plus(duration); } @@ -54,6 +75,21 @@ public class LocalDateTimeUtils { return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)}; } + /** + * 判指定断时间,是否在该时间范围内 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param time 指定时间 + * @return 是否 + */ + public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, String time) { + if (startTime == null || endTime == null || time == null) { + return false; + } + return LocalDateTimeUtil.isIn(parse(time), startTime, endTime); + } + /** * 判断当前时间是否在该时间范围内 * @@ -122,6 +158,16 @@ public class LocalDateTimeUtils { return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); } + /** + * 获得指定日期所在季度 + * + * @param date 日期 + * @return 所在季度 + */ + public static int getQuarterOfYear(LocalDateTime date) { + return (date.getMonthValue() - 1) / 3 + 1; + } + /** * 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负 * @@ -168,4 +214,94 @@ public class LocalDateTimeUtils { return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN); } + public static List getDateRangeList(LocalDateTime startTime, + LocalDateTime endTime, + Integer interval) { + // 1.1 找到枚举 + DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval); + Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval); + // 1.2 将时间对齐 + startTime = LocalDateTimeUtil.beginOfDay(startTime); + endTime = LocalDateTimeUtil.endOfDay(endTime); + + // 2. 循环,生成时间范围 + List timeRanges = new ArrayList<>(); + switch (intervalEnum) { + case DateIntervalEnum.DAY: + while (startTime.isBefore(endTime)) { + timeRanges.add(new LocalDateTime[]{startTime, startTime.plusDays(1).minusNanos(1)}); + startTime = startTime.plusDays(1); + } + break; + case DateIntervalEnum.WEEK: + while (startTime.isBefore(endTime)) { + LocalDateTime endOfWeek = startTime.with(DayOfWeek.SUNDAY).plusDays(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, endOfWeek}); + startTime = endOfWeek.plusNanos(1); + } + break; + case DateIntervalEnum.MONTH: + while (startTime.isBefore(endTime)) { + LocalDateTime endOfMonth = startTime.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, endOfMonth}); + startTime = endOfMonth.plusNanos(1); + } + break; + case DateIntervalEnum.QUARTER: + while (startTime.isBefore(endTime)) { + LocalDateTime quarterEnd = startTime.withMonth(getQuarterOfYear(startTime) * 3 + 1) + .withDayOfMonth(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, quarterEnd}); + startTime = quarterEnd.plusNanos(1); + } + break; + case DateIntervalEnum.YEAR: + while (startTime.isBefore(endTime)) { + LocalDateTime endOfYear = startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1); + timeRanges.add(new LocalDateTime[]{startTime, endOfYear}); + startTime = endOfYear.plusNanos(1); + } + break; + default: + throw new IllegalArgumentException("Invalid interval: " + interval); + } + // 3. 兜底,最后一个时间,需要保持在 endTime 之前 + LocalDateTime[] lastTimeRange = CollUtil.getLast(timeRanges); + if (lastTimeRange != null) { + lastTimeRange[1] = endTime; + } + return timeRanges; + } + + /** + * 格式化时间范围 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param interval 时间间隔 + * @return 时间范围 + */ + public static String formatDateRange(LocalDateTime startTime, LocalDateTime endTime, Integer interval) { + // 1. 找到枚举 + DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval); + Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval); + + // 2. 循环,生成时间范围 + switch (intervalEnum) { + case DateIntervalEnum.DAY: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN); + case DateIntervalEnum.WEEK: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN) + + StrUtil.format("(第 {} 周)", LocalDateTimeUtil.weekOfYear(startTime)); + case DateIntervalEnum.MONTH: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_MONTH_PATTERN); + case DateIntervalEnum.QUARTER: + return StrUtil.format("{}-Q{}", startTime.getYear(), getQuarterOfYear(startTime)); + case DateIntervalEnum.YEAR: + return LocalDateTimeUtil.format(startTime, DatePattern.NORM_YEAR_PATTERN); + default: + throw new IllegalArgumentException("Invalid interval: " + interval); + } + } + } diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index d49f6068cf..27fb6f9cea 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -104,6 +104,5 @@ public interface ErrorCodeConstants { ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); // ========== 数据统计 1_020_014_000 ========== - ErrorCode STATISTICS_CUSTOMER_TIMES_NOT_SET = new ErrorCode(1_020_014_000, "自定义时间间隔,必须输入时间区间"); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http index 9d96e159aa..b5d35f5c4a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http @@ -1,6 +1,6 @@ # == 1. 客户总量分析 == ### 1.1 客户总量分析(按日) -GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&intervalType=11×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&interval=1×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index 4a0b2e760e..7d45ae217f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -40,25 +40,25 @@ public class CrmStatisticsCustomerController { return success(customerService.getCustomerSummaryByUser(reqVO)); } - @GetMapping("/get-followup-summary-by-date") + @GetMapping("/get-follow-up-summary-by-date") @Operation(summary = "获取客户跟进次数分析(按日期)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getFollowupSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getFollowupSummaryByDate(reqVO)); + public CommonResult> getFollowupSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowUpSummaryByDate(reqVO)); } - @GetMapping("/get-followup-summary-by-user") + @GetMapping("/get-follow-up-summary-by-user") @Operation(summary = "获取客户跟进次数分析(按用户)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getFollowupSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getFollowupSummaryByUser(reqVO)); + public CommonResult> getFollowUpSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowUpSummaryByUser(reqVO)); } - @GetMapping("/get-followup-summary-by-type") + @GetMapping("/get-follow-up-summary-by-type") @Operation(summary = "获取客户跟进次数分析(按类型)") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getFollowupSummaryByType(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getFollowupSummaryByType(reqVO)); + public CommonResult> getFollowUpSummaryByType(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(customerService.getFollowUpSummaryByType(reqVO)); } @GetMapping("/get-contract-summary") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java index 41fa9152e9..bde0029c68 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; -import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -13,7 +12,6 @@ import lombok.Data; public class CrmStatisticsCustomerByUserBaseRespVO { @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @JsonIgnore private Long ownerUserId; @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java index ec1d273034..fa03d46098 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java @@ -1,18 +1,12 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; -import java.time.LocalDate; import java.time.LocalDateTime; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; - @Schema(description = "管理后台 - CRM 客户转化率分析 VO") @Data public class CrmStatisticsCustomerContractSummaryRespVO { @@ -29,31 +23,19 @@ public class CrmStatisticsCustomerContractSummaryRespVO { @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00") private BigDecimal receivablePrice; - @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @JsonIgnore - private String industryId; + @Schema(description = "客户行业编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer industryId; - @Schema(description = "客户行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "金融") - private String industryName; - - @Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @JsonIgnore - private String source; - - @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "外呼") - private String sourceName; + @Schema(description = "客户来源编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer source; @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @JsonIgnore private Long ownerUserId; - @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") private String ownerUserName; @Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @JsonIgnore - private String creatorUserId; - + private String creator; @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "源码") private String creatorUserName; @@ -61,7 +43,6 @@ public class CrmStatisticsCustomerContractSummaryRespVO { private LocalDateTime createTime; @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02 00:00:00") - @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT) - private LocalDate orderDate; + private LocalDateTime orderDate; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java index 44b2526e85..62facb053e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java @@ -11,6 +11,6 @@ public class CrmStatisticsCustomerDealCycleByDateRespVO { private String time; @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") - private Double customerDealCycle = 0.0; + private Double customerDealCycle; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java index 6c8137983d..1c394b8b49 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java @@ -8,9 +8,9 @@ import lombok.Data; public class CrmStatisticsCustomerDealCycleByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") - private Double customerDealCycle = 0.0; + private Double customerDealCycle; @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer customerDealCount = 0; + private Integer customerDealCount; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java index 38f15cf034..0564c2679e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java @@ -30,12 +30,12 @@ public class CrmStatisticsCustomerReqVO { * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 * 后续,可能会支持选择部分用户进行查询 */ - @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") private List userIds; @Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}") - private Integer intervalType; + private Integer interval; /** * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间 @@ -49,7 +49,8 @@ public class CrmStatisticsCustomerReqVO { * group by DATE_FORMAT(field, #{dateFormat}) * 非前端传递, 由Service计算后传递给Mapper的参数 */ - @Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m") + @Deprecated + @Schema(description = "Group By 日期格式", hidden = true, example = "%Y%m") private String sqlDateFormat; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java index 866a58f1e6..7ffcb20ff5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java @@ -11,9 +11,9 @@ public class CrmStatisticsCustomerSummaryByDateRespVO { private String time; @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer customerCreateCount = 0; + private Integer customerCreateCount; @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer customerDealCount = 0; + private Integer customerDealCount; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java index bd719a1b8a..fa8372b8bb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java @@ -10,15 +10,15 @@ import java.math.BigDecimal; public class CrmStatisticsCustomerSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer customerCreateCount = 0; + private Integer customerCreateCount; @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer customerDealCount = 0; + private Integer customerDealCount; @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") - private BigDecimal contractPrice = BigDecimal.ZERO; + private BigDecimal contractPrice; @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") - private BigDecimal receivablePrice = BigDecimal.ZERO; + private BigDecimal receivablePrice; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByDateRespVO.java similarity index 79% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByDateRespVO.java index 6bd6f1d4db..9040c1eab7 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByDateRespVO.java @@ -5,15 +5,15 @@ import lombok.Data; @Schema(description = "管理后台 - CRM 跟进次数分析(按日期) VO") @Data -public class CrmStatisticsFollowupSummaryByDateRespVO { +public class CrmStatisticsFollowUpSummaryByDateRespVO { @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") private String time; @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer followupRecordCount = 0; + private Integer followUpRecordCount; @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer followupCustomerCount = 0; + private Integer followUpCustomerCount; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByTypeRespVO.java similarity index 76% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByTypeRespVO.java index c722305a5f..d39f1cc0d5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByTypeRespVO.java @@ -6,12 +6,12 @@ import lombok.Data; @Schema(description = "管理后台 - CRM 跟进次数分析(按类型) VO") @Data -public class CrmStatisticsFollowupSummaryByTypeRespVO { +public class CrmStatisticsFollowUpSummaryByTypeRespVO { @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private String followupType; + private Integer followUpType; @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer followupRecordCount = 0; + private Integer followUpRecordCount; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByUserRespVO.java similarity index 75% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByUserRespVO.java index 5cd610c360..0651356266 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowUpSummaryByUserRespVO.java @@ -5,12 +5,12 @@ import lombok.Data; @Schema(description = "管理后台 - CRM 跟进次数分析(按用户) VO") @Data -public class CrmStatisticsFollowupSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { +public class CrmStatisticsFollowUpSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO { @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer followupRecordCount = 0; + private Integer followUpRecordCount; @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer followupCustomerCount = 0; + private Integer followUpCustomerCount; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java index 101cd8bccf..261aa893e8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java @@ -17,6 +17,7 @@ public class CrmStatisticsRankRespVO { @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private String deptName; + // TODO @芋艿:需要改下,金额是 bigdecimal /** * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义 *

diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 7c8ed7e93c..6b535d4c86 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -13,32 +13,32 @@ import java.util.List; @Mapper public interface CrmStatisticsCustomerMapper { - List selectCustomerCreateCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review + List selectCustomerCreateCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); - List selectCustomerDealCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review + List selectCustomerDealCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); - List selectCustomerCreateCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); // 已经 review + List selectCustomerCreateCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); - List selectCustomerDealCountGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review + List selectCustomerDealCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); - List selectContractPriceGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review + List selectContractPriceGroupByUser(CrmStatisticsCustomerReqVO reqVO); - List selectReceivablePriceGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review + List selectReceivablePriceGroupByUser(CrmStatisticsCustomerReqVO reqVO); - List selectFollowupRecordCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); + List selectFollowUpRecordCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); - List selectFollowupCustomerCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); + List selectFollowUpCustomerCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); - List selectFollowupRecordCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); + List selectFollowUpRecordCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); - List selectFollowupCustomerCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); + List selectFollowUpCustomerCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); List selectContractSummary(CrmStatisticsCustomerReqVO reqVO); - List selectFollowupRecordCountGroupByType(CrmStatisticsCustomerReqVO reqVO); + List selectFollowUpRecordCountGroupByType(CrmStatisticsCustomerReqVO reqVO); List selectCustomerDealCycleGroupByDate(CrmStatisticsCustomerReqVO reqVO); - List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); // TODO } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index 546124701a..06873e4a18 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -27,14 +27,13 @@ public interface CrmStatisticsCustomerService { */ List getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO); - /** * 跟进次数分析(按日期) * * @param reqVO 请求参数 * @return 统计数据 */ - List getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO); + List getFollowUpSummaryByDate(CrmStatisticsCustomerReqVO reqVO); /** * 跟进次数分析(按用户) @@ -42,7 +41,7 @@ public interface CrmStatisticsCustomerService { * @param reqVO 请求参数 * @return 统计数据 */ - List getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO); + List getFollowUpSummaryByUser(CrmStatisticsCustomerReqVO reqVO); /** * 客户跟进次数分析(按类型) @@ -50,8 +49,7 @@ public interface CrmStatisticsCustomerService { * @param reqVO 请求参数 * @return 统计数据 */ - List getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO); - + List getFollowUpSummaryByType(CrmStatisticsCustomerReqVO reqVO); /** * 获取合同摘要信息(客户转化率页面) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index f951e25f54..250560ef29 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -1,19 +1,13 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; @@ -27,10 +21,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Stream; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.STATISTICS_CUSTOMER_TIMES_NOT_SET; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; /** * CRM 客户分析 Service 实现类 @@ -41,13 +33,6 @@ import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.STATISTICS_CU @Validated public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerService { - private static final String SQL_DATE_FORMAT_BY_MONTH = "%Y%m"; - private static final String SQL_DATE_FORMAT_BY_DAY = "%Y%m%d"; - - private static final String TIME_FORMAT_BY_MONTH = "yyyyMM"; - private static final String TIME_FORMAT_BY_DAY = "yyyyMMdd"; - - @Resource private CrmStatisticsCustomerMapper customerMapper; @@ -55,283 +40,211 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; - @Resource - private DictDataApi dictDataApi; @Override public List getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获取分项统计数据 - initParams(reqVO); - List customerCreateCountVoList = customerMapper.selectCustomerCreateCountGroupByDate(reqVO); - List customerDealCountVoList = customerMapper.selectCustomerDealCountGroupByDate(reqVO); + // 2. 按天统计,获取分项统计数据 + List customerCreateCountList = customerMapper.selectCustomerCreateCountGroupByDate(reqVO); + List customerDealCountList = customerMapper.selectCustomerDealCountGroupByDate(reqVO); - // 3. 合并数据 - List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); - Map customerCreateCountMap = convertMap(customerCreateCountVoList, - CrmStatisticsCustomerSummaryByDateRespVO::getTime, - CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); - Map customerDealCountMap = convertMap(customerDealCountVoList, - CrmStatisticsCustomerSummaryByDateRespVO::getTime, - CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); - List respVoList = convertList(times, - time -> new CrmStatisticsCustomerSummaryByDateRespVO() - .setTime(time) - .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0)) - .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))); - - return respVoList; + // 3. 按照日期间隔,合并数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Integer customerCreateCount = customerCreateCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount).sum(); + Integer customerDealCount = customerDealCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount).sum(); + return new CrmStatisticsCustomerSummaryByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setCustomerCreateCount(customerCreateCount).setCustomerDealCount(customerDealCount); + }); } @Override public List getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获取分项统计数据 - initParams(reqVO); - List customerCreateCount = customerMapper.selectCustomerCreateCountGroupByUser(reqVO); - List customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO); - List contractPrice = customerMapper.selectContractPriceGroupByUser(reqVO); - List receivablePrice = customerMapper.selectReceivablePriceGroupByUser(reqVO); + // 2. 按用户统计,获取分项统计数据 + List customerCreateCountList = customerMapper.selectCustomerCreateCountGroupByUser(reqVO); + List customerDealCountList = customerMapper.selectCustomerDealCountGroupByUser(reqVO); + List contractPriceList = customerMapper.selectContractPriceGroupByUser(reqVO); + List receivablePriceList = customerMapper.selectReceivablePriceGroupByUser(reqVO); - // 3. 合并统计数据 - Map customerCreateCountMap = convertMap(customerCreateCount, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); - Map customerDealCountMap = convertMap(customerDealCount, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); - Map contractPriceMap = convertMap(contractPrice, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); - Map receivablePriceMap = convertMap(receivablePrice, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); - List respVoList = convertList(userIds, userId -> { - CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO(); - // ownerUserId 为基类属性 - vo.setOwnerUserId(userId); - vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0)) - .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)) - .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO)) - .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO)); - return vo; + // 3.1 按照用户,合并统计数据 + List summaryList = convertList(reqVO.getUserIds(), userId -> { + Integer customerCreateCount = customerCreateCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount).sum(); + Integer customerDealCount = customerDealCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount).sum(); + BigDecimal contractPrice = contractPriceList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .reduce(BigDecimal.ZERO, (sum, vo) -> sum.add(vo.getContractPrice()), BigDecimal::add); + BigDecimal receivablePrice = receivablePriceList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .reduce(BigDecimal.ZERO, (sum, vo) -> sum.add(vo.getReceivablePrice()), BigDecimal::add); + return (CrmStatisticsCustomerSummaryByUserRespVO) new CrmStatisticsCustomerSummaryByUserRespVO() + .setCustomerCreateCount(customerCreateCount).setCustomerDealCount(customerDealCount) + .setContractPrice(contractPrice).setReceivablePrice(receivablePrice).setOwnerUserId(userId); }); - - // 4. 拼接用户信息 - appendUserInfo(respVoList); - - return respVoList; + // 3.2 拼接用户信息 + appendUserInfo(summaryList); + return summaryList; } @Override - public List getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { + public List getFollowUpSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获取分项统计数据 - initParams(reqVO); - List followupRecordCount = customerMapper.selectFollowupRecordCountGroupByDate(reqVO); - List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByDate(reqVO); + // 2. 按天统计,获取分项统计数据 + List followUpRecordCountList = customerMapper.selectFollowUpRecordCountGroupByDate(reqVO); + List followUpCustomerCountList = customerMapper.selectFollowUpCustomerCountGroupByDate(reqVO); - // 3. 合并统计数据 - List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); - Map followupRecordCountMap = convertMap(followupRecordCount, - CrmStatisticsFollowupSummaryByDateRespVO::getTime, - CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); - Map followupCustomerCountMap = convertMap(followupCustomerCount, - CrmStatisticsFollowupSummaryByDateRespVO::getTime, - CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); - List respVoList = convertList(times, time -> - new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time) - .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0)) - .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0)) - ); - - return respVoList; + // 3. 按照时间间隔,合并统计数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Integer followUpRecordCount = followUpRecordCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsFollowUpSummaryByDateRespVO::getFollowUpRecordCount).sum(); + Integer followUpCustomerCount = followUpCustomerCountList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToInt(CrmStatisticsFollowUpSummaryByDateRespVO::getFollowUpCustomerCount).sum(); + return new CrmStatisticsFollowUpSummaryByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setFollowUpCustomerCount(followUpRecordCount).setFollowUpRecordCount(followUpCustomerCount); + }); } @Override - public List getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { + public List getFollowUpSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获取分项统计数据 - initParams(reqVO); - List followupRecordCount = customerMapper.selectFollowupRecordCountGroupByUser(reqVO); - List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByUser(reqVO); + // 2. 按用户统计,获取分项统计数据 + List followUpRecordCountList = customerMapper.selectFollowUpRecordCountGroupByUser(reqVO); + List followUpCustomerCountList = customerMapper.selectFollowUpCustomerCountGroupByUser(reqVO); - // 3. 合并统计数据 - Map followupRecordCountMap = convertMap(followupRecordCount, - CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); - Map followupCustomerCountMap = convertMap(followupCustomerCount, - CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); - List respVoList = convertList(userIds, userId -> { - CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO() - .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0)) - .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0)); - // ownerUserId 为基类属性 - vo.setOwnerUserId(userId); - return vo; + // 3.1 按照用户,合并统计数据 + List summaryList = convertList(reqVO.getUserIds(), userId -> { + Integer followUpRecordCount = followUpRecordCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsFollowUpSummaryByUserRespVO::getFollowUpRecordCount).sum(); + Integer followUpCustomerCount = followUpCustomerCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsFollowUpSummaryByUserRespVO::getFollowUpCustomerCount).sum(); + return (CrmStatisticsFollowUpSummaryByUserRespVO) new CrmStatisticsFollowUpSummaryByUserRespVO() + .setFollowUpCustomerCount(followUpRecordCount).setFollowUpRecordCount(followUpCustomerCount).setOwnerUserId(userId); }); - - // 4. 拼接用户信息 - appendUserInfo(respVoList); - return respVoList; + // 3.2 拼接用户信息 + appendUserInfo(summaryList); + return summaryList; } @Override - public List getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO) { + public List getFollowUpSummaryByType(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获得排行数据 - initParams(reqVO); - List respVoList = customerMapper.selectFollowupRecordCountGroupByType(reqVO); - - // 3. 获取字典数据 - List followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE); - Map followUpTypeMap = convertMap(followUpTypes, - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); - respVoList.forEach(vo -> { - vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType())); - }); - - return respVoList; + // 2. 获得跟进数据 + return customerMapper.selectFollowUpRecordCountGroupByType(reqVO); } @Override public List getContractSummary(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获取统计数据 - initParams(reqVO); - List respVoList = customerMapper.selectContractSummary(reqVO); + // 2. 按用户统计,获取统计数据 + List summaryList = customerMapper.selectContractSummary(reqVO); - // 3. 设置 创建人、负责人、行业、来源 - // 3.1 获取客户所属行业 - Map industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY), - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); - // 3.2 获取客户来源 - Map sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE), - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); - // 3.3 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList, - vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); - // 3.4 设置 创建人、负责人、行业、来源 - respVoList.forEach(vo -> { - MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName); - MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName); - MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()), - user -> vo.setCreatorUserName(user.getNickname())); - MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); + // 3. 拼接信息 + Map userMap = adminUserApi.getUserMap( + convertSetByFlatMap(summaryList, vo -> Stream.of(NumberUtils.parseLong(vo.getCreator()), vo.getOwnerUserId()))); + summaryList.forEach(vo -> { + findAndThen(userMap, NumberUtils.parseLong(vo.getCreator()), user -> vo.setCreatorUserName(user.getNickname())); + findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); }); - - return respVoList; + return summaryList; } @Override public List getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获取分项统计数据 - initParams(reqVO); - List customerDealCycle = customerMapper.selectCustomerDealCycleGroupByDate(reqVO); + // 2. 按天统计,获取分项统计数据 + List customerDealCycleList = customerMapper.selectCustomerDealCycleGroupByDate(reqVO); - // 3. 合并统计数据 - List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); - Map customerDealCycleMap = convertMap(customerDealCycle, - CrmStatisticsCustomerDealCycleByDateRespVO::getTime, - CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); - List respVoList = convertList(times, time -> - new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time) - .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D)) - ); - - return respVoList; + // 3. 按照日期间隔,合并统计数据 + List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); + return convertList(timeRanges, times -> { + Double customerDealCycle = customerDealCycleList.stream() + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) + .mapToDouble(CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle).sum(); + return new CrmStatisticsCustomerDealCycleByDateRespVO() + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) + .setCustomerDealCycle(customerDealCycle); + }); } @Override public List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { return Collections.emptyList(); } - reqVO.setUserIds(userIds); - // 2. 获取分项统计数据 - initParams(reqVO); - List customerDealCycle = customerMapper.selectCustomerDealCycleGroupByUser(reqVO); - List customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO); + // 2. 按用户统计,获取分项统计数据 + List customerDealCycleList = customerMapper.selectCustomerDealCycleGroupByUser(reqVO); + List customerDealCountList = customerMapper.selectCustomerDealCountGroupByUser(reqVO); - // 3. 合并统计数据 - Map customerDealCycleMap = convertMap(customerDealCycle, - CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); - Map customerDealCountMap = convertMap(customerDealCount, - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); - List respVoList = convertList(userIds, userId -> { - CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO() - .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0)) - .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)); - // ownerUserId 为基类属性 - vo.setOwnerUserId(userId); - return vo; + // 3.1 按照用户,合并统计数据 + List summaryList = convertList(reqVO.getUserIds(), userId -> { + Double customerDealCycle = customerDealCycleList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToDouble(CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle).sum(); + Integer customerDealCount = customerDealCountList.stream().filter(vo -> userId.equals(vo.getOwnerUserId())) + .mapToInt(CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount).sum(); + return (CrmStatisticsCustomerDealCycleByUserRespVO) new CrmStatisticsCustomerDealCycleByUserRespVO() + .setCustomerDealCycle(customerDealCycle).setCustomerDealCount(customerDealCount).setOwnerUserId(userId); }); - - // 4. 拼接用户信息 - appendUserInfo(respVoList); - - return respVoList; + // 3.2 拼接用户信息 + appendUserInfo(summaryList); + return summaryList; } /** * 拼接用户信息(昵称) * - * @param respVoList 统计数据 + * @param voList 统计数据 */ - private void appendUserInfo(List respVoList) { - Map userMap = adminUserApi.getUserMap(convertSet(respVoList, - CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); - respVoList.forEach(vo -> MapUtils.findAndThen(userMap, - vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); + private void appendUserInfo(List voList) { + Map userMap = adminUserApi.getUserMap( + convertSet(voList, CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); + voList.forEach(vo -> findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); } /** @@ -347,113 +260,10 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe } // 情况二:选中某个部门 // 2.1 获得部门列表 - Long deptId = reqVO.getDeptId(); - List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); - deptIds.add(deptId); + List deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId); + deptIds.add(reqVO.getDeptId()); // 2.2 获得用户编号 return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); } - - /** - * 判断是否按照 月粒度 统计 - * - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 是, 按月粒度, 否则按天粒度统计。 - */ - private boolean queryByMonth(LocalDateTime startTime, LocalDateTime endTime) { - return LocalDateTimeUtil.between(startTime, endTime).toDays() > 31; - } - - /** - * 生成时间序列 - * - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 时间序列 - */ - private List generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) { - boolean byMonth = queryByMonth(startTime, endTime); - List times = CollUtil.newArrayList(); - while (!startTime.isAfter(endTime)) { - times.add(LocalDateTimeUtil.format(startTime, byMonth ? TIME_FORMAT_BY_MONTH : TIME_FORMAT_BY_DAY)); - if (byMonth) - startTime = startTime.plusMonths(1); - else - startTime = startTime.plusDays(1); - } - - return times; - } - - /** - * 获取 SQL 查询 GROUP BY 的时间格式 - * - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return SQL 查询 GROUP BY 的时间格式 - */ - private String getSqlDateFormat(LocalDateTime startTime, LocalDateTime endTime) { - return queryByMonth(startTime, endTime) ? SQL_DATE_FORMAT_BY_MONTH : SQL_DATE_FORMAT_BY_DAY; - } - - private void initParams(CrmStatisticsCustomerReqVO reqVO) { - final Integer intervalType = reqVO.getIntervalType(); - - // 1. 自定义时间间隔,必须输入起始日期-结束日期 - if (DateIntervalEnum.CUSTOMER.getType().equals(intervalType)) { - if (ObjUtil.isEmpty(reqVO.getTimes()) || reqVO.getTimes().length != 2) { - throw exception(STATISTICS_CUSTOMER_TIMES_NOT_SET); - } - // 设置 mapper sqlDateFormat 参数 - reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1])); - // 自定义日期无需计算日期参数 - return; - } - - // 2. 根据时间区间类型计算时间段区间日期 - DateTime beginDate = null; - DateTime endDate = null; - if (DateIntervalEnum.TODAY.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfDay(DateUtil.date()); - endDate = DateUtil.endOfDay(DateUtil.date()); - } else if (DateIntervalEnum.YESTERDAY.getType().equals(intervalType)) { - beginDate = DateUtil.offsetDay(DateUtil.date(), -1); - endDate = DateUtil.offsetDay(DateUtil.date(), -1); - } else if (DateIntervalEnum.THIS_WEEK.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfWeek(DateUtil.date()); - endDate = DateUtil.endOfWeek(DateUtil.date()); - } else if (DateIntervalEnum.LAST_WEEK.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1)); - endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1)); - } else if (DateIntervalEnum.THIS_MONTH.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfMonth(DateUtil.date()); - endDate = DateUtil.endOfMonth(DateUtil.date()); - } else if (DateIntervalEnum.LAST_MONTH.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1)); - endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1)); - } else if (DateIntervalEnum.THIS_QUARTER.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfQuarter(DateUtil.date()); - endDate = DateUtil.endOfQuarter(DateUtil.date()); - } else if (DateIntervalEnum.LAST_QUARTER.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3)); - endDate = DateUtil.endOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3)); - } else if (DateIntervalEnum.THIS_YEAR.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfYear(DateUtil.date()); - endDate = DateUtil.endOfYear(DateUtil.date()); - } else if (DateIntervalEnum.LAST_YEAR.getType().equals(intervalType)) { - beginDate = DateUtil.beginOfYear(DateUtil.offsetMonth(DateUtil.date(), -12)); - endDate = DateUtil.endOfYear(DateUtil.offsetMonth(DateUtil.date(), -12)); - } - - // 3. 计算开始、结束日期时间,并设置reqVo - LocalDateTime[] times = new LocalDateTime[2]; - times[0] = LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.of(beginDate)); - times[1] = LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.of(endDate)); - // 3.1 设置 mapper 时间区间 参数 - reqVO.setTimes(times); - // 3.2 设置 mapper sqlDateFormat 参数 - reqVO.setSqlDateFormat(getSqlDateFormat(times[0], times[1])); - } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index 32a1d425e5..4e1cee0ea3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -5,31 +5,31 @@ @@ -38,13 +38,13 @@ SELECT owner_user_id, COUNT(1) AS customer_create_count - FROM crm_customer - WHERE deleted = 0 - AND owner_user_id in - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + FROM crm_customer + WHERE deleted = 0 + AND owner_user_id in + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -53,16 +53,16 @@ SELECT customer.owner_user_id, COUNT( DISTINCT customer.id ) AS customer_deal_count - FROM crm_customer AS customer - LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id - WHERE customer.deleted = 0 AND contract.deleted = 0 - AND contract.audit_status = 20 - AND customer.owner_user_id IN - - #{userId} - - AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - GROUP BY customer.owner_user_id + FROM crm_customer AS customer + LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id + WHERE customer.deleted = 0 AND contract.deleted = 0 + AND contract.audit_status = 20 + AND customer.owner_user_id IN + + #{userId} + + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + GROUP BY customer.owner_user_id - SELECT - DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time, - COUNT(*) AS followup_record_count - FROM crm_follow_up_record - WHERE creator IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} - GROUP BY time + DATE_FORMAT( create_time, '%Y-%m-%d' ) AS time, + COUNT(*) AS follow_up_record_count + FROM crm_follow_up_record + WHERE creator IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} + GROUP BY time - SELECT - DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time, - COUNT(DISTINCT biz_id) AS followup_customer_count - FROM crm_follow_up_record - WHERE creator IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} - GROUP BY time + DATE_FORMAT( create_time, '%Y-%m-%d' ) AS time, + COUNT(DISTINCT biz_id) AS follow_up_customer_count + FROM crm_follow_up_record + WHERE creator IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} + GROUP BY time - SELECT creator as owner_user_id, - COUNT(*) AS followup_record_count - FROM crm_follow_up_record - WHERE creator IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} - GROUP BY creator + COUNT(*) AS follow_up_record_count + FROM crm_follow_up_record + WHERE creator IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} + GROUP BY creator - SELECT creator as owner_user_id, - COUNT(DISTINCT biz_id) AS followup_customer_count - FROM crm_follow_up_record - WHERE creator IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} - GROUP BY creator + COUNT(DISTINCT biz_id) AS follow_up_customer_count + FROM crm_follow_up_record + WHERE creator IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} + GROUP BY creator - SELECT - type AS followupType, - COUNT(*) AS followup_record_count - FROM crm_follow_up_record - WHERE creator IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} - GROUP BY followupType + type AS follow_up_type, + COUNT(*) AS follow_up_record_count + FROM crm_follow_up_record + WHERE creator IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type} + GROUP BY follow_up_type From a8bec19196cd63b135734011b1de13d8b728b6a8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 Mar 2024 11:00:15 +0800 Subject: [PATCH 42/86] =?UTF-8?q?CRM=EF=BC=9Acode=20review=E3=80=90?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=BB=9F=E8=AE=A1=E3=80=91=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.java | 6 ++- .../CrmStatisticsCustomerMapper.java | 2 +- .../CrmStatisticsCustomerService.java | 6 ++- .../CrmStatisticsCustomerMapper.xml | 30 +++++------ .../statistics/CrmStatisticsRankMapper.xml | 54 +++++++++---------- 5 files changed, 51 insertions(+), 47 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index 7d45ae217f..450a9cd99e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -61,8 +61,10 @@ public class CrmStatisticsCustomerController { return success(customerService.getFollowUpSummaryByType(reqVO)); } + // TODO @dhb52:【客户转化率】里,应该少了一个接口,给上面图标的; + @GetMapping("/get-contract-summary") - @Operation(summary = "获取合同摘要信息(客户转化率页面)") + @Operation(summary = "获取客户的首次合同、回款信息列表", description = "用于【客户转化率】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") public CommonResult> getContractSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { return success(customerService.getContractSummary(reqVO)); @@ -82,4 +84,6 @@ public class CrmStatisticsCustomerController { return success(customerService.getCustomerDealCycleByUser(reqVO)); } + // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析; + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 6b535d4c86..213a07d29a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -39,6 +39,6 @@ public interface CrmStatisticsCustomerMapper { List selectCustomerDealCycleGroupByDate(CrmStatisticsCustomerReqVO reqVO); - List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); // TODO + List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index 06873e4a18..55317f4aec 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -52,16 +52,18 @@ public interface CrmStatisticsCustomerService { List getFollowUpSummaryByType(CrmStatisticsCustomerReqVO reqVO); /** - * 获取合同摘要信息(客户转化率页面) + * 获取客户的首次合同、回款信息列表,用于【客户转化率】页面 * * @param reqVO 请求参数 - * @return 合同摘要列表 + * @return 客户的首次合同、回款信息列表 */ List getContractSummary(CrmStatisticsCustomerReqVO reqVO); /** * 客户成交周期(按日期) * + * 成交的定义:客户 customer 在创建出来,到合同 contract 第一次成交的时间差 + * * @param reqVO 请求参数 * @return 统计数据 */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index 4e1cee0ea3..0672d629e1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -24,7 +24,7 @@ COUNT( DISTINCT customer_id ) AS customerDealCount FROM crm_contract WHERE deleted = 0 - AND audit_status = 20 + AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND owner_user_id IN #{userId} @@ -56,7 +56,7 @@ FROM crm_customer AS customer LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id WHERE customer.deleted = 0 AND contract.deleted = 0 - AND contract.audit_status = 20 + AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND customer.owner_user_id IN #{userId} @@ -72,7 +72,7 @@ IFNULL(SUM(total_price), 0) AS contract_price FROM crm_contract WHERE deleted = 0 - AND audit_status = 20 + AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND owner_user_id in #{userId} @@ -88,7 +88,7 @@ IFNULL(SUM(price), 0) AS receivable_price FROM crm_receivable WHERE deleted = 0 - AND audit_status = 20 + AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND owner_user_id IN #{userId} @@ -175,28 +175,24 @@ + @@ -222,11 +219,12 @@ FROM crm_customer AS customer LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id WHERE customer.deleted = 0 AND contract.deleted = 0 - AND contract.audit_status = 20 + AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND customer.owner_user_id IN #{userId} + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} GROUP BY customer.owner_user_id diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml index c82c554120..ae84e1d474 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml @@ -7,11 +7,11 @@ SELECT IFNULL(SUM(total_price), 0) AS count, owner_user_id FROM crm_contract WHERE deleted = 0 - AND audit_status = 20 + AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} and owner_user_id in - - #{userId} - + + #{userId} + AND order_date between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -22,11 +22,11 @@ SELECT IFNULL(SUM(price), 0) AS count, owner_user_id FROM crm_receivable WHERE deleted = 0 - AND audit_status = 20 + AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND owner_user_id in - - #{userId} - + + #{userId} + AND return_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -37,11 +37,11 @@ SELECT COUNT(1) AS count, owner_user_id FROM crm_contract WHERE deleted = 0 - AND audit_status = 20 + AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND owner_user_id in - - #{userId} - + + #{userId} + AND order_date between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -55,9 +55,9 @@ WHERE deleted = 0 AND audit_status = 20 AND owner_user_id in - - #{userId} - + + #{userId} + AND order_date between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -69,9 +69,9 @@ FROM crm_customer WHERE deleted = 0 AND owner_user_id in - - #{userId} - + + #{userId} + AND create_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -83,9 +83,9 @@ FROM crm_contact WHERE deleted = 0 AND owner_user_id in - - #{userId} - + + #{userId} + AND create_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -99,9 +99,9 @@ WHERE cfur.deleted = 0 AND cc.deleted = 0 AND cc.owner_user_id in - - #{userId} - + + #{userId} + AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY cc.owner_user_id @@ -115,9 +115,9 @@ WHERE cfur.deleted = 0 AND cc.deleted = 0 AND cc.owner_user_id in - - #{userId} - + + #{userId} + AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY cc.owner_user_id From 8266fb8f94f4679e37fdaf3444486aa6d14ca922 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 Mar 2024 11:49:06 +0800 Subject: [PATCH 43/86] =?UTF-8?q?CRM=EF=BC=9A=E5=AE=8C=E5=96=84=E3=80=90?= =?UTF-8?q?=E6=8E=92=E8=A1=8C=E7=89=88=E3=80=91=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vo/rank/CrmStatisticsRankRespVO.java | 9 +++-- .../statistics/CrmStatisticsRankMapper.xml | 38 ++++++++----------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java index 261aa893e8..feb2f3f2e1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/rank/CrmStatisticsRankRespVO.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.rank; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.math.BigDecimal; + @Schema(description = "管理后台 - CRM 排行榜统计 Response VO") @Data @@ -17,14 +19,15 @@ public class CrmStatisticsRankRespVO { @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private String deptName; - // TODO @芋艿:需要改下,金额是 bigdecimal /** * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义 - *

+ * * 1. 金额:合同金额排行、回款金额排行 * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 + * + * 为什么使用 BigDecimal 的原因: */ @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer count; + private BigDecimal count; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml index ae84e1d474..abd63f27d2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsRankMapper.xml @@ -12,8 +12,7 @@ #{userId} - AND order_date between #{times[0],javaType=java.time.LocalDateTime} and - #{times[1],javaType=java.time.LocalDateTime} + AND order_date between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -27,8 +26,7 @@ #{userId} - AND return_time between #{times[0],javaType=java.time.LocalDateTime} and - #{times[1],javaType=java.time.LocalDateTime} + AND return_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -42,25 +40,23 @@ #{userId} - AND order_date between #{times[0],javaType=java.time.LocalDateTime} and - #{times[1],javaType=java.time.LocalDateTime} + AND order_date between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id - @@ -86,8 +81,7 @@ #{userId} - AND create_time between #{times[0],javaType=java.time.LocalDateTime} and - #{times[1],javaType=java.time.LocalDateTime} + AND create_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY owner_user_id @@ -102,8 +96,7 @@ #{userId} - AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and - #{times[1],javaType=java.time.LocalDateTime} + AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY cc.owner_user_id @@ -118,8 +111,7 @@ #{userId} - AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and - #{times[1],javaType=java.time.LocalDateTime} + AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime} GROUP BY cc.owner_user_id From 924580f4a29db98d7add392e516be8505d0ed61b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 Mar 2024 13:51:46 +0800 Subject: [PATCH 44/86] =?UTF-8?q?CRM=EF=BC=9A=E9=87=8D=E6=9E=84=E3=80=90?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=94=BB=E5=83=8F=E3=80=91=EF=BC=8C=E4=BB=8E?= =?UTF-8?q?=E3=80=90=E5=AE=A2=E6=88=B7=E7=BB=9F=E8=AE=A1=E3=80=91=E6=8B=86?= =?UTF-8?q?=E5=88=86=E5=87=BA=E5=8E=BB=E5=85=88~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsCustomerController.java | 32 ---- .../CrmStatisticsPortraitController.java | 61 +++++++ .../CrmStatisticsRankController.java | 1 - .../customer/CrmStatisticsCustomerReqVO.java | 8 - .../CrmStatisticCustomerAreaRespVO.java | 2 +- .../CrmStatisticCustomerIndustryRespVO.java | 2 +- .../CrmStatisticCustomerLevelRespVO.java | 2 +- .../CrmStatisticCustomerSourceRespVO.java | 2 +- .../CrmStatisticsCustomerMapper.java | 14 +- .../CrmStatisticsPortraitMapper.java | 28 +++ .../CrmStatisticsCustomerService.java | 36 ---- .../CrmStatisticsCustomerServiceImpl.java | 107 ----------- .../CrmStatisticsPortraitService.java | 50 ++++++ .../CrmStatisticsPortraitServiceImpl.java | 166 ++++++++++++++++++ .../CrmStatisticsCustomerMapper.xml | 85 --------- .../CrmStatisticsPortraitMapper.xml | 90 ++++++++++ 16 files changed, 400 insertions(+), 286 deletions(-) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/{customer/analyze => portrait}/CrmStatisticCustomerAreaRespVO.java (98%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/{customer/analyze => portrait}/CrmStatisticCustomerIndustryRespVO.java (98%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/{customer/analyze => portrait}/CrmStatisticCustomerLevelRespVO.java (98%) rename yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/{customer/analyze => portrait}/CrmStatisticCustomerSourceRespVO.java (98%) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index 413bae8f88..450a9cd99e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -2,10 +2,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -90,32 +86,4 @@ public class CrmStatisticsCustomerController { // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析; - @GetMapping("/get-customer-industry-summary") - @Operation(summary = "获取客户行业统计数据") - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getCustomerIndustry(reqVO)); - } - - @GetMapping("/get-customer-source-summary") - @Operation(summary = "获取客户来源统计数据") - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getCustomerSource(reqVO)); - } - - @GetMapping("/get-customer-level-summary") - @Operation(summary = "获取客户级别统计数据") - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getCustomerLevel(reqVO)); - } - - @GetMapping("/get-customer-area-summary") - @Operation(summary = "获取客户地区统计数据") - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getCustomerArea(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getCustomerArea(reqVO)); - } - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java new file mode 100644 index 0000000000..90ef266880 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsPortraitService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 客户画像") +@RestController +@RequestMapping("/crm/statistics-portrait") +@Validated +public class CrmStatisticsPortraitController { + + @Resource + private CrmStatisticsPortraitService statisticsPortraitService; + + @GetMapping("/get-customer-area-summary") + @Operation(summary = "获取客户地区统计数据", description = "用于【城市分布分析】页面") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerAreaSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(statisticsPortraitService.getCustomerArea(reqVO)); + } + + @GetMapping("/get-customer-industry-summary") + @Operation(summary = "获取客户行业统计数据") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(statisticsPortraitService.getCustomerIndustry(reqVO)); + } + + @GetMapping("/get-customer-level-summary") + @Operation(summary = "获取客户级别统计数据") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(statisticsPortraitService.getCustomerLevel(reqVO)); + } + + @GetMapping("/get-customer-source-summary") + @Operation(summary = "获取客户来源统计数据") + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") + public CommonResult> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSource(reqVO)); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java index f3757ea28c..974963d33b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java @@ -18,7 +18,6 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - @Tag(name = "管理后台 - CRM 排行榜统计") @RestController @RequestMapping("/crm/statistics-rank") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java index 0564c2679e..5c887c6af3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java @@ -45,12 +45,4 @@ public class CrmStatisticsCustomerReqVO { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] times; - /** - * group by DATE_FORMAT(field, #{dateFormat}) - * 非前端传递, 由Service计算后传递给Mapper的参数 - */ - @Deprecated - @Schema(description = "Group By 日期格式", hidden = true, example = "%Y%m") - private String sqlDateFormat; - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java similarity index 98% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java index 5f6924d58d..05220d47c6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java similarity index 98% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java index 4811740923..8d368a3067 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java similarity index 98% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java index 74e06918c9..5d6e9793da 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java similarity index 98% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java index 2edba39edb..60b938139e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index f2e9dc9f34..b7f495b616 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -1,16 +1,12 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import org.apache.ibatis.annotations.Mapper; import java.util.List; /** - * CRM 数据统计 员工客户分析 Mapper + * CRM 数据统计 Mapper * * @author dhb52 */ @@ -45,12 +41,4 @@ public interface CrmStatisticsCustomerMapper { List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); - List selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); - - List selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); - - List selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); - - List selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO); - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java new file mode 100644 index 0000000000..25b7cb2d2b --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 数据画像 Mapper + * + * @author dhb52 + */ +@Mapper +public interface CrmStatisticsPortraitMapper { + + List selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); + + List selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); + + List selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); + + List selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index a69e1b9a07..55317f4aec 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -1,10 +1,6 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import java.util.List; @@ -81,36 +77,4 @@ public interface CrmStatisticsCustomerService { */ List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); - /** - * 获取客户行业统计数据 - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO); - - /** - * 获取客户来源统计数据 - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List getCustomerSource(CrmStatisticsCustomerReqVO reqVO); - - /** - * 获取客户级别统计数据 - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); - - /** - * 获取客户地区统计数据 - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List getCustomerArea(CrmStatisticsCustomerReqVO reqVO); - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index e20d3a9631..250560ef29 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -4,14 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.framework.ip.core.Area; -import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; -import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -30,8 +23,6 @@ import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; /** * CRM 客户分析 Service 实现类 @@ -245,104 +236,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe return summaryList; } - @Override - public List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { - return Collections.emptyList(); - } - reqVO.setUserIds(userIds); - // 2. 获取客户行业统计数据 - List industryRespVOList = customerMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO); - if (CollUtil.isEmpty(industryRespVOList)) { - return Collections.emptyList(); - } - - return convertList(industryRespVOList, item -> { - if (ObjUtil.isNull(item.getIndustryId())) { - return item; - } - item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId())); - return item; - }); - } - - @Override - public List getCustomerSource(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { - return Collections.emptyList(); - } - reqVO.setUserIds(userIds); - // 2. 获取客户行业统计数据 - List sourceRespVOList = customerMapper.selectCustomerSourceListGroupbySource(reqVO); - if (CollUtil.isEmpty(sourceRespVOList)) { - return Collections.emptyList(); - } - - return convertList(sourceRespVOList, item -> { - if (ObjUtil.isNull(item.getSource())) { - return item; - } - item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource())); - return item; - }); - } - - @Override - public List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { - return Collections.emptyList(); - } - reqVO.setUserIds(userIds); - // 2. 获取客户行业统计数据 - List levelRespVOList = customerMapper.selectCustomerLevelListGroupbyLevel(reqVO); - if (CollUtil.isEmpty(levelRespVOList)) { - return Collections.emptyList(); - } - - return convertList(levelRespVOList, item -> { - if (ObjUtil.isNull(item.getLevel())) { - return item; - } - item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel())); - return item; - }); - } - - @Override - public List getCustomerArea(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { - return Collections.emptyList(); - } - reqVO.setUserIds(userIds); - // 2. 获取客户地区统计数据 - List list = customerMapper.selectSummaryListByAreaId(reqVO); - if (CollUtil.isEmpty(list)) { - return Collections.emptyList(); - } - - // 拼接数据 - List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); - areaList.add(new Area().setId(null).setName("未知")); - Map areaMap = convertMap(areaList, Area::getId); - List customerAreaRespVOList = convertList(list, item -> { - Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); - if (parentId == null) { - return item; - } - findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); - return item; - }); - return customerAreaRespVOList; - } - /** * 拼接用户信息(昵称) * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java new file mode 100644 index 0000000000..33afe0ecac --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO; + +import java.util.List; + +/** + * CRM 客户画像 Service 接口 + * + * @author HUIHUI + */ +public interface CrmStatisticsPortraitService { + + /** + * 获取客户地区统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerArea(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取客户行业统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取客户级别统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); + + /** + * 获取客户来源统计数据 + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getCustomerSource(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java new file mode 100644 index 0000000000..2e63d8786b --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java @@ -0,0 +1,166 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPortraitMapper; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; + +/** + * CRM 客户画像 Service 实现类 + * + * @author HUIHUI + */ +@Service +public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitService { + + @Resource + private CrmStatisticsPortraitMapper portraitMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + @Resource + private DictDataApi dictDataApi; + + @Override + public List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 + List industryRespVOList = portraitMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO); + if (CollUtil.isEmpty(industryRespVOList)) { + return Collections.emptyList(); + } + + return convertList(industryRespVOList, item -> { + if (ObjUtil.isNull(item.getIndustryId())) { + return item; + } + item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId())); + return item; + }); + } + + @Override + public List getCustomerSource(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 + List sourceRespVOList = portraitMapper.selectCustomerSourceListGroupbySource(reqVO); + if (CollUtil.isEmpty(sourceRespVOList)) { + return Collections.emptyList(); + } + + return convertList(sourceRespVOList, item -> { + if (ObjUtil.isNull(item.getSource())) { + return item; + } + item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource())); + return item; + }); + } + + @Override + public List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 + List levelRespVOList = portraitMapper.selectCustomerLevelListGroupbyLevel(reqVO); + if (CollUtil.isEmpty(levelRespVOList)) { + return Collections.emptyList(); + } + + return convertList(levelRespVOList, item -> { + if (ObjUtil.isNull(item.getLevel())) { + return item; + } + item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel())); + return item; + }); + } + + @Override + public List getCustomerArea(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户地区统计数据 + List list = portraitMapper.selectSummaryListByAreaId(reqVO); + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + + // 拼接数据 + List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); + areaList.add(new Area().setId(null).setName("未知")); + Map areaMap = convertMap(areaList, Area::getId); + List customerAreaRespVOList = convertList(list, item -> { + Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); + if (parentId == null) { + return item; + } + findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); + return item; + }); + return customerAreaRespVOList; + } + + /** + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsCustomerReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return List.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + List deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId); + deptIds.add(reqVO.getDeptId()); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index acf3545057..0672d629e1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -229,89 +229,4 @@ GROUP BY customer.owner_user_id - - - - - diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml new file mode 100644 index 0000000000..0364027c7b --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml @@ -0,0 +1,90 @@ + + + + + + + + + + From 3f5724e97803557d54a746ee26f4cc6cbf78e3d2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 Mar 2024 14:17:28 +0800 Subject: [PATCH 45/86] =?UTF-8?q?CRM=EF=BC=9Acode=20review=E3=80=90?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=94=BB=E5=83=8F=E3=80=91=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsPortraitController.java | 22 +++--- .../CrmStatisticCustomerAreaRespVO.java | 2 + .../CrmStatisticCustomerIndustryRespVO.java | 3 + .../CrmStatisticCustomerLevelRespVO.java | 5 +- .../CrmStatisticCustomerSourceRespVO.java | 5 +- .../CrmStatisticsPortraitMapper.java | 4 +- .../CrmStatisticsPortraitService.java | 8 +-- .../CrmStatisticsPortraitServiceImpl.java | 67 ++++++++++--------- .../CrmStatisticsPortraitMapper.xml | 2 + 9 files changed, 69 insertions(+), 49 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java index 90ef266880..0f1e9e6355 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java @@ -30,32 +30,34 @@ public class CrmStatisticsPortraitController { @Resource private CrmStatisticsPortraitService statisticsPortraitService; + // TODO @puhui999:搞个属于自己的 CrmStatisticsCustomerReqVO 类哈 + @GetMapping("/get-customer-area-summary") @Operation(summary = "获取客户地区统计数据", description = "用于【城市分布分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") public CommonResult> getCustomerAreaSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerArea(reqVO)); + return success(statisticsPortraitService.getCustomerAreaSummary(reqVO)); } @GetMapping("/get-customer-industry-summary") - @Operation(summary = "获取客户行业统计数据") + @Operation(summary = "获取客户行业统计数据", description = "用于【客户行业分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") - public CommonResult> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerIndustry(reqVO)); + public CommonResult> getCustomerIndustrySummary(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(statisticsPortraitService.getCustomerIndustrySummary(reqVO)); } @GetMapping("/get-customer-level-summary") - @Operation(summary = "获取客户级别统计数据") + @Operation(summary = "获取客户级别统计数据", description = "用于【客户级别分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") - public CommonResult> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerLevel(reqVO)); + public CommonResult> getCustomerLevelSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(statisticsPortraitService.getCustomerLevelSummary(reqVO)); } @GetMapping("/get-customer-source-summary") - @Operation(summary = "获取客户来源统计数据") + @Operation(summary = "获取客户来源统计数据", description = "用于【客户来源分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") - public CommonResult> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerSource(reqVO)); + public CommonResult> getCustomerSourceSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSourceSummary(reqVO)); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java index 05220d47c6..e83563d5b1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java @@ -18,6 +18,8 @@ public class CrmStatisticCustomerAreaRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; + // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 + @Schema(description = "省份占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Double areaPortion; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java index 8d368a3067..4029a42b03 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java @@ -9,6 +9,7 @@ public class CrmStatisticCustomerIndustryRespVO { @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer industryId; + // TODO @puhui999:这个前端字典翻译哈 @Schema(description = "客户行业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private String industryName; @@ -18,6 +19,8 @@ public class CrmStatisticCustomerIndustryRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; + // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 + @Schema(description = "行业占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Double industryPortion; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java index 5d6e9793da..c438ee21e1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java @@ -7,8 +7,9 @@ import lombok.Data; @Data public class CrmStatisticCustomerLevelRespVO { - @Schema(description = "客户级别ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @Schema(description = "客户级别编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer level; + // TODO @puhui999:这个前端字典翻译哈 @Schema(description = "客户级别名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private String levelName; @@ -18,6 +19,8 @@ public class CrmStatisticCustomerLevelRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; + // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 + @Schema(description = "级别占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Double levelPortion; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java index 60b938139e..e66a5c634f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java @@ -7,8 +7,9 @@ import lombok.Data; @Data public class CrmStatisticCustomerSourceRespVO { - @Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @Schema(description = "客户来源编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer source; + // TODO @puhui999:这个前端字典翻译哈 @Schema(description = "客户来源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private String sourceName; @@ -18,6 +19,8 @@ public class CrmStatisticCustomerSourceRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; + // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 + @Schema(description = "来源占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Double sourcePortion; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java index 25b7cb2d2b..193cc93072 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java @@ -12,11 +12,13 @@ import java.util.List; /** * CRM 数据画像 Mapper * - * @author dhb52 + * @author HUIHUI */ @Mapper public interface CrmStatisticsPortraitMapper { + // TODO @puuhui999:GroupBy + List selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); List selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java index 33afe0ecac..dd1f3e3daf 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java @@ -21,7 +21,7 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerArea(CrmStatisticsCustomerReqVO reqVO); + List getCustomerAreaSummary(CrmStatisticsCustomerReqVO reqVO); /** * 获取客户行业统计数据 @@ -29,7 +29,7 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO); + List getCustomerIndustrySummary(CrmStatisticsCustomerReqVO reqVO); /** * 获取客户级别统计数据 @@ -37,7 +37,7 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); + List getCustomerLevelSummary(CrmStatisticsCustomerReqVO reqVO); /** * 获取客户来源统计数据 @@ -45,6 +45,6 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerSource(CrmStatisticsCustomerReqVO reqVO); + List getCustomerSourceSummary(CrmStatisticsCustomerReqVO reqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java index 2e63d8786b..e38a702bcb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java @@ -28,6 +28,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; +// TODO @puhui999:参考 CrmStatisticsCustomerServiceImpl 代码风格,优化下这个类哈;包括命名、空行、注释等; /** * CRM 客户画像 Service 实现类 * @@ -47,7 +48,37 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe private DictDataApi dictDataApi; @Override - public List getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) { + public List getCustomerAreaSummary(CrmStatisticsCustomerReqVO reqVO) { + // 1. 获得用户编号数组 + List userIds = getUserIds(reqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + reqVO.setUserIds(userIds); + // 2. 获取客户地区统计数据 + List list = portraitMapper.selectSummaryListByAreaId(reqVO); + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + + // 拼接数据 + List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); + areaList.add(new Area().setId(null).setName("未知")); + Map areaMap = convertMap(areaList, Area::getId); + List customerAreaRespVOList = convertList(list, item -> { + Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); + // TODO @puhui999:找不到,可以归到未知哈; + if (parentId == null) { + return item; + } + findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); + return item; + }); + return customerAreaRespVOList; + } + + @Override + public List getCustomerIndustrySummary(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { @@ -70,13 +101,14 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe } @Override - public List getCustomerSource(CrmStatisticsCustomerReqVO reqVO) { + public List getCustomerSourceSummary(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { return Collections.emptyList(); } reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 List sourceRespVOList = portraitMapper.selectCustomerSourceListGroupbySource(reqVO); if (CollUtil.isEmpty(sourceRespVOList)) { @@ -93,7 +125,7 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe } @Override - public List getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) { + public List getCustomerLevelSummary(CrmStatisticsCustomerReqVO reqVO) { // 1. 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { @@ -115,35 +147,6 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe }); } - @Override - public List getCustomerArea(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { - return Collections.emptyList(); - } - reqVO.setUserIds(userIds); - // 2. 获取客户地区统计数据 - List list = portraitMapper.selectSummaryListByAreaId(reqVO); - if (CollUtil.isEmpty(list)) { - return Collections.emptyList(); - } - - // 拼接数据 - List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); - areaList.add(new Area().setId(null).setName("未知")); - Map areaMap = convertMap(areaList, Area::getId); - List customerAreaRespVOList = convertList(list, item -> { - Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); - if (parentId == null) { - return item; - } - findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); - return item; - }); - return customerAreaRespVOList; - } - /** * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml index 0364027c7b..946bd292b8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml @@ -2,6 +2,8 @@ + + - SELECT - DATE_FORMAT(create_time, '%Y-%m-%d') AS time, - COUNT(*) AS customerCreateCount - FROM crm_customer - WHERE deleted = 0 - AND owner_user_id IN - - #{userId} - - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - GROUP BY time + SELECT DATE_FORMAT(create_time, '%Y-%m-%d') AS time, + COUNT(*) AS customerCreateCount + FROM crm_customer + WHERE deleted = 0 + AND owner_user_id IN + + #{userId} + + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + GROUP BY time From a9a8efc808cb037692c253147833c24badcea50b Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 3 Apr 2024 10:09:46 +0800 Subject: [PATCH 51/86] =?UTF-8?q?CRM:=20=E5=AE=8C=E5=96=84=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=94=BB=E5=83=8F=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsPortraitController.java | 20 ++- .../CrmStatisticCustomerAreaRespVO.java | 8 -- .../CrmStatisticCustomerIndustryRespVO.java | 11 -- .../CrmStatisticCustomerLevelRespVO.java | 11 -- .../CrmStatisticCustomerSourceRespVO.java | 11 -- .../portrait/CrmStatisticsPortraitReqVO.java | 42 ++++++ .../CrmStatisticsPortraitMapper.java | 16 +-- .../CrmStatisticsPortraitService.java | 14 +- .../CrmStatisticsPortraitServiceImpl.java | 74 +++------- .../CrmStatisticsPortraitMapper.xml | 129 +++++++----------- 10 files changed, 132 insertions(+), 204 deletions(-) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java index 0f1e9e6355..986e2268c4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticsPortraitReqVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; @@ -30,34 +30,32 @@ public class CrmStatisticsPortraitController { @Resource private CrmStatisticsPortraitService statisticsPortraitService; - // TODO @puhui999:搞个属于自己的 CrmStatisticsCustomerReqVO 类哈 - @GetMapping("/get-customer-area-summary") @Operation(summary = "获取客户地区统计数据", description = "用于【城市分布分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") - public CommonResult> getCustomerAreaSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerAreaSummary(reqVO)); + public CommonResult> getCustomerAreaSummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryByArea(reqVO)); } @GetMapping("/get-customer-industry-summary") @Operation(summary = "获取客户行业统计数据", description = "用于【客户行业分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") - public CommonResult> getCustomerIndustrySummary(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerIndustrySummary(reqVO)); + public CommonResult> getCustomerIndustrySummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryByIndustry(reqVO)); } @GetMapping("/get-customer-level-summary") @Operation(summary = "获取客户级别统计数据", description = "用于【客户级别分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") - public CommonResult> getCustomerLevelSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerLevelSummary(reqVO)); + public CommonResult> getCustomerLevelSummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryByLevel(reqVO)); } @GetMapping("/get-customer-source-summary") @Operation(summary = "获取客户来源统计数据", description = "用于【客户来源分析】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") - public CommonResult> getCustomerSourceSummary(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(statisticsPortraitService.getCustomerSourceSummary(reqVO)); + public CommonResult> getCustomerSourceSummary(@Valid CrmStatisticsPortraitReqVO reqVO) { + return success(statisticsPortraitService.getCustomerSummaryBySource(reqVO)); } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java index e83563d5b1..3420e7e5b6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java @@ -18,12 +18,4 @@ public class CrmStatisticCustomerAreaRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 - - @Schema(description = "省份占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double areaPortion; - - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double dealPortion; - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java index 4029a42b03..84b8de70f3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java @@ -9,9 +9,6 @@ public class CrmStatisticCustomerIndustryRespVO { @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer industryId; - // TODO @puhui999:这个前端字典翻译哈 - @Schema(description = "客户行业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private String industryName; @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer customerCount; @@ -19,12 +16,4 @@ public class CrmStatisticCustomerIndustryRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 - - @Schema(description = "行业占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double industryPortion; - - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double dealPortion; - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java index c438ee21e1..dea4eeb0c8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java @@ -9,9 +9,6 @@ public class CrmStatisticCustomerLevelRespVO { @Schema(description = "客户级别编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer level; - // TODO @puhui999:这个前端字典翻译哈 - @Schema(description = "客户级别名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private String levelName; @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer customerCount; @@ -19,12 +16,4 @@ public class CrmStatisticCustomerLevelRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 - - @Schema(description = "级别占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double levelPortion; - - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double dealPortion; - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java index e66a5c634f..61b9688ff4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java @@ -9,9 +9,6 @@ public class CrmStatisticCustomerSourceRespVO { @Schema(description = "客户来源编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer source; - // TODO @puhui999:这个前端字典翻译哈 - @Schema(description = "客户来源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private String sourceName; @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer customerCount; @@ -19,12 +16,4 @@ public class CrmStatisticCustomerSourceRespVO { @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer dealCount; - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。 - - @Schema(description = "来源占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double sourcePortion; - - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Double dealPortion; - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java new file mode 100644 index 0000000000..c284e7457f --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 客户画像 Request VO") +@Data +public class CrmStatisticsPortraitReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + /** + * 负责人用户 id, 当用户为空, 则计算部门下用户 + */ + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + /** + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 + * 后续,可能会支持选择部分用户进行查询 + */ + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") + private List userIds; + + /** + * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间 + * 并作为参数传递给Mapper + */ + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] times; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java index 193cc93072..a7c942752b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java @@ -1,10 +1,6 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -17,14 +13,12 @@ import java.util.List; @Mapper public interface CrmStatisticsPortraitMapper { - // TODO @puuhui999:GroupBy + List selectSummaryListGroupByAreaId(CrmStatisticsPortraitReqVO reqVO); - List selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerIndustryListGroupByIndustryId(CrmStatisticsPortraitReqVO reqVO); - List selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerSourceListGroupBySource(CrmStatisticsPortraitReqVO reqVO); - List selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); - - List selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO); + List selectCustomerLevelListGroupByLevel(CrmStatisticsPortraitReqVO reqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java index dd1f3e3daf..c568d3b4ec 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java @@ -1,10 +1,6 @@ package cn.iocoder.yudao.module.crm.service.statistics; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*; import java.util.List; @@ -21,7 +17,7 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerAreaSummary(CrmStatisticsCustomerReqVO reqVO); + List getCustomerSummaryByArea(CrmStatisticsPortraitReqVO reqVO); /** * 获取客户行业统计数据 @@ -29,7 +25,7 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerIndustrySummary(CrmStatisticsCustomerReqVO reqVO); + List getCustomerSummaryByIndustry(CrmStatisticsPortraitReqVO reqVO); /** * 获取客户级别统计数据 @@ -37,7 +33,7 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerLevelSummary(CrmStatisticsCustomerReqVO reqVO); + List getCustomerSummaryByLevel(CrmStatisticsPortraitReqVO reqVO); /** * 获取客户来源统计数据 @@ -45,6 +41,6 @@ public interface CrmStatisticsPortraitService { * @param reqVO 请求参数 * @return 统计数据 */ - List getCustomerSourceSummary(CrmStatisticsCustomerReqVO reqVO); + List getCustomerSummaryBySource(CrmStatisticsPortraitReqVO reqVO); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java index e38a702bcb..9863f62fcf 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java @@ -5,15 +5,10 @@ import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.ip.core.Area; import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPortraitMapper; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; @@ -26,9 +21,7 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; -// TODO @puhui999:参考 CrmStatisticsCustomerServiceImpl 代码风格,优化下这个类哈;包括命名、空行、注释等; /** * CRM 客户画像 Service 实现类 * @@ -44,64 +37,54 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; - @Resource - private DictDataApi dictDataApi; @Override - public List getCustomerAreaSummary(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 + public List getCustomerSummaryByArea(CrmStatisticsPortraitReqVO reqVO) { + // 1.1 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { return Collections.emptyList(); } reqVO.setUserIds(userIds); - // 2. 获取客户地区统计数据 - List list = portraitMapper.selectSummaryListByAreaId(reqVO); + // 1.2 获取客户地区统计数据 + List list = portraitMapper.selectSummaryListGroupByAreaId(reqVO); if (CollUtil.isEmpty(list)) { return Collections.emptyList(); } - // 拼接数据 + // 2. 拼接数据 List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); areaList.add(new Area().setId(null).setName("未知")); Map areaMap = convertMap(areaList, Area::getId); - List customerAreaRespVOList = convertList(list, item -> { + return convertList(list, item -> { Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); - // TODO @puhui999:找不到,可以归到未知哈; - if (parentId == null) { - return item; + if (parentId == null) { // 找不到,归到未知 + return item.setAreaId(null).setAreaName("未知"); } findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); return item; }); - return customerAreaRespVOList; } @Override - public List getCustomerIndustrySummary(CrmStatisticsCustomerReqVO reqVO) { + public List getCustomerSummaryByIndustry(CrmStatisticsPortraitReqVO reqVO) { // 1. 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { return Collections.emptyList(); } reqVO.setUserIds(userIds); + // 2. 获取客户行业统计数据 - List industryRespVOList = portraitMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO); + List industryRespVOList = portraitMapper.selectCustomerIndustryListGroupByIndustryId(reqVO); if (CollUtil.isEmpty(industryRespVOList)) { return Collections.emptyList(); } - - return convertList(industryRespVOList, item -> { - if (ObjUtil.isNull(item.getIndustryId())) { - return item; - } - item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId())); - return item; - }); + return industryRespVOList; } @Override - public List getCustomerSourceSummary(CrmStatisticsCustomerReqVO reqVO) { + public List getCustomerSummaryBySource(CrmStatisticsPortraitReqVO reqVO) { // 1. 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { @@ -110,41 +93,28 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe reqVO.setUserIds(userIds); // 2. 获取客户行业统计数据 - List sourceRespVOList = portraitMapper.selectCustomerSourceListGroupbySource(reqVO); + List sourceRespVOList = portraitMapper.selectCustomerSourceListGroupBySource(reqVO); if (CollUtil.isEmpty(sourceRespVOList)) { return Collections.emptyList(); } - - return convertList(sourceRespVOList, item -> { - if (ObjUtil.isNull(item.getSource())) { - return item; - } - item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource())); - return item; - }); + return sourceRespVOList; } @Override - public List getCustomerLevelSummary(CrmStatisticsCustomerReqVO reqVO) { + public List getCustomerSummaryByLevel(CrmStatisticsPortraitReqVO reqVO) { // 1. 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { return Collections.emptyList(); } reqVO.setUserIds(userIds); - // 2. 获取客户行业统计数据 - List levelRespVOList = portraitMapper.selectCustomerLevelListGroupbyLevel(reqVO); + + // 2. 获取客户级别统计数据 + List levelRespVOList = portraitMapper.selectCustomerLevelListGroupByLevel(reqVO); if (CollUtil.isEmpty(levelRespVOList)) { return Collections.emptyList(); } - - return convertList(levelRespVOList, item -> { - if (ObjUtil.isNull(item.getLevel())) { - return item; - } - item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel())); - return item; - }); + return levelRespVOList; } /** @@ -153,7 +123,7 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe * @param reqVO 请求参数 * @return 用户编号数组 */ - private List getUserIds(CrmStatisticsCustomerReqVO reqVO) { + private List getUserIds(CrmStatisticsPortraitReqVO reqVO) { // 情况一:选中某个用户 if (ObjUtil.isNotNull(reqVO.getUserId())) { return List.of(reqVO.getUserId()); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml index 946bd292b8..42056a48b5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml @@ -2,91 +2,60 @@ - - - - - - + + + + + + From d9758636b191a4b7d0201b8d3943c15c5b7b220a Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Fri, 5 Apr 2024 12:59:37 +0800 Subject: [PATCH 52/86] =?UTF-8?q?=E4=BB=BF=E9=92=89=E9=92=89=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AE=BE=E8=AE=A1-=E6=8A=84=E9=80=81=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmSimpleModelNodeType.java | 4 +- .../flowable/core/util/BpmnModelUtils.java | 58 +++++++++++++------ .../task/BpmProcessInstanceCopyService.java | 6 +- .../BpmProcessInstanceCopyServiceImpl.java | 18 +++--- .../service/task/BpmSimpleNodeService.java | 34 +++++++++++ .../bpm/service/task/BpmTaskServiceImpl.java | 3 +- 6 files changed, 90 insertions(+), 33 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java index 75889985e2..4e26d02d9f 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java @@ -20,8 +20,10 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批; START_EVENT_NODE(0, "开始节点"), APPROVE_USER_NODE (1, "审批人节点"), + // 抄送人节点、对应 BPMN 的 ScriptTask. 使用ScriptTask 原因。好像 ServiceTask 自定义属性不能写入 XML + SCRIPT_TASK_NODE(2, "抄送人节点"), EXCLUSIVE_GATEWAY_NODE(4, "排他网关"), - END_NODE(-2, "结束节点"); + END_EVENT_NODE(-2, "结束节点"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 17c36623b3..03745adceb 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -13,6 +13,7 @@ import org.flowable.bpmn.BpmnAutoLayout; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; +import org.flowable.common.engine.impl.scripting.ScriptingEngines; import org.flowable.common.engine.impl.util.io.BytesStreamSource; import java.util.ArrayList; @@ -20,11 +21,15 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import static org.flowable.bpmn.constants.BpmnXMLConstants.*; + /** * 流程模型转操作工具类 */ public class BpmnModelUtils { + public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}"; + public static Integer parseCandidateStrategy(FlowElement userTask) { return NumberUtils.parseInt(userTask.getAttributeValue( BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); @@ -379,26 +384,27 @@ public class BpmnModelUtils { Assert.notNull(nodeType, "模型节点类型不支持"); switch (nodeType) { case START_EVENT_NODE: - case APPROVE_USER_NODE: { + case APPROVE_USER_NODE: + case SCRIPT_TASK_NODE: { addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null, null); // 递归调用后续节点 - addBpmnSequenceFlow(mainProcess, childNode,endId); + addBpmnSequenceFlow(mainProcess, childNode, endId); break; } case EXCLUSIVE_GATEWAY_NODE: { - String gateWayEndId = ( childNode == null || childNode.getId() == null ) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); + String gateWayEndId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); List conditionNodes = node.getConditionNodes(); Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); for (int i = 0; i < conditionNodes.size(); i++) { BpmSimpleModelNodeVO item = conditionNodes.get(i); - BpmSimpleModelNodeVO nextNodeOnCondition = getNextNodeOnCondition(item); + BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode(); if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) { addBpmnSequenceFlowElement(mainProcess, node.getId(), nextNodeOnCondition.getId(), - String.format("%s_SequenceFlow_%d", node.getId(), i+1), null); + String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); addBpmnSequenceFlow(mainProcess, nextNodeOnCondition, gateWayEndId); } else { addBpmnSequenceFlowElement(mainProcess, node.getId(), gateWayEndId, - String.format("%s_SequenceFlow_%d", node.getId(), i+1), null); + String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); } } // 递归调用后续节点 @@ -412,10 +418,6 @@ public class BpmnModelUtils { } - private static BpmSimpleModelNodeVO getNextNodeOnCondition(BpmSimpleModelNodeVO conditionNode) { - return conditionNode.getChildNode(); - } - private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String seqFlowId, String conditionExpression) { SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); if (StrUtil.isNotEmpty(conditionExpression)) { @@ -439,7 +441,10 @@ public class BpmnModelUtils { addBpmnStartEventNode(mainProcess, simpleModelNode); break; case APPROVE_USER_NODE: - addBpmnUserTaskEventNode(mainProcess, simpleModelNode); + addBpmnUserTaskNode(mainProcess, simpleModelNode); + break; + case SCRIPT_TASK_NODE: + addBpmnScriptTaSskNode(mainProcess, simpleModelNode); break; case EXCLUSIVE_GATEWAY_NODE: addBpmnExclusiveGatewayNode(mainProcess, simpleModelNode); @@ -467,6 +472,25 @@ public class BpmnModelUtils { } } + private static void addBpmnScriptTaSskNode(Process mainProcess, BpmSimpleModelNodeVO node) { + ScriptTask scriptTask = new ScriptTask(); + scriptTask.setId(node.getId()); + scriptTask.setName(node.getName()); + scriptTask.setScriptFormat(ScriptingEngines.DEFAULT_SCRIPTING_LANGUAGE); + scriptTask.setScript(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT); + // 添加自定义属性 + addExtensionAttributes(node, scriptTask); + mainProcess.addFlowElement(scriptTask); + } + + private static void addExtensionAttributes(BpmSimpleModelNodeVO node, FlowElement flowElement) { + Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); + addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, + candidateStrategy == null ? null : String.valueOf(candidateStrategy)); + addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, + MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); + } + private static void addBpmnExclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) { Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); @@ -483,25 +507,21 @@ public class BpmnModelUtils { mainProcess.addFlowElement(endEvent); } - private static void addBpmnUserTaskEventNode(Process mainProcess, BpmSimpleModelNodeVO node) { + private static void addBpmnUserTaskNode(Process mainProcess, BpmSimpleModelNodeVO node) { UserTask userTask = new UserTask(); userTask.setId(node.getId()); userTask.setName(node.getName()); - Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); - // 添加自定义属性 - addExtensionAttribute(userTask, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, - candidateStrategy == null ? null : String.valueOf(candidateStrategy)); - addExtensionAttribute(userTask, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, - MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); + addExtensionAttributes(node, userTask); mainProcess.addFlowElement(userTask); } - private static void addExtensionAttribute(FlowElement element, String namespace, String name, String value) { + private static void addExtensionAttributes(FlowElement element, String namespace, String name, String value) { if (value == null) { return; } ExtensionAttribute extensionAttribute = new ExtensionAttribute(name, value); extensionAttribute.setNamespace(namespace); + extensionAttribute.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX); element.addAttribute(extensionAttribute); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java index bd84490e8e..94df76d4d8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java @@ -17,9 +17,11 @@ public interface BpmProcessInstanceCopyService { * 流程实例的抄送 * * @param userIds 抄送的用户编号 - * @param taskId 流程任务编号 + * @param processInstanceId 流程编号 + * @param taskId 任务编号 + * @param taskName 任务名称 */ - void createProcessInstanceCopy(Collection userIds, String taskId); + void createProcessInstanceCopy(Collection userIds, String processInstanceId, String taskId, String taskName); /** * 获得抄送的流程的分页 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java index aba8bd9f17..ce1ddd7fd2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.bpm.service.task; -import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; @@ -11,7 +10,6 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -47,14 +45,14 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy private BpmProcessDefinitionService processDefinitionService; @Override - public void createProcessInstanceCopy(Collection userIds, String taskId) { - // 1.1 校验任务存在 - Task task = taskService.getTask(taskId); - if (ObjectUtil.isNull(task)) { - throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); - } + public void createProcessInstanceCopy(Collection userIds, String processInstanceId, String taskId, String taskName) { + // 1.1 校验任务存在 暂时去掉这个校验. 因为任务可能仿钉钉快搭的抄送节点(ScriptTask) +// Task task = taskService.getTask(taskId); +// if (ObjectUtil.isNull(task)) { +// throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); +// } // 1.2 校验流程实例存在 - String processInstanceId = task.getProcessInstanceId(); +// String processInstanceId = task.getProcessInstanceId(); ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId); if (processInstance == null) { throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); @@ -70,7 +68,7 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy List copyList = convertList(userIds, userId -> new BpmProcessInstanceCopyDO() .setUserId(userId).setStartUserId(Long.valueOf(processInstance.getStartUserId())) .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName()) - .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(task.getName())); + .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(taskName)); processInstanceCopyMapper.insertBatch(copyList); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java new file mode 100644 index 0000000000..89ba0ee84c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.bpm.service.task; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import jakarta.annotation.Resource; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Service; + +import java.util.Set; + +/** + * 仿钉钉快搭各个节点 Service + * @author jason + */ +@Service +public class BpmSimpleNodeService { + + @Resource + private BpmTaskCandidateInvoker taskCandidateInvoker; + @Resource + private BpmProcessInstanceCopyService processInstanceCopyService; + + /** + * 仿钉钉快搭抄送 + * @param execution 执行的任务(ScriptTask) + */ + public Boolean copy(DelegateExecution execution) { + Set userIds = taskCandidateInvoker.calculateUsers(execution); + FlowElement currentFlowElement = execution.getCurrentFlowElement(); + processInstanceCopyService.createProcessInstanceCopy(userIds, execution.getProcessInstanceId(), + currentFlowElement.getId(), currentFlowElement.getName()); + return Boolean.TRUE; + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 7afed756b8..5c2de9f483 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -185,7 +185,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2. 抄送用户 if (CollUtil.isNotEmpty(reqVO.getCopyUserIds())) { - processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), reqVO.getId()); + processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), instance.getProcessInstanceId(), + reqVO.getId(), task.getName()); } // 情况一:被委派的任务,不调用 complete 去完成任务 From 05af77b786b0eb370bd721382647646dcc629f58 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 5 Apr 2024 14:44:00 +0800 Subject: [PATCH 53/86] =?UTF-8?q?crm=EF=BC=9Acode=20review=20=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=94=BB=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CrmStatisticsPortraitServiceImpl.java | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java index 9863f62fcf..eae0128664 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java @@ -40,21 +40,22 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe @Override public List getCustomerSummaryByArea(CrmStatisticsPortraitReqVO reqVO) { - // 1.1 获得用户编号数组 + // 1. 获得用户编号数组 List userIds = getUserIds(reqVO); if (CollUtil.isEmpty(userIds)) { return Collections.emptyList(); } reqVO.setUserIds(userIds); - // 1.2 获取客户地区统计数据 + + // 2. 获取客户地区统计数据 List list = portraitMapper.selectSummaryListGroupByAreaId(reqVO); if (CollUtil.isEmpty(list)) { return Collections.emptyList(); } - // 2. 拼接数据 + // 3. 拼接数据 List areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); - areaList.add(new Area().setId(null).setName("未知")); + areaList.add(new Area().setId(null).setName("未知")); // TODO @puhui999:是不是 65 find 的逻辑改下;不用 findAndThen,直接从 areaMap 拿;拿到就设置,不拿到就设置 null 和 未知;这样,58 本行可以删除掉完事了;这样代码更简单和一致 Map areaMap = convertMap(areaList, Area::getId); return convertList(list, item -> { Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); @@ -76,11 +77,7 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe reqVO.setUserIds(userIds); // 2. 获取客户行业统计数据 - List industryRespVOList = portraitMapper.selectCustomerIndustryListGroupByIndustryId(reqVO); - if (CollUtil.isEmpty(industryRespVOList)) { - return Collections.emptyList(); - } - return industryRespVOList; + return portraitMapper.selectCustomerIndustryListGroupByIndustryId(reqVO); } @Override @@ -93,11 +90,7 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe reqVO.setUserIds(userIds); // 2. 获取客户行业统计数据 - List sourceRespVOList = portraitMapper.selectCustomerSourceListGroupBySource(reqVO); - if (CollUtil.isEmpty(sourceRespVOList)) { - return Collections.emptyList(); - } - return sourceRespVOList; + return portraitMapper.selectCustomerSourceListGroupBySource(reqVO); } @Override @@ -110,11 +103,7 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe reqVO.setUserIds(userIds); // 2. 获取客户级别统计数据 - List levelRespVOList = portraitMapper.selectCustomerLevelListGroupByLevel(reqVO); - if (CollUtil.isEmpty(levelRespVOList)) { - return Collections.emptyList(); - } - return levelRespVOList; + return portraitMapper.selectCustomerLevelListGroupByLevel(reqVO); } /** From e18d26d8a6c004394c5c3fd7cb184d3fde402a2f Mon Sep 17 00:00:00 2001 From: dhb52 Date: Fri, 5 Apr 2024 14:59:00 +0800 Subject: [PATCH 54/86] =?UTF-8?q?fix:=20[CRM-=E5=AE=A2=E6=88=B7=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1]=E6=8C=89=E5=AE=A2=E6=88=B7=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=AD=9B=E9=80=89,=E5=85=B3=E8=81=94?= =?UTF-8?q?=E5=90=88=E5=90=8C=E6=98=AF=E5=90=A6=E6=9C=89=E6=88=90=E4=BA=A4?= =?UTF-8?q?=E8=AE=B0=E5=BD=95,=E6=9C=89=E5=88=99=E8=A7=86=E4=B8=BA[?= =?UTF-8?q?=E6=88=90=E4=BA=A4=E5=AE=A2=E6=88=B7]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../statistics/CrmStatisticsCustomerMapper.xml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index b767e20924..7f8b36ba48 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -18,17 +18,18 @@ - SELECT DATE_FORMAT(order_date, '%Y-%m-%d') AS time, - COUNT(DISTINCT customer_id) AS customerDealCount - FROM crm_contract - WHERE deleted = 0 - AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} - AND owner_user_id IN + SELECT DATE_FORMAT(customer.create_time, '%Y-%m-%d') AS time, + COUNT(DISTINCT customer.id) AS customer_deal_count + FROM crm_customer AS customer + LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id + WHERE customer.deleted = 0 AND contract.deleted = 0 + AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} + AND customer.owner_user_id IN #{userId} - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} - GROUP BY time + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + GROUP BY time + - SELECT DATE_FORMAT(customer.create_time, '%Y-%m-%d') AS time, - COUNT(DISTINCT customer.id) AS customer_deal_count + SELECT DATE_FORMAT(customer.create_time, '%Y-%m-%d') AS time, + COUNT(DISTINCT customer.id) AS customer_deal_count FROM crm_customer AS customer LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id - WHERE customer.deleted = 0 AND contract.deleted = 0 + WHERE customer.deleted = 0 + AND contract.deleted = 0 AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND customer.owner_user_id IN #{userId} - AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} GROUP BY time @@ -53,13 +54,14 @@ COUNT(DISTINCT customer.id) AS customer_deal_count FROM crm_customer AS customer LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id - WHERE customer.deleted = 0 AND contract.deleted = 0 + WHERE customer.deleted = 0 + AND contract.deleted = 0 AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND customer.owner_user_id IN #{userId} - AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} GROUP BY customer.owner_user_id @@ -221,4 +223,42 @@ GROUP BY customer.owner_user_id + + + + From 321f71de73fd91dbaf6f334e12260e3feefd6300 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 10 Apr 2024 13:03:20 +0800 Subject: [PATCH 66/86] =?UTF-8?q?=E9=87=8D=E6=9E=84=20LocalDateTimeDeseria?= =?UTF-8?q?lizer=20=E5=92=8C=20LocalDateTimeSerializer=20=E7=9A=84?= =?UTF-8?q?=E5=91=BD=E5=90=8D=EF=BC=8C=E5=8F=AF=E8=AF=BB=E6=80=A7=E6=9B=B4?= =?UTF-8?q?=E5=A5=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/YudaoJacksonAutoConfiguration.java | 12 ++++++------ ....java => TimestampLocalDateTimeDeserializer.java} | 12 +++++++----- ...er.java => TimestampLocalDateTimeSerializer.java} | 12 +++++++----- 3 files changed, 20 insertions(+), 16 deletions(-) rename yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/{LocalDateTimeDeserializer.java => TimestampLocalDateTimeDeserializer.java} (62%) rename yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/{LocalDateTimeSerializer.java => TimestampLocalDateTimeSerializer.java} (62%) diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java index 6ea95b1962..4f94f16ec5 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java @@ -2,9 +2,9 @@ package cn.iocoder.yudao.framework.jackson.config; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer; -import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer; import cn.iocoder.yudao.framework.jackson.core.databind.NumberSerializer; +import cn.iocoder.yudao.framework.jackson.core.databind.TimestampLocalDateTimeDeserializer; +import cn.iocoder.yudao.framework.jackson.core.databind.TimestampLocalDateTimeSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; @@ -37,13 +37,13 @@ public class YudaoJacksonAutoConfiguration { .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE) .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE) .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE) - // 新增 LocalDateTime 序列化、反序列化规则 - .addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE) - .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE); + // 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳 + .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) + .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); // 1.2 注册到 objectMapper objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule)); - // 2. 设置 objectMapper 到 JsonUtils { + // 2. 设置 objectMapper 到 JsonUtils JsonUtils.init(CollUtil.getFirst(objectMappers)); log.info("[init][初始化 JsonUtils 成功]"); return new JsonUtils(); diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalDateTimeDeserializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeDeserializer.java similarity index 62% rename from yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalDateTimeDeserializer.java rename to yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeDeserializer.java index 53c40254b3..71a480fbf2 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalDateTimeDeserializer.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeDeserializer.java @@ -10,16 +10,18 @@ import java.time.LocalDateTime; import java.time.ZoneId; /** - * LocalDateTime反序列化规则 - *

- * 会将毫秒级时间戳反序列化为LocalDateTime + * 基于时间戳的 LocalDateTime 反序列化器 + * + * @author 老五 */ -public class LocalDateTimeDeserializer extends JsonDeserializer { +public class TimestampLocalDateTimeDeserializer extends JsonDeserializer { - public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer(); + public static final TimestampLocalDateTimeDeserializer INSTANCE = new TimestampLocalDateTimeDeserializer(); @Override public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + // 将 Long 时间戳,转换为 LocalDateTime 对象 return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault()); } + } diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalDateTimeSerializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeSerializer.java similarity index 62% rename from yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalDateTimeSerializer.java rename to yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeSerializer.java index 286fb733ed..e72c47bb81 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalDateTimeSerializer.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/TimestampLocalDateTimeSerializer.java @@ -9,16 +9,18 @@ import java.time.LocalDateTime; import java.time.ZoneId; /** - * LocalDateTime序列化规则 - *

- * 会将LocalDateTime序列化为毫秒级时间戳 + * 基于时间戳的 LocalDateTime 序列化器 + * + * @author 老五 */ -public class LocalDateTimeSerializer extends JsonSerializer { +public class TimestampLocalDateTimeSerializer extends JsonSerializer { - public static final LocalDateTimeSerializer INSTANCE = new LocalDateTimeSerializer(); + public static final TimestampLocalDateTimeSerializer INSTANCE = new TimestampLocalDateTimeSerializer(); @Override public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + // 将 LocalDateTime 对象,转换为 Long 时间戳 gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } + } From 38db5fe0087afd98c61dd7b54e811f40ae93cdde Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 10 Apr 2024 20:13:31 +0800 Subject: [PATCH 67/86] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20UserIdempotentKeyResolver=20=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=99=A8=EF=BC=8C=E6=94=AF=E6=8C=81=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=BA=A7=E5=88=AB=E7=9A=84=E5=B9=82=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pom.xml | 7 +++++ .../config/YudaoIdempotentConfiguration.java | 6 ++++ .../core/annotation/Idempotent.java | 17 +++++++++++ .../idempotent/core/aop/IdempotentAspect.java | 24 ++++++++++++---- .../impl/DefaultIdempotentKeyResolver.java | 2 +- .../impl/UserIdempotentKeyResolver.java | 28 +++++++++++++++++++ .../core/redis/IdempotentRedisDAO.java | 5 ++++ .../controller/admin/user/UserController.http | 1 + 8 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java diff --git a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml index e4e970f29f..46fd97e438 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml @@ -16,6 +16,13 @@ https://github.com/YunaiV/ruoyi-vue-pro + + + cn.iocoder.boot + yudao-spring-boot-starter-web + provided + + cn.iocoder.boot diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java index 23a75588f8..de74963d23 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.idempotent.core.aop.IdempotentAspect; import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; import org.springframework.boot.autoconfigure.AutoConfiguration; import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; @@ -32,6 +33,11 @@ public class YudaoIdempotentConfiguration { return new DefaultIdempotentKeyResolver(); } + @Bean + public UserIdempotentKeyResolver userIdempotentKeyResolver() { + return new UserIdempotentKeyResolver(); + } + @Bean public ExpressionIdempotentKeyResolver expressionIdempotentKeyResolver() { return new ExpressionIdempotentKeyResolver(); diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java index 579a07c589..cd6add8ca3 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/annotation/Idempotent.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.idempotent.core.annotation; import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -36,6 +38,10 @@ public @interface Idempotent { /** * 使用的 Key 解析器 + * + * @see DefaultIdempotentKeyResolver 全局级别 + * @see UserIdempotentKeyResolver 用户级别 + * @see ExpressionIdempotentKeyResolver 自定义表达式,通过 {@link #keyArg()} 计算 */ Class keyResolver() default DefaultIdempotentKeyResolver.class; /** @@ -43,4 +49,15 @@ public @interface Idempotent { */ String keyArg() default ""; + /** + * 删除 Key,当发生异常时候 + * + * 问题:为什么发生异常时,需要删除 Key 呢? + * 回答:发生异常时,说明业务发生错误,此时需要删除 Key,避免下次请求无法正常执行。 + * + * 问题:为什么不搞 deleteWhenSuccess 执行成功时,需要删除 Key 呢? + * 回答:这种情况下,本质上是分布式锁,推荐使用 @Lock4j 注解 + */ + boolean deleteKeyWhenException() default true; + } diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java index 9453444f86..2d8c76d558 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java @@ -2,14 +2,14 @@ package cn.iocoder.yudao.framework.idempotent.core.aop; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import lombok.extern.slf4j.Slf4j; -import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; import org.springframework.util.Assert; import java.util.List; @@ -36,21 +36,33 @@ public class IdempotentAspect { this.idempotentRedisDAO = idempotentRedisDAO; } - @Before("@annotation(idempotent)") - public void beforePointCut(JoinPoint joinPoint, Idempotent idempotent) { + @Around(value = "@annotation(idempotent)") + public Object beforePointCut(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable { // 获得 IdempotentKeyResolver IdempotentKeyResolver keyResolver = keyResolvers.get(idempotent.keyResolver()); Assert.notNull(keyResolver, "找不到对应的 IdempotentKeyResolver"); // 解析 Key String key = keyResolver.resolver(joinPoint, idempotent); - // 锁定 Key。 + // 1. 锁定 Key boolean success = idempotentRedisDAO.setIfAbsent(key, idempotent.timeout(), idempotent.timeUnit()); // 锁定失败,抛出异常 if (!success) { log.info("[beforePointCut][方法({}) 参数({}) 存在重复请求]", joinPoint.getSignature().toString(), joinPoint.getArgs()); throw new ServiceException(GlobalErrorCodeConstants.REPEATED_REQUESTS.getCode(), idempotent.message()); } + + // 2. 执行逻辑 + try { + return joinPoint.proceed(); + } catch (Throwable throwable) { + // 3. 异常时,删除 Key + // 参考美团 GTIS 思路:https://tech.meituan.com/2016/09/29/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html + if (idempotent.deleteKeyWhenException()) { + idempotentRedisDAO.delete(key); + } + throw throwable; + } } } diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java index 56856993ba..7b5e145e4c 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/DefaultIdempotentKeyResolver.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResol import org.aspectj.lang.JoinPoint; /** - * 默认幂等 Key 解析器,使用方法名 + 方法参数,组装成一个 Key + * 默认(全局级别)幂等 Key 解析器,使用方法名 + 方法参数,组装成一个 Key * * 为了避免 Key 过长,使用 MD5 进行“压缩” * diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java new file mode 100644 index 0000000000..2fa91ff976 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/keyresolver/impl/UserIdempotentKeyResolver.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.aspectj.lang.JoinPoint; + +/** + * 用户级别的幂等 Key 解析器,使用方法名 + 方法参数 + userId + userType,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class UserIdempotentKeyResolver implements IdempotentKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, Idempotent idempotent) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + Long userId = WebFrameworkUtils.getLoginUserId(); + Integer userType = WebFrameworkUtils.getLoginUserType(); + return SecureUtil.md5(methodName + argsStr + userId + userType); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java index e3a79414d4..a8d981dec3 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java @@ -29,6 +29,11 @@ public class IdempotentRedisDAO { return redisTemplate.opsForValue().setIfAbsent(redisKey, "", timeout, timeUnit); } + public void delete(String key) { + String redisKey = formatKey(key); + redisTemplate.delete(redisKey); + } + private static String formatKey(String key) { return String.format(IDEMPOTENT, key); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.http index 6d9cea8010..7d7f6227e8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.http +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.http @@ -1,4 +1,5 @@ ### 请求 /system/user/page 接口 => 没有权限 GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10 Authorization: Bearer {{token}} +#Authorization: Bearer test100 tenant-id: {{adminTenentId}} From 2e03dcba6946b4039fcd2b5b54c5f45106734918 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 10 Apr 2024 20:57:44 +0800 Subject: [PATCH 68/86] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20resilience4j=20?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 12 ---------- .../pom.xml | 6 ----- .../framework/resilience4j/package-info.java | 9 ------- ... Spring Boot 服务容错 Resilience4j 入门》.md | 1 - .../core/handler/GlobalExceptionHandler.java | 24 ++++--------------- .../test/resources/application-unit-test.yaml | 2 -- .../test/resources/application-unit-test.yaml | 2 -- .../test/resources/application-unit-test.yaml | 2 -- .../test/resources/application-unit-test.yaml | 2 -- .../test/resources/application-unit-test.yaml | 2 -- .../test/resources/application-unit-test.yaml | 2 -- .../test/resources/application-unit-test.yaml | 2 -- .../application-integration-test.yaml | 10 -------- .../test/resources/application-unit-test.yaml | 2 -- .../test/resources/application-unit-test.yaml | 2 -- .../application-integration-test.yaml | 10 -------- .../test/resources/application-unit-test.yaml | 2 -- .../src/main/resources/application-dev.yaml | 10 -------- .../src/main/resources/application-local.yaml | 10 -------- 19 files changed, 5 insertions(+), 107 deletions(-) delete mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/package-info.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/《芋道 Spring Boot 服务容错 Resilience4j 入门》.md diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index f5a03a90bd..09067a2a4e 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -34,7 +34,6 @@ 2.2.3 2.2.7 - 2.1.0 9.0.0 3.2.1 @@ -282,17 +281,6 @@ - - io.github.resilience4j - resilience4j-ratelimiter - ${resilience4j.version} - - - io.github.resilience4j - resilience4j-spring-boot2 - ${resilience4j.version} - - cn.iocoder.boot diff --git a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml index 46fd97e438..a93991ff51 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml @@ -35,12 +35,6 @@ lock4j-redisson-spring-boot-starter true - - - io.github.resilience4j - resilience4j-spring-boot2 - true - diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/package-info.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/package-info.java deleted file mode 100644 index 649e8a0eaa..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/package-info.java +++ /dev/null @@ -1,9 +0,0 @@ -/** - * 使用 Resilience4j 组件,实现服务保障,包括: - * 1. 熔断器 - * 2. 限流器 - * 3. 舱壁隔离 - * 4. 重试 - * 5. 限时器 - */ -package cn.iocoder.yudao.framework.resilience4j; diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/《芋道 Spring Boot 服务容错 Resilience4j 入门》.md b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/《芋道 Spring Boot 服务容错 Resilience4j 入门》.md deleted file mode 100644 index 8d6d0335b1..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/《芋道 Spring Boot 服务容错 Resilience4j 入门》.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java index 243f949f28..7c60141953 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java @@ -11,6 +11,10 @@ import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.ValidationException; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -26,13 +30,8 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.servlet.NoHandlerFoundException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.ConstraintViolationException; -import jakarta.validation.ValidationException; import java.time.LocalDateTime; import java.util.Map; -import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*; @@ -181,14 +180,6 @@ public class GlobalExceptionHandler { return CommonResult.error(METHOD_NOT_ALLOWED.getCode(), String.format("请求方法不正确:%s", ex.getMessage())); } - /** - * 处理 Resilience4j 限流抛出的异常 - */ - public CommonResult requestNotPermittedExceptionHandler(HttpServletRequest req, Throwable ex) { - log.warn("[requestNotPermittedExceptionHandler][url({}) 访问过于频繁]", req.getRequestURL(), ex); - return CommonResult.error(TOO_MANY_REQUESTS); - } - /** * 处理 Spring Security 权限不足的异常 * @@ -223,12 +214,7 @@ public class GlobalExceptionHandler { return tableNotExistsResult; } - // 情况二:部分特殊的库的处理 - if (Objects.equals("io.github.resilience4j.ratelimiter.RequestNotPermitted", ex.getClass().getName())) { - return requestNotPermittedExceptionHandler(req, ex); - } - - // 情况三:处理异常 + // 情况二:处理异常 log.error("[defaultExceptionHandler]", ex); // 插入异常日志 this.createExceptionLog(req, ex); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml index 1bbe0f530c..dd9b95bfb9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/resources/application-unit-test.yaml @@ -32,8 +32,6 @@ mybatis-plus: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-crm/yudao-module-crm-biz/src/test/resources/application-unit-test.yaml b/yudao-module-crm/yudao-module-crm-biz/src/test/resources/application-unit-test.yaml index 0f28838da5..a55b301c69 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-crm/yudao-module-crm-biz/src/test/resources/application-unit-test.yaml @@ -39,8 +39,6 @@ mybatis-plus: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml index 2d0d827d29..d88a15a600 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/application-unit-test.yaml @@ -39,8 +39,6 @@ mybatis-plus: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/resources/application-unit-test.yaml b/yudao-module-mall/yudao-module-product-biz/src/test/resources/application-unit-test.yaml index 518fa712b9..36aec5c43d 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-mall/yudao-module-product-biz/src/test/resources/application-unit-test.yaml @@ -39,8 +39,6 @@ mybatis-plus: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/application-unit-test.yaml b/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/application-unit-test.yaml index 7b76570fd8..f05f050744 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/application-unit-test.yaml @@ -38,8 +38,6 @@ mybatis: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml index 0aa14e897a..4168a2bdad 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/resources/application-unit-test.yaml @@ -38,8 +38,6 @@ mybatis: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-member/yudao-module-member-biz/src/test/resources/application-unit-test.yaml b/yudao-module-member/yudao-module-member-biz/src/test/resources/application-unit-test.yaml index 7b76570fd8..f05f050744 100644 --- a/yudao-module-member/yudao-module-member-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-member/yudao-module-member-biz/src/test/resources/application-unit-test.yaml @@ -38,8 +38,6 @@ mybatis: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-pay/yudao-module-pay-biz/src/test-integration/resources/application-integration-test.yaml b/yudao-module-pay/yudao-module-pay-biz/src/test-integration/resources/application-integration-test.yaml index 0e55d5639a..5a030df7bb 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/test-integration/resources/application-integration-test.yaml +++ b/yudao-module-pay/yudao-module-pay-biz/src/test-integration/resources/application-integration-test.yaml @@ -71,16 +71,6 @@ mybatis-plus: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 -resilience4j: - ratelimiter: - instances: - backendA: - limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 - limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500 - timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s - register-health-indicator: true # 是否注册到健康监测 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-pay/yudao-module-pay-biz/src/test/resources/application-unit-test.yaml b/yudao-module-pay/yudao-module-pay-biz/src/test/resources/application-unit-test.yaml index 7b76570fd8..f05f050744 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-pay/yudao-module-pay-biz/src/test/resources/application-unit-test.yaml @@ -38,8 +38,6 @@ mybatis: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-report/yudao-module-report-biz/src/test/resources/application-unit-test.yaml b/yudao-module-report/yudao-module-report-biz/src/test/resources/application-unit-test.yaml index 6bfd9953d7..c0da26010c 100644 --- a/yudao-module-report/yudao-module-report-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-report/yudao-module-report-biz/src/test/resources/application-unit-test.yaml @@ -38,8 +38,6 @@ mybatis: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml b/yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml index 4a1880178f..9b025ac8ef 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml @@ -75,16 +75,6 @@ mybatis: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 -resilience4j: - ratelimiter: - instances: - backendA: - limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 - limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500 - timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s - register-health-indicator: true # 是否注册到健康监测 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/application-unit-test.yaml b/yudao-module-system/yudao-module-system-biz/src/test/resources/application-unit-test.yaml index 78d1d9c68b..58bbf921bd 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/application-unit-test.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/application-unit-test.yaml @@ -38,8 +38,6 @@ mybatis: # Lock4j 配置项(单元测试,禁用 Lock4j) -# Resilience4j 配置项 - --- #################### 监控相关配置 #################### --- #################### 芋道相关配置 #################### diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 8caf15b088..c10cdcb45b 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -115,16 +115,6 @@ lock4j: acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 -# Resilience4j 配置项 -resilience4j: - ratelimiter: - instances: - backendA: - limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 - limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500 - timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s - register-health-indicator: true # 是否注册到健康监测 - --- #################### 监控相关配置 #################### # Actuator 监控端点的配置项 diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 89a0378307..555030b576 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -135,16 +135,6 @@ lock4j: acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 -# Resilience4j 配置项 -resilience4j: - ratelimiter: - instances: - backendA: - limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 - limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500 - timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s - register-health-indicator: true # 是否注册到健康监测 - --- #################### 监控相关配置 #################### # Actuator 监控端点的配置项 From cc50891632d91a84c9eacf2a540af01fe94594c2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 11 Apr 2024 22:43:37 +0800 Subject: [PATCH 69/86] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91RateL?= =?UTF-8?q?imiter=20=E9=99=90=E6=B5=81=E5=99=A8=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E3=80=81=E7=94=A8=E6=88=B7=E3=80=81IP=20?= =?UTF-8?q?=E7=AD=89=E7=BA=A7=E5=88=AB=E7=9A=84=E9=99=90=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +- .../pom.xml | 2 +- .../idempotent/core/aop/IdempotentAspect.java | 4 +- .../config/YudaoRateLimiterConfiguration.java | 55 ++++++++++++++++ .../core/annotation/RateLimiter.java | 62 ++++++++++++++++++ .../core/aop/RateLimiterAspect.java | 60 +++++++++++++++++ .../keyresolver/RateLimiterKeyResolver.java | 22 +++++++ .../impl/ClientIpRateLimiterKeyResolver.java | 27 ++++++++ .../impl/DefaultRateLimiterKeyResolver.java | 25 ++++++++ .../ExpressionRateLimiterKeyResolver.java | 64 +++++++++++++++++++ .../ServerNodeRateLimiterKeyResolver.java | 27 ++++++++ .../impl/UserRateLimiterKeyResolver.java | 28 ++++++++ .../core/redis/RateLimiterRedisDAO.java | 60 +++++++++++++++++ .../framework/ratelimiter/package-info.java | 4 ++ ...ot.autoconfigure.AutoConfiguration.imports | 3 +- 15 files changed, 440 insertions(+), 8 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java diff --git a/README.md b/README.md index 4787c4d4f0..cf023ea79f 100644 --- a/README.md +++ b/README.md @@ -207,9 +207,7 @@ | 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 | | 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 | | 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 | -| 🚀 | 分布式锁 | 基于 Redis 实现分布式锁,满足并发场景 | -| 🚀 | 幂等组件 | 基于 Redis 实现幂等组件,解决重复请求问题 | -| 🚀 | 服务保障 | 基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 | +| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 | | 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 | | 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 | @@ -304,7 +302,6 @@ | [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 7.0.0 | [文档](https://doc.iocoder.cn/bpm/) | | [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) | | [Springdoc](https://springdoc.org/) | Swagger 文档 | 2.2.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | -| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 2.1.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) | | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 9.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | | [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 3.1.8 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | | [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.15.3 | | diff --git a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml index a93991ff51..bbb5b12ebe 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml @@ -20,7 +20,7 @@ cn.iocoder.boot yudao-spring-boot-starter-web - provided + provided diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java index 2d8c76d558..11ff765760 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java @@ -37,7 +37,7 @@ public class IdempotentAspect { } @Around(value = "@annotation(idempotent)") - public Object beforePointCut(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable { + public Object aroundPointCut(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable { // 获得 IdempotentKeyResolver IdempotentKeyResolver keyResolver = keyResolvers.get(idempotent.keyResolver()); Assert.notNull(keyResolver, "找不到对应的 IdempotentKeyResolver"); @@ -48,7 +48,7 @@ public class IdempotentAspect { boolean success = idempotentRedisDAO.setIfAbsent(key, idempotent.timeout(), idempotent.timeUnit()); // 锁定失败,抛出异常 if (!success) { - log.info("[beforePointCut][方法({}) 参数({}) 存在重复请求]", joinPoint.getSignature().toString(), joinPoint.getArgs()); + log.info("[aroundPointCut][方法({}) 参数({}) 存在重复请求]", joinPoint.getSignature().toString(), joinPoint.getArgs()); throw new ServiceException(GlobalErrorCodeConstants.REPEATED_REQUESTS.getCode(), idempotent.message()); } diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java new file mode 100644 index 0000000000..68b910feae --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/config/YudaoRateLimiterConfiguration.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.framework.ratelimiter.config; + +import cn.iocoder.yudao.framework.ratelimiter.core.aop.RateLimiterAspect; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.*; +import cn.iocoder.yudao.framework.ratelimiter.core.redis.RateLimiterRedisDAO; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import org.redisson.api.RedissonClient; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +@AutoConfiguration(after = YudaoRedisAutoConfiguration.class) +public class YudaoRateLimiterConfiguration { + + @Bean + public RateLimiterAspect rateLimiterAspect(List keyResolvers, RateLimiterRedisDAO rateLimiterRedisDAO) { + return new RateLimiterAspect(keyResolvers, rateLimiterRedisDAO); + } + + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public RateLimiterRedisDAO rateLimiterRedisDAO(RedissonClient redissonClient) { + return new RateLimiterRedisDAO(redissonClient); + } + + // ========== 各种 RateLimiterRedisDAO Bean ========== + + @Bean + public DefaultRateLimiterKeyResolver defaultRateLimiterKeyResolver() { + return new DefaultRateLimiterKeyResolver(); + } + + @Bean + public UserRateLimiterKeyResolver userRateLimiterKeyResolver() { + return new UserRateLimiterKeyResolver(); + } + + @Bean + public ClientIpRateLimiterKeyResolver clientIpRateLimiterKeyResolver() { + return new ClientIpRateLimiterKeyResolver(); + } + + @Bean + public ServerNodeRateLimiterKeyResolver serverNodeRateLimiterKeyResolver() { + return new ServerNodeRateLimiterKeyResolver(); + } + + @Bean + public ExpressionRateLimiterKeyResolver expressionRateLimiterKeyResolver() { + return new ExpressionRateLimiterKeyResolver(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java new file mode 100644 index 0000000000..417c4d642e --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/annotation/RateLimiter.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.annotation; + +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.ClientIpRateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.DefaultRateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.ServerNodeRateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl.UserRateLimiterKeyResolver; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; + +/** + * 限流注解 + * + * @author 芋道源码 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface RateLimiter { + + /** + * 限流的时间,默认为 1 秒 + */ + int time() default 1; + /** + * 时间单位,默认为 SECONDS 秒 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; + + /** + * 限流次数 + */ + int count() default 100; + + /** + * 提示信息,请求过快的提示 + * + * @see GlobalErrorCodeConstants#TOO_MANY_REQUESTS + */ + String message() default ""; // 为空时,使用 TOO_MANY_REQUESTS 错误提示 + + /** + * 使用的 Key 解析器 + * + * @see DefaultRateLimiterKeyResolver 全局级别 + * @see UserRateLimiterKeyResolver 用户 ID 级别 + * @see ClientIpRateLimiterKeyResolver 用户 IP 级别 + * @see ServerNodeRateLimiterKeyResolver 服务器 Node 级别 + * @see ExpressionIdempotentKeyResolver 自定义表达式,通过 {@link #keyArg()} 计算 + */ + Class keyResolver() default DefaultRateLimiterKeyResolver.class; + /** + * 使用的 Key 参数 + */ + String keyArg() default ""; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java new file mode 100644 index 0000000000..6ede62bea0 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/aop/RateLimiterAspect.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.aop; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.ratelimiter.core.redis.RateLimiterRedisDAO; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.util.Assert; + +import java.util.List; +import java.util.Map; + +/** + * 拦截声明了 {@link RateLimiter} 注解的方法,实现限流操作 + * + * @author 芋道源码 + */ +@Aspect +@Slf4j +public class RateLimiterAspect { + + /** + * RateLimiterKeyResolver 集合 + */ + private final Map, RateLimiterKeyResolver> keyResolvers; + + private final RateLimiterRedisDAO rateLimiterRedisDAO; + + public RateLimiterAspect(List keyResolvers, RateLimiterRedisDAO rateLimiterRedisDAO) { + this.keyResolvers = CollectionUtils.convertMap(keyResolvers, RateLimiterKeyResolver::getClass); + this.rateLimiterRedisDAO = rateLimiterRedisDAO; + } + + @Before("@annotation(rateLimiter)") + public void beforePointCut(JoinPoint joinPoint, RateLimiter rateLimiter) { + // 获得 IdempotentKeyResolver 对象 + RateLimiterKeyResolver keyResolver = keyResolvers.get(rateLimiter.keyResolver()); + Assert.notNull(keyResolver, "找不到对应的 RateLimiterKeyResolver"); + // 解析 Key + String key = keyResolver.resolver(joinPoint, rateLimiter); + + // 获取 1 次限流 + boolean success = rateLimiterRedisDAO.tryAcquire(key, + rateLimiter.count(), rateLimiter.time(), rateLimiter.timeUnit()); + if (!success) { + log.info("[beforePointCut][方法({}) 参数({}) 请求过于频繁]", joinPoint.getSignature().toString(), joinPoint.getArgs()); + String message = StrUtil.blankToDefault(rateLimiter.message(), + GlobalErrorCodeConstants.TOO_MANY_REQUESTS.getMsg()); + throw new ServiceException(GlobalErrorCodeConstants.TOO_MANY_REQUESTS.getCode(), message); + } + } + +} + diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java new file mode 100644 index 0000000000..44d7bdff50 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/RateLimiterKeyResolver.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver; + +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import org.aspectj.lang.JoinPoint; + +/** + * 限流 Key 解析器接口 + * + * @author 芋道源码 + */ +public interface RateLimiterKeyResolver { + + /** + * 解析一个 Key + * + * @param rateLimiter 限流注解 + * @param joinPoint AOP 切面 + * @return Key + */ + String resolver(JoinPoint joinPoint, RateLimiter rateLimiter); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java new file mode 100644 index 0000000000..8d6253caa7 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ClientIpRateLimiterKeyResolver.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; + +/** + * IP 级别的限流 Key 解析器,使用方法名 + 方法参数 + IP,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class ClientIpRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + String clientIp = ServletUtils.getClientIP(); + return SecureUtil.md5(methodName + argsStr + clientIp); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java new file mode 100644 index 0000000000..236ea45cb6 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/DefaultRateLimiterKeyResolver.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; + +/** + * 默认(全局级别)限流 Key 解析器,使用方法名 + 方法参数,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class DefaultRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + return SecureUtil.md5(methodName + argsStr); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java new file mode 100644 index 0000000000..118581e352 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ExpressionRateLimiterKeyResolver.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.lang.reflect.Method; + +/** + * 基于 Spring EL 表达式的 {@link RateLimiterKeyResolver} 实现类 + * + * @author 芋道源码 + */ +public class ExpressionRateLimiterKeyResolver implements RateLimiterKeyResolver { + + private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); + + private final ExpressionParser expressionParser = new SpelExpressionParser(); + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + // 获得被拦截方法参数名列表 + Method method = getMethod(joinPoint); + Object[] args = joinPoint.getArgs(); + String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method); + // 准备 Spring EL 表达式解析的上下文 + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + if (ArrayUtil.isNotEmpty(parameterNames)) { + for (int i = 0; i < parameterNames.length; i++) { + evaluationContext.setVariable(parameterNames[i], args[i]); + } + } + + // 解析参数 + Expression expression = expressionParser.parseExpression(rateLimiter.keyArg()); + return expression.getValue(evaluationContext, String.class); + } + + private static Method getMethod(JoinPoint point) { + // 处理,声明在类上的情况 + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + if (!method.getDeclaringClass().isInterface()) { + return method; + } + + // 处理,声明在接口上的情况 + try { + return point.getTarget().getClass().getDeclaredMethod( + point.getSignature().getName(), method.getParameterTypes()); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java new file mode 100644 index 0000000000..300a4d2f1e --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/ServerNodeRateLimiterKeyResolver.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.system.SystemUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import org.aspectj.lang.JoinPoint; + +/** + * Server 节点级别的限流 Key 解析器,使用方法名 + 方法参数 + IP,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class ServerNodeRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + String serverNode = String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID()); + return SecureUtil.md5(methodName + argsStr + serverNode); + } + +} \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java new file mode 100644 index 0000000000..a8d1c3a98c --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/keyresolver/impl/UserRateLimiterKeyResolver.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; +import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import org.aspectj.lang.JoinPoint; + +/** + * 用户级别的限流 Key 解析器,使用方法名 + 方法参数 + userId + userType,组装成一个 Key + * + * 为了避免 Key 过长,使用 MD5 进行“压缩” + * + * @author 芋道源码 + */ +public class UserRateLimiterKeyResolver implements RateLimiterKeyResolver { + + @Override + public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) { + String methodName = joinPoint.getSignature().toString(); + String argsStr = StrUtil.join(",", joinPoint.getArgs()); + Long userId = WebFrameworkUtils.getLoginUserId(); + Integer userType = WebFrameworkUtils.getLoginUserType(); + return SecureUtil.md5(methodName + argsStr + userId + userType); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java new file mode 100644 index 0000000000..fc1378f3bd --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/core/redis/RateLimiterRedisDAO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.framework.ratelimiter.core.redis; + +import lombok.AllArgsConstructor; +import org.redisson.api.*; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * 限流 Redis DAO + * + * @author 芋道源码 + */ +@AllArgsConstructor +public class RateLimiterRedisDAO { + + /** + * 限流操作 + * + * KEY 格式:rate_limiter:%s // 参数为 uuid + * VALUE 格式:String + * 过期时间:不固定 + */ + private static final String RATE_LIMITER = "rate_limiter:%s"; + + private final RedissonClient redissonClient; + + public Boolean tryAcquire(String key, int count, int time, TimeUnit timeUnit) { + // 1. 获得 RRateLimiter,并设置 rate 速率 + RRateLimiter rateLimiter = getRRateLimiter(key, count, time, timeUnit); + // 2. 尝试获取 1 个 + return rateLimiter.tryAcquire(); + } + + private static String formatKey(String key) { + return String.format(RATE_LIMITER, key); + } + + private RRateLimiter getRRateLimiter(String key, long count, int time, TimeUnit timeUnit) { + String redisKey = formatKey(key); + RRateLimiter rateLimiter = redissonClient.getRateLimiter(redisKey); + long rateInterval = timeUnit.toSeconds(time); + // 1. 如果不存在,设置 rate 速率 + RateLimiterConfig config = rateLimiter.getConfig(); + if (config == null) { + rateLimiter.trySetRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS); + return rateLimiter; + } + // 2. 如果存在,并且配置相同,则直接返回 + if (config.getRateType() == RateType.OVERALL + && Objects.equals(config.getRate(), count) + && Objects.equals(config.getRateInterval(), TimeUnit.SECONDS.toMillis(rateInterval))) { + return rateLimiter; + } + // 3. 如果存在,并且配置不同,则进行新建 + rateLimiter.setRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS); + return rateLimiter; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java new file mode 100644 index 0000000000..36a408c8e0 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/ratelimiter/package-info.java @@ -0,0 +1,4 @@ +/** + * 限流组件,基于 Redisson {@link org.redisson.api.RRateLimiter} 限流实现 + */ +package cn.iocoder.yudao.framework.ratelimiter; \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index be5c0990d4..d7cd3a8830 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,2 +1,3 @@ cn.iocoder.yudao.framework.idempotent.config.YudaoIdempotentConfiguration -cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration \ No newline at end of file +cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration +cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration \ No newline at end of file From 1e348dbf8381657388a470b6424b5521890a49d8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 11 Apr 2024 22:52:34 +0800 Subject: [PATCH 70/86] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91?= =?UTF-8?q?=E5=B0=86=E9=A1=B9=E7=9B=AE=E7=9A=84=20annotations=20=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E4=BF=AE=E6=94=B9=E6=88=90=20annotation=20=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apilog/core/{annotations => annotation}/ApiAccessLog.java | 2 +- .../yudao/framework/apilog/core/filter/ApiAccessLogFilter.java | 2 +- .../crm/controller/admin/business/CrmBusinessController.java | 2 +- .../module/crm/controller/admin/clue/CrmClueController.java | 2 +- .../crm/controller/admin/contact/CrmContactController.java | 2 +- .../crm/controller/admin/contract/CrmContractController.java | 2 +- .../crm/controller/admin/customer/CrmCustomerController.java | 2 +- .../crm/controller/admin/product/CrmProductController.java | 2 +- .../controller/admin/receivable/CrmReceivableController.java | 2 +- .../admin/receivable/CrmReceivablePlanController.java | 2 +- .../erp/controller/admin/finance/ErpAccountController.java | 2 +- .../controller/admin/finance/ErpFinancePaymentController.java | 2 +- .../controller/admin/finance/ErpFinanceReceiptController.java | 2 +- .../controller/admin/product/ErpProductCategoryController.java | 2 +- .../erp/controller/admin/product/ErpProductController.java | 2 +- .../erp/controller/admin/product/ErpProductUnitController.java | 2 +- .../erp/controller/admin/purchase/ErpPurchaseInController.java | 2 +- .../controller/admin/purchase/ErpPurchaseOrderController.java | 2 +- .../controller/admin/purchase/ErpPurchaseReturnController.java | 2 +- .../erp/controller/admin/purchase/ErpSupplierController.java | 2 +- .../module/erp/controller/admin/sale/ErpCustomerController.java | 2 +- .../erp/controller/admin/sale/ErpSaleOrderController.java | 2 +- .../module/erp/controller/admin/sale/ErpSaleOutController.java | 2 +- .../erp/controller/admin/sale/ErpSaleReturnController.java | 2 +- .../erp/controller/admin/stock/ErpStockCheckController.java | 2 +- .../module/erp/controller/admin/stock/ErpStockController.java | 2 +- .../module/erp/controller/admin/stock/ErpStockInController.java | 2 +- .../erp/controller/admin/stock/ErpStockMoveController.java | 2 +- .../erp/controller/admin/stock/ErpStockOutController.java | 2 +- .../erp/controller/admin/stock/ErpStockRecordController.java | 2 +- .../erp/controller/admin/stock/ErpWarehouseController.java | 2 +- .../module/infra/controller/admin/config/ConfigController.java | 2 +- .../controller/admin/demo/demo01/Demo01ContactController.java | 2 +- .../controller/admin/demo/demo02/Demo02CategoryController.java | 2 +- .../controller/admin/demo/demo03/Demo03StudentController.java | 2 +- .../yudao/module/infra/controller/admin/job/JobController.java | 2 +- .../module/infra/controller/admin/job/JobLogController.java | 2 +- .../infra/controller/admin/logger/ApiAccessLogController.java | 2 +- .../infra/controller/admin/logger/ApiErrorLogController.java | 2 +- .../yudao/module/infra/service/codegen/inner/CodegenEngine.java | 2 +- .../product/controller/admin/spu/ProductSpuController.java | 2 +- .../controller/admin/delivery/DeliveryExpressController.java | 2 +- .../module/pay/controller/admin/order/PayOrderController.java | 2 +- .../module/pay/controller/admin/refund/PayRefundController.java | 2 +- .../module/system/controller/admin/dept/PostController.java | 2 +- .../module/system/controller/admin/dict/DictDataController.java | 2 +- .../module/system/controller/admin/dict/DictTypeController.java | 2 +- .../system/controller/admin/errorcode/ErrorCodeController.java | 2 +- .../system/controller/admin/logger/LoginLogController.java | 2 +- .../system/controller/admin/logger/OperateLogController.java | 2 +- .../system/controller/admin/notify/NotifyMessageController.java | 2 +- .../system/controller/admin/permission/RoleController.java | 2 +- .../controller/admin/sensitiveword/SensitiveWordController.java | 2 +- .../module/system/controller/admin/sms/SmsLogController.java | 2 +- .../system/controller/admin/sms/SmsTemplateController.java | 2 +- .../module/system/controller/admin/tenant/TenantController.java | 2 +- .../module/system/controller/admin/user/UserController.java | 2 +- 57 files changed, 57 insertions(+), 57 deletions(-) rename yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/{annotations => annotation}/ApiAccessLog.java (96%) diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotations/ApiAccessLog.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java similarity index 96% rename from yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotations/ApiAccessLog.java rename to yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java index 096c3bef23..fe93ef6014 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotations/ApiAccessLog.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/annotation/ApiAccessLog.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.framework.apilog.core.annotations; +package cn.iocoder.yudao.framework.apilog.core.annotation; import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java index 654db7a6ed..b092683384 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/filter/ApiAccessLogFilter.java @@ -7,7 +7,7 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java index 62aacf5064..a2bbd06362 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.business; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java index f060e07d9c..992549b315 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.clue; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java index 8d23f5635a..58ea20d493 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java index 94b90607a4..b9fd295183 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.contract; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index e9d5c63a2b..a4cc996e73 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java index c91e67ff85..bf98a80606 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.product; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java index d53cfcf4d0..58e02d187b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java index dfb4114af4..0e879ae38c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpAccountController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpAccountController.java index 273d40dd6c..5c68ed9504 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpAccountController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpAccountController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.finance; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinancePaymentController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinancePaymentController.java index 29b71e5dbb..09e2469160 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinancePaymentController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinancePaymentController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.finance; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java index e374b3c29a..0d71e6f859 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/finance/ErpFinanceReceiptController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.finance; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java index d56b9d8909..d7bc7a7958 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java index 40ed30a208..04f9068df7 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java index c1f9d1acd0..3be6dd9739 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java index 754c3548fe..3a63540f48 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java index a60fda222e..47569b97c3 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseReturnController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseReturnController.java index 4afb083ea2..2847e2b870 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseReturnController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseReturnController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java index 3337b38013..7212507635 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpSupplierController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java index 88d050ac67..2eb974df63 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpCustomerController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java index acb49e7634..b0ec991718 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java index 02c5561481..f67398b16c 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleReturnController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleReturnController.java index 2a3a83411b..77e6106afd 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleReturnController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleReturnController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java index 5eda9617d2..2c35cb8ed2 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java index f439272fa4..981cb92f78 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java index 6f9e8b3143..49f640f697 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockInController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java index df0ffc81d9..d2b343fb82 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java index 10e7d47ab4..2ab548b052 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockOutController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java index e1b0b36f6a..943df16b12 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockRecordController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java index 46901a2af3..6adc383db4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java index edcb222548..e0f9a81e91 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/config/ConfigController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.config; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java index 2cbf98ffe5..cf6935e505 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java index 62228f5c2c..5cdc332219 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java index 624de732f4..bee5984751 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.java index ed9f75df02..1881db53aa 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.job; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobLogController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobLogController.java index f1a230eea1..71b098b948 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobLogController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/job/JobLogController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.job; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java index d170933df6..b4ee86c0d8 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiAccessLogController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.logger; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java index a5b7a455bd..25eb2e99c2 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/logger/ApiErrorLogController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.logger; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java index 650df057a5..e4b7e18c84 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java @@ -8,7 +8,7 @@ import cn.hutool.extra.template.TemplateConfig; import cn.hutool.extra.template.TemplateEngine; import cn.hutool.extra.template.engine.velocity.VelocityEngine; import cn.hutool.system.SystemUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java index 31d36ba6d6..076170138e 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.product.controller.admin.spu; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java index 5484075c21..dedfe2d318 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.trade.controller.admin.delivery; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java index 68cdf2e01a..a5322c9eb2 100755 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.order; import cn.hutool.core.collection.CollectionUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java index 81255443a0..a476ff9b5d 100755 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/refund/PayRefundController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.pay.controller.admin.refund; import cn.hutool.core.collection.CollectionUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java index cf44cd5eff..897cea267c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.dept; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java index 59b03f0067..c05de995e8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.dict; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictTypeController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictTypeController.java index 8873ca4d88..c40980cfc5 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictTypeController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictTypeController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.dict; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java index 9a28f8d720..a0d14c5570 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.errorcode; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/LoginLogController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/LoginLogController.java index 1903ab6e58..f2ff3a4f0f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/LoginLogController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/LoginLogController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.logger; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java index a7036c8f6c..57b9b619bd 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/logger/OperateLogController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.logger; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java index 1909046779..752ad28e8c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyMessageController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.notify; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java index ee6ae9fbb8..cf22687529 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.permission; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java index 16b49f2990..15da9d9529 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.sensitiveword; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsLogController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsLogController.java index 1e468f6e0a..4646e785e8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsLogController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsLogController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.sms; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java index 481b6b0335..80c6082265 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.sms; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.*; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java index 51aab02d6d..090c6a80ff 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.system.controller.admin.tenant; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java index 8f1a376f84..51ec808575 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.system.controller.admin.user; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.apilog.core.annotations.ApiAccessLog; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; From 48aef10d2dc2663587373779a633320001fb902c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8A=8B=E9=81=93=E6=BA=90=E7=A0=81?= Date: Fri, 12 Apr 2024 11:13:11 +0000 Subject: [PATCH 71/86] =?UTF-8?q?=E5=9B=9E=E9=80=80=20'Pull=20Request=20!9?= =?UTF-8?q?37=20:=20feat:=20=E5=AE=A2=E6=88=B7=E6=88=90=E4=BA=A4=E5=91=A8?= =?UTF-8?q?=E6=9C=9F=E5=88=86=E6=9E=90(=E6=8C=89=E5=8C=BA=E5=9F=9F?= =?UTF-8?q?=E3=80=81=E6=8C=89=E4=BA=A7=E5=93=81)'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/ErrorCodeConstants.java | 4 - .../definition/BpmSimpleModelNodeType.java | 47 ---- .../definition/BpmSimpleModelController.java | 39 ---- .../vo/simple/BpmSimpleModelNodeVO.java | 40 ---- .../vo/simple/BpmSimpleModelSaveReqVO.java | 23 -- .../core/enums/BpmnModelConstants.java | 16 -- .../flowable/core/util/BpmnModelUtils.java | 208 +----------------- .../service/definition/BpmModelService.java | 24 -- .../definition/BpmModelServiceImpl.java | 25 +-- .../definition/BpmSimpleModelService.java | 29 --- .../definition/BpmSimpleModelServiceImpl.java | 170 -------------- .../task/BpmProcessInstanceCopyService.java | 6 +- .../BpmProcessInstanceCopyServiceImpl.java | 18 +- .../service/task/BpmSimpleNodeService.java | 34 --- .../bpm/service/task/BpmTaskServiceImpl.java | 3 +- .../CrmStatisticsCustomerController.http | 10 - .../CrmStatisticsCustomerController.java | 14 +- ...atisticsCustomerDealCycleByAreaRespVO.java | 24 -- ...sticsCustomerDealCycleByProductRespVO.java | 19 -- .../CrmStatisticsCustomerMapper.java | 17 -- .../CrmStatisticsCustomerService.java | 18 +- .../CrmStatisticsCustomerServiceImpl.java | 49 ----- .../CrmStatisticsCustomerMapper.xml | 52 +---- 23 files changed, 27 insertions(+), 862 deletions(-) delete mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByAreaRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByProductRespVO.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index e344a2145e..ec167719cc 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -75,8 +75,4 @@ public interface ErrorCodeConstants { // ========== BPM 流程表达式 1-009-014-000 ========== ErrorCode PROCESS_EXPRESSION_NOT_EXISTS = new ErrorCode(1_009_014_000, "流程表达式不存在"); - // ========== BPM 仿钉钉流程设计器 1-009-015-000 ========== - // TODO @芋艿:这个错误码,需要关注下 - ErrorCode CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT = new ErrorCode(1_009_015_000, "该流程模型不支持仿钉钉设计流程"); - } diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java deleted file mode 100644 index 4e26d02d9f..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.yudao.module.bpm.enums.definition; - -import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; -import java.util.Objects; - -/** - * 仿钉钉的流程器设计器的模型节点类型 - * - * @author jason - */ -@Getter -@AllArgsConstructor -public enum BpmSimpleModelNodeType implements IntArrayValuable { - - // TODO @jaosn:-1、0、1、4、-2 是前端已经定义好的么?感觉未来可以考虑搞成和 BPMN 尽量一致的单词哈;类似 usertask 用户审批; - START_EVENT_NODE(0, "开始节点"), - APPROVE_USER_NODE (1, "审批人节点"), - // 抄送人节点、对应 BPMN 的 ScriptTask. 使用ScriptTask 原因。好像 ServiceTask 自定义属性不能写入 XML - SCRIPT_TASK_NODE(2, "抄送人节点"), - EXCLUSIVE_GATEWAY_NODE(4, "排他网关"), - END_EVENT_NODE(-2, "结束节点"); - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); - - private final Integer type; - private final String name; - - public static boolean isGatewayNode(Integer type) { - // TODO 后续增加并行网关的支持 - return Objects.equals(EXCLUSIVE_GATEWAY_NODE.getType(), type); - } - - public static BpmSimpleModelNodeType valueOf(Integer type) { - return ArrayUtil.firstMatch(nodeType -> nodeType.getType().equals(type), values()); - } - - @Override - public int[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java deleted file mode 100644 index 2f88c6b6d5..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmSimpleModelController.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; -import cn.iocoder.yudao.module.bpm.service.definition.BpmSimpleModelService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -// TODO @芋艿:后续考虑下,怎么放这个 Controller -@Tag(name = "管理后台 - BPM 仿钉钉流程设计器") -@RestController -@RequestMapping("/bpm/simple") -public class BpmSimpleModelController { - @Resource - private BpmSimpleModelService bpmSimpleModelService; - - @PostMapping("/save") - @Operation(summary = "保存仿钉钉流程设计模型") - @PreAuthorize("@ss.hasPermission('bpm:model:update')") - public CommonResult saveSimpleModel(@Valid @RequestBody BpmSimpleModelSaveReqVO reqVO) { - return success(bpmSimpleModelService.saveSimpleModel(reqVO)); - } - - @GetMapping("/get") - @Operation(summary = "获得仿钉钉流程设计模型") - @Parameter(name = "modelId", description = "流程模型编号", required = true, example = "a2c5eee0-eb6c-11ee-abf4-0c37967c420a") - public CommonResult getSimpleModel(@RequestParam("modelId") String modelId){ - return success(bpmSimpleModelService.getSimpleModel(modelId)); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java deleted file mode 100644 index 09db4764c4..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelNodeVO.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; -import com.fasterxml.jackson.annotation.JsonInclude; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.util.List; -import java.util.Map; - -@Schema(description = "管理后台 - 仿钉钉流程设计模型节点 VO") -@Data -@JsonInclude(JsonInclude.Include.NON_NULL) -public class BpmSimpleModelNodeVO { - - @Schema(description = "模型节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartEvent_1") - @NotEmpty(message = "模型节点编号不能为空") - private String id; - - @Schema(description = "模型节点类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "模型节点类型不能为空") - @InEnum(BpmSimpleModelNodeType.class) - private Integer type; - - @Schema(description = "模型节点名称", example = "领导审批") - private String name; - - @Schema(description = "孩子节点") - private BpmSimpleModelNodeVO childNode; - - @Schema(description = "网关节点的条件节点") - private List conditionNodes; - - @Schema(description = "节点的属性") - private Map attributes; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java deleted file mode 100644 index 54e0191d56..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/simple/BpmSimpleModelSaveReqVO.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -// TODO @芋艿:或许挪到 model 里的 simple 包 -@Schema(description = "管理后台 - 仿钉钉流程设计模型的新增/修改 Request VO") -@Data -public class BpmSimpleModelSaveReqVO { - - @Schema(description = "流程模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotEmpty(message = "流程模型编号不能为空") - private String modelId; // 对应 Flowable act_re_model 表 ID_ 字段 - - @Schema(description = "仿钉钉流程设计模型对象", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "仿钉钉流程设计模型对象不能为空") - @Valid - private BpmSimpleModelNodeVO simpleModelBody; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java index 7513a64c88..3eb6981ef9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java @@ -1,10 +1,5 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; -import com.google.common.collect.ImmutableSet; -import org.flowable.bpmn.model.*; - -import java.util.Set; - /** * BPMN XML 常量信息 * @@ -28,15 +23,4 @@ public interface BpmnModelConstants { */ String USER_TASK_CANDIDATE_PARAM = "candidateParam"; - // TODO @芋艿:这里后面得关注下; - /** - * BPMN End Event 节点 Id, 用于后端生成 End Event 节点 - */ - String END_EVENT_ID = "EndEvent_1"; - - /** - * 支持转仿钉钉设计模型的 Bpmn 节点 - */ - Set> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class); - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 03745adceb..bcf82d731c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -1,35 +1,21 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; -import org.flowable.bpmn.BpmnAutoLayout; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; -import org.flowable.common.engine.impl.scripting.ScriptingEngines; import org.flowable.common.engine.impl.util.io.BytesStreamSource; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.flowable.bpmn.constants.BpmnXMLConstants.*; +import java.util.*; /** * 流程模型转操作工具类 */ public class BpmnModelUtils { - public static final String BPMN_SIMPLE_COPY_EXECUTION_SCRIPT = "#{bpmSimpleNodeService.copy(execution)}"; - public static Integer parseCandidateStrategy(FlowElement userTask) { return NumberUtils.parseInt(userTask.getAttributeValue( BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); @@ -340,196 +326,4 @@ public class BpmnModelUtils { return userTaskList; } - // ========== TODO 芋艿:这里得捉摸下; ========== - - /** - * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善) - * - * @param processId 流程标识 - * @param processName 流程名称 - * @param simpleModelNode 仿钉钉流程设计模型数据结构 - * @return Bpmn Model - */ - public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { - BpmnModel bpmnModel = new BpmnModel(); - Process mainProcess = new Process(); - mainProcess.setId(processId); - mainProcess.setName(processName); - mainProcess.setExecutable(Boolean.TRUE); - bpmnModel.addProcess(mainProcess); - // 前端模型数据结构。 有 start event 节点. 没有 end event 节点。 - // 添加 FlowNode - addBpmnFlowNode(mainProcess, simpleModelNode); - // 单独添加 end event 节点 - addBpmnEndEventNode(mainProcess); - // 添加节点之间的连线 Sequence Flow - addBpmnSequenceFlow(mainProcess, simpleModelNode, BpmnModelConstants.END_EVENT_ID); - // 自动布局 - new BpmnAutoLayout(bpmnModel).execute(); - return bpmnModel; - } - - private static void addBpmnSequenceFlow(Process mainProcess, BpmSimpleModelNodeVO node, String endId) { - // 节点为 null 退出 - if (node == null || node.getId() == null) { - return; - } - BpmSimpleModelNodeVO childNode = node.getChildNode(); - // 如果不是网关节点、且后续节点为 null. 添加与结束节点的连线 - if (!BpmSimpleModelNodeType.isGatewayNode(node.getType()) && (childNode == null || childNode.getId() == null)) { - addBpmnSequenceFlowElement(mainProcess, node.getId(), endId, null, null); - return; - } - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); - Assert.notNull(nodeType, "模型节点类型不支持"); - switch (nodeType) { - case START_EVENT_NODE: - case APPROVE_USER_NODE: - case SCRIPT_TASK_NODE: { - addBpmnSequenceFlowElement(mainProcess, node.getId(), childNode.getId(), null, null); - // 递归调用后续节点 - addBpmnSequenceFlow(mainProcess, childNode, endId); - break; - } - case EXCLUSIVE_GATEWAY_NODE: { - String gateWayEndId = (childNode == null || childNode.getId() == null) ? BpmnModelConstants.END_EVENT_ID : childNode.getId(); - List conditionNodes = node.getConditionNodes(); - Assert.notEmpty(conditionNodes, "网关节点的条件节点不能为空"); - for (int i = 0; i < conditionNodes.size(); i++) { - BpmSimpleModelNodeVO item = conditionNodes.get(i); - BpmSimpleModelNodeVO nextNodeOnCondition = item.getChildNode(); - if (nextNodeOnCondition != null && nextNodeOnCondition.getId() != null) { - addBpmnSequenceFlowElement(mainProcess, node.getId(), nextNodeOnCondition.getId(), - String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); - addBpmnSequenceFlow(mainProcess, nextNodeOnCondition, gateWayEndId); - } else { - addBpmnSequenceFlowElement(mainProcess, node.getId(), gateWayEndId, - String.format("%s_SequenceFlow_%d", node.getId(), i + 1), null); - } - } - // 递归调用后续节点 - addBpmnSequenceFlow(mainProcess, childNode, endId); - break; - } - default: { - // TODO 其它节点类型的实现 - } - } - - } - - private static void addBpmnSequenceFlowElement(Process mainProcess, String sourceId, String targetId, String seqFlowId, String conditionExpression) { - SequenceFlow sequenceFlow = new SequenceFlow(sourceId, targetId); - if (StrUtil.isNotEmpty(conditionExpression)) { - sequenceFlow.setConditionExpression(conditionExpression); - } - if (StrUtil.isNotEmpty(seqFlowId)) { - sequenceFlow.setId(seqFlowId); - } - mainProcess.addFlowElement(sequenceFlow); - } - - private static void addBpmnFlowNode(Process mainProcess, BpmSimpleModelNodeVO simpleModelNode) { - // 节点为 null 退出 - if (simpleModelNode == null || simpleModelNode.getId() == null) { - return; - } - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); - Assert.notNull(nodeType, "模型节点类型不支持"); - switch (nodeType) { - case START_EVENT_NODE: - addBpmnStartEventNode(mainProcess, simpleModelNode); - break; - case APPROVE_USER_NODE: - addBpmnUserTaskNode(mainProcess, simpleModelNode); - break; - case SCRIPT_TASK_NODE: - addBpmnScriptTaSskNode(mainProcess, simpleModelNode); - break; - case EXCLUSIVE_GATEWAY_NODE: - addBpmnExclusiveGatewayNode(mainProcess, simpleModelNode); - break; - default: { - // TODO 其它节点类型的实现 - } - } - - // 如果不是网关类型的接口, 并且chileNode为空退出 - if (!BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) { - return; - } - - // 如果是网关类型接口. 递归添加条件节点 - if (BpmSimpleModelNodeType.isGatewayNode(simpleModelNode.getType()) && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) { - for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) { - addBpmnFlowNode(mainProcess, node.getChildNode()); - } - } - - // chileNode不为空,递归添加子节点 - if (simpleModelNode.getChildNode() != null) { - addBpmnFlowNode(mainProcess, simpleModelNode.getChildNode()); - } - } - - private static void addBpmnScriptTaSskNode(Process mainProcess, BpmSimpleModelNodeVO node) { - ScriptTask scriptTask = new ScriptTask(); - scriptTask.setId(node.getId()); - scriptTask.setName(node.getName()); - scriptTask.setScriptFormat(ScriptingEngines.DEFAULT_SCRIPTING_LANGUAGE); - scriptTask.setScript(BPMN_SIMPLE_COPY_EXECUTION_SCRIPT); - // 添加自定义属性 - addExtensionAttributes(node, scriptTask); - mainProcess.addFlowElement(scriptTask); - } - - private static void addExtensionAttributes(BpmSimpleModelNodeVO node, FlowElement flowElement) { - Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); - addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY, - candidateStrategy == null ? null : String.valueOf(candidateStrategy)); - addExtensionAttributes(flowElement, BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, - MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM)); - } - - private static void addBpmnExclusiveGatewayNode(Process mainProcess, BpmSimpleModelNodeVO node) { - Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); - ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); - exclusiveGateway.setId(node.getId()); - // 条件节点的最后一个条件为 网关的 default sequence flow - exclusiveGateway.setDefaultFlow(String.format("%s_SequenceFlow_%d", node.getId(), node.getConditionNodes().size())); - mainProcess.addFlowElement(exclusiveGateway); - } - - private static void addBpmnEndEventNode(Process mainProcess) { - EndEvent endEvent = new EndEvent(); - endEvent.setId(BpmnModelConstants.END_EVENT_ID); - endEvent.setName("结束"); - mainProcess.addFlowElement(endEvent); - } - - private static void addBpmnUserTaskNode(Process mainProcess, BpmSimpleModelNodeVO node) { - UserTask userTask = new UserTask(); - userTask.setId(node.getId()); - userTask.setName(node.getName()); - addExtensionAttributes(node, userTask); - mainProcess.addFlowElement(userTask); - } - - private static void addExtensionAttributes(FlowElement element, String namespace, String name, String value) { - if (value == null) { - return; - } - ExtensionAttribute extensionAttribute = new ExtensionAttribute(name, value); - extensionAttribute.setNamespace(namespace); - extensionAttribute.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX); - element.addAttribute(extensionAttribute); - } - - private static void addBpmnStartEventNode(Process mainProcess, BpmSimpleModelNodeVO node) { - StartEvent startEvent = new StartEvent(); - startEvent.setId(node.getId()); - startEvent.setName(node.getName()); - mainProcess.addFlowElement(startEvent); - } - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java index c5f1c962c1..e1acce0649 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java @@ -46,30 +46,6 @@ public interface BpmModelService { */ byte[] getModelBpmnXML(String id); - - /** - * 保存流程模型的 BPMN XML - * - * @param id 编号 - * @param xmlBytes BPMN XML bytes - */ - // TODO @芋艿:可能要关注下; - void saveModelBpmnXml(String id, byte[] xmlBytes); - - /** - * 获得仿钉钉快搭模型的 JSON 数据 - * @param id 编号 - * @return JSON bytes - */ - byte[] getModelSimpleJson(String id); - - /** - * 保存仿钉钉快搭模型的 JSON 数据 - * @param id 编号 - * @param jsonBytes JSON bytes - */ - void saveModelSimpleJson(String id, byte[] jsonBytes); - /** * 修改流程模型 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 9a12b7acdf..abfa0d568d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.bpm.service.definition; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -104,7 +103,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 保存流程定义 repositoryService.saveModel(model); // 保存 BPMN XML - saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(bpmnXml)); + saveModelBpmnXml(model, bpmnXml); return model.getId(); } @@ -122,7 +121,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 更新模型 repositoryService.saveModel(model); // 更新 BPMN XML - saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(updateReqVO.getBpmnXml())); + saveModelBpmnXml(model, updateReqVO.getBpmnXml()); } @Override @@ -237,25 +236,11 @@ public class BpmModelServiceImpl implements BpmModelService { } } - @Override - public void saveModelBpmnXml(String id, byte[] xmlBytes) { - if (ArrayUtil.isEmpty(xmlBytes)) { + private void saveModelBpmnXml(Model model, String bpmnXml) { + if (StrUtil.isEmpty(bpmnXml)) { return; } - repositoryService.addModelEditorSource(id, xmlBytes); - } - - @Override - public byte[] getModelSimpleJson(String id) { - return repositoryService.getModelEditorSourceExtra(id); - } - - @Override - public void saveModelSimpleJson(String id, byte[] jsonBytes) { - if (ArrayUtil.isEmpty(jsonBytes)) { - return; - } - repositoryService.addModelEditorSourceExtra(id, jsonBytes); + repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml)); } /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java deleted file mode 100644 index e06dff7c66..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelService.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.definition; - -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; -import jakarta.validation.Valid; - -/** - * 仿钉钉流程设计 Service 接口 - * - * @author jason - */ -public interface BpmSimpleModelService { - - /** - * 保存仿钉钉流程设计模型 - * - * @param reqVO 请求信息 - */ - Boolean saveSimpleModel(@Valid BpmSimpleModelSaveReqVO reqVO); - - /** - * 获取仿钉钉流程设计模型结构 - * - * @param modelId 流程模型编号 - * @return 仿钉钉流程设计模型结构 - */ - BpmSimpleModelNodeVO getSimpleModel(String modelId); - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java deleted file mode 100644 index cbdabbf7a1..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmSimpleModelServiceImpl.java +++ /dev/null @@ -1,170 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.definition; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; -import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; -import jakarta.annotation.Resource; -import org.flowable.bpmn.model.*; -import org.flowable.engine.repository.Model; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT_NODE; -import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM; -import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY; - -/** - * 仿钉钉流程设计 Service 实现类 - * - * @author jason - */ -@Service -@Validated -public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { - - @Resource - private BpmModelService bpmModelService; - - @Override - public Boolean saveSimpleModel(BpmSimpleModelSaveReqVO reqVO) { - Model model = bpmModelService.getModel(reqVO.getModelId()); - if (model == null) { - throw exception(MODEL_NOT_EXISTS); - } -// byte[] bpmnBytes = bpmModelService.getModelBpmnXML(reqVO.getModelId()); -// if (ArrayUtil.isEmpty(bpmnBytes)) { -// // BPMN XML 不存在。新增 -// BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); -// bpmModelService.saveModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel)); -// return Boolean.TRUE; -// } else { -// // TODO BPMN XML 已经存在。如何修改 ?? TODO add by 芋艿:感觉一个流程,只能二选一,要么 bpmn、要么 simple -// return Boolean.FALSE; -// } - // 1. JSON 转换成 bpmnModel - BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); - // 2.1 保存 Bpmn XML - bpmModelService.saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel))); - // 2.2 保存 JSON 数据 - bpmModelService.saveModelSimpleJson(model.getId(), JsonUtils.toJsonByte(reqVO.getSimpleModelBody())); - return Boolean.TRUE; - } - - @Override - public BpmSimpleModelNodeVO getSimpleModel(String modelId) { - Model model = bpmModelService.getModel(modelId); - if (model == null) { - throw exception(MODEL_NOT_EXISTS); - } - // 暂时不用 bpmn 转 json, 有点复杂, - // 通过 ACT_RE_MODEL 表 EDITOR_SOURCE_EXTRA_VALUE_ID_ 获取 仿钉钉快搭模型的JSON 数据 - byte[] jsonBytes = bpmModelService.getModelSimpleJson(model.getId()); - return JsonUtils.parseObject(jsonBytes, BpmSimpleModelNodeVO.class); - } - - // TODO @jason:一般要支持这个么?感觉 bpmn 转 json 支持会不会太复杂。可以优先级低一点,做下调研~ - - /** - * Bpmn Model 转换成 仿钉钉流程设计模型数据结构(json) 待完善 - * - * @param bpmnModel Bpmn Model - * @return 仿钉钉流程设计模型数据结构 - */ - private BpmSimpleModelNodeVO convertBpmnModelToSimpleModel(BpmnModel bpmnModel) { - if (bpmnModel == null) { - return null; - } - StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel); - if (startEvent == null) { - return null; - } - BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO(); - rootNode.setType(START_EVENT_NODE.getType()); - rootNode.setId(startEvent.getId()); - rootNode.setName(startEvent.getName()); - recursiveBuildSimpleModelNode(startEvent, rootNode); - return rootNode; - } - - private void recursiveBuildSimpleModelNode(FlowNode currentFlowNode, BpmSimpleModelNodeVO currentSimpleModeNode) { - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(currentSimpleModeNode.getType()); - Assert.notNull(nodeType, "节点类型不支持"); - // 校验节点是否支持转仿钉钉的流程模型 - List outgoingFlows = validateCanConvertSimpleNode(nodeType, currentFlowNode); - if (CollUtil.isEmpty(outgoingFlows) || outgoingFlows.get(0).getTargetFlowElement() == null) { - return; - } - FlowElement targetElement = outgoingFlows.get(0).getTargetFlowElement(); - // 如果是 EndEvent 直接退出 - if (targetElement instanceof EndEvent) { - return; - } - if (targetElement instanceof UserTask) { - BpmSimpleModelNodeVO childNode = convertUserTaskToSimpleModelNode((UserTask) targetElement); - currentSimpleModeNode.setChildNode(childNode); - recursiveBuildSimpleModelNode((FlowNode) targetElement, childNode); - } - // TODO 其它节点类型待实现 - } - - private BpmSimpleModelNodeVO convertUserTaskToSimpleModelNode(UserTask userTask) { - BpmSimpleModelNodeVO simpleModelNodeVO = new BpmSimpleModelNodeVO(); - simpleModelNodeVO.setType(BpmSimpleModelNodeType.APPROVE_USER_NODE.getType()); - simpleModelNodeVO.setName(userTask.getName()); - simpleModelNodeVO.setId(userTask.getId()); - Map attributes = MapUtil.newHashMap(); - // TODO 暂时是普通审批,需要加会签 - attributes.put("approveMethod", 1); - attributes.computeIfAbsent(USER_TASK_CANDIDATE_STRATEGY, (key) -> BpmnModelUtils.parseCandidateStrategy(userTask)); - attributes.computeIfAbsent(USER_TASK_CANDIDATE_PARAM, (key) -> BpmnModelUtils.parseCandidateParam(userTask)); - simpleModelNodeVO.setAttributes(attributes); - return simpleModelNodeVO; - } - - private List validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) { - switch (nodeType) { - case START_EVENT_NODE: - case APPROVE_USER_NODE: { - List outgoingFlows = currentFlowNode.getOutgoingFlows(); - if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) { - throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); - } - validIsSupportFlowNode(outgoingFlows.get(0).getTargetFlowElement()); - return outgoingFlows; - } - default: { - // TODO 其它节点类型待实现 - throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); - } - } - } - - private void validIsSupportFlowNode(FlowElement targetElement) { - if (targetElement == null) { - return; - } - boolean isSupport = false; - for (Class item : BpmnModelConstants.SUPPORT_CONVERT_SIMPLE_FlOW_NODES) { - if (item.isInstance(targetElement)) { - isSupport = true; - break; - } - } - if (!isSupport) { - throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); - } - } -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java index 94df76d4d8..bd84490e8e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java @@ -17,11 +17,9 @@ public interface BpmProcessInstanceCopyService { * 流程实例的抄送 * * @param userIds 抄送的用户编号 - * @param processInstanceId 流程编号 - * @param taskId 任务编号 - * @param taskName 任务名称 + * @param taskId 流程任务编号 */ - void createProcessInstanceCopy(Collection userIds, String processInstanceId, String taskId, String taskName); + void createProcessInstanceCopy(Collection userIds, String taskId); /** * 获得抄送的流程的分页 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java index ce1ddd7fd2..aba8bd9f17 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.service.task; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; @@ -10,6 +11,7 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -45,14 +47,14 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy private BpmProcessDefinitionService processDefinitionService; @Override - public void createProcessInstanceCopy(Collection userIds, String processInstanceId, String taskId, String taskName) { - // 1.1 校验任务存在 暂时去掉这个校验. 因为任务可能仿钉钉快搭的抄送节点(ScriptTask) -// Task task = taskService.getTask(taskId); -// if (ObjectUtil.isNull(task)) { -// throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); -// } + public void createProcessInstanceCopy(Collection userIds, String taskId) { + // 1.1 校验任务存在 + Task task = taskService.getTask(taskId); + if (ObjectUtil.isNull(task)) { + throw exception(ErrorCodeConstants.TASK_NOT_EXISTS); + } // 1.2 校验流程实例存在 -// String processInstanceId = task.getProcessInstanceId(); + String processInstanceId = task.getProcessInstanceId(); ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId); if (processInstance == null) { throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS); @@ -68,7 +70,7 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy List copyList = convertList(userIds, userId -> new BpmProcessInstanceCopyDO() .setUserId(userId).setStartUserId(Long.valueOf(processInstance.getStartUserId())) .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName()) - .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(taskName)); + .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(task.getName())); processInstanceCopyMapper.insertBatch(copyList); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java deleted file mode 100644 index 89ba0ee84c..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmSimpleNodeService.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.task; - -import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; -import jakarta.annotation.Resource; -import org.flowable.bpmn.model.FlowElement; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.stereotype.Service; - -import java.util.Set; - -/** - * 仿钉钉快搭各个节点 Service - * @author jason - */ -@Service -public class BpmSimpleNodeService { - - @Resource - private BpmTaskCandidateInvoker taskCandidateInvoker; - @Resource - private BpmProcessInstanceCopyService processInstanceCopyService; - - /** - * 仿钉钉快搭抄送 - * @param execution 执行的任务(ScriptTask) - */ - public Boolean copy(DelegateExecution execution) { - Set userIds = taskCandidateInvoker.calculateUsers(execution); - FlowElement currentFlowElement = execution.getCurrentFlowElement(); - processInstanceCopyService.createProcessInstanceCopy(userIds, execution.getProcessInstanceId(), - currentFlowElement.getId(), currentFlowElement.getName()); - return Boolean.TRUE; - } -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index c18ea5398f..aa5326ddd4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -186,8 +186,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2. 抄送用户 if (CollUtil.isNotEmpty(reqVO.getCopyUserIds())) { - processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), instance.getProcessInstanceId(), - reqVO.getId(), task.getName()); + processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), reqVO.getId()); } // 情况一:被委派的任务,不调用 complete 去完成任务 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http index 6b960512d8..389bf4ac90 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http @@ -53,13 +53,3 @@ tenant-id: {{adminTenentId}} GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} - -### 6.3 获取客户成交周期(按区域) -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-area?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} - -### 6.4 获取客户成交周期(按产品) -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-product?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java index 3539b5db5c..51d1499006 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java @@ -96,18 +96,6 @@ public class CrmStatisticsCustomerController { return success(customerService.getCustomerDealCycleByUser(reqVO)); } - @GetMapping("/get-customer-deal-cycle-by-area") - @Operation(summary = "获取客户成交周期(按用户)") - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getCustomerDealCycleByArea(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getCustomerDealCycleByArea(reqVO)); - } - - @GetMapping("/get-customer-deal-cycle-by-product") - @Operation(summary = "获取客户成交周期(按用户)") - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") - public CommonResult> getCustomerDealCycleByProduct(@Valid CrmStatisticsCustomerReqVO reqVO) { - return success(customerService.getCustomerDealCycleByProduct(reqVO)); - } + // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByAreaRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByAreaRespVO.java deleted file mode 100644 index 3698378278..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByAreaRespVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - CRM 客户成交周期分析(按区域) VO") -@Data -public class CrmStatisticsCustomerDealCycleByAreaRespVO { - - @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @JsonIgnore - private Integer areaId; - - @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省") - private String areaName; - - @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") - private Double customerDealCycle; - - @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer customerDealCount; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByProductRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByProductRespVO.java deleted file mode 100644 index 442c195aae..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByProductRespVO.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - CRM 客户成交周期分析(按产品) VO") -@Data -public class CrmStatisticsCustomerDealCycleByProductRespVO { - - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "演示产品") - private String productName; - - @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") - private Double customerDealCycle; - - @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer customerDealCount; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 171d432b02..458ef79c3d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -53,7 +53,6 @@ public interface CrmStatisticsCustomerMapper { /** * 合同总金额(按用户) - * * @return 统计数据@return 统计数据@param reqVO 请求参数 * @return 统计数据 */ @@ -192,20 +191,4 @@ public interface CrmStatisticsCustomerMapper { */ List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); - /** - * 客户成交周期(按区域) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List selectCustomerDealCycleGroupByAreaId(CrmStatisticsCustomerReqVO reqVO); - - /** - * 客户成交周期(按产品) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List selectCustomerDealCycleGroupByProductId(CrmStatisticsCustomerReqVO reqVO); - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java index 56ecf975ed..0e00e9c222 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java @@ -77,7 +77,7 @@ public interface CrmStatisticsCustomerService { /** * 客户成交周期(按日期) - *

+ * * 成交周期的定义:客户 customer 在创建出来,到合同 contract 第一次成交的时间差 * * @param reqVO 请求参数 @@ -93,20 +93,4 @@ public interface CrmStatisticsCustomerService { */ List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); - /** - * 客户成交周期(按区域) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO); - - /** - * 客户成交周期(按产品) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - List getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO); - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index c5b933c439..f4787b20fa 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -4,9 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.framework.ip.core.Area; -import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; -import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; import cn.iocoder.yudao.module.system.api.dept.DeptApi; @@ -22,7 +19,6 @@ import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.Function; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @@ -294,51 +290,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe return summaryList; } - @Override - public List getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { - return Collections.emptyList(); - } - reqVO.setUserIds(userIds); - - // 2. 获取客户地区统计数据 - List dealCycleByAreaList = customerMapper.selectCustomerDealCycleGroupByAreaId(reqVO); - if (CollUtil.isEmpty(dealCycleByAreaList)) { - return Collections.emptyList(); - } - - // 3. 拼接数据 - Map areaMap = convertMap(AreaUtils.getByType(AreaTypeEnum.PROVINCE, Function.identity()), - Area::getId); - return convertList(dealCycleByAreaList, vo -> { - if (vo.getAreaId() != null) { - Integer parentId = AreaUtils.getParentIdByType(vo.getAreaId(), AreaTypeEnum.PROVINCE); - findAndThen(areaMap, parentId, area -> vo.setAreaId(parentId).setAreaName(area.getName())); - } - return vo; - }); - } - - @Override - public List getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO) { - // 1. 获得用户编号数组 - List userIds = getUserIds(reqVO); - if (CollUtil.isEmpty(userIds)) { - return Collections.emptyList(); - } - reqVO.setUserIds(userIds); - - // 2. 获取客户产品统计数据 - List dealCycleByProductList = customerMapper.selectCustomerDealCycleGroupByProductId(reqVO); - if (CollUtil.isEmpty(dealCycleByProductList)) { - return Collections.emptyList(); - } - - return dealCycleByProductList; - } - /** * 拼接用户信息(昵称) * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml index e850a0c882..44c6c4b84a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml @@ -19,18 +19,17 @@ @@ -54,14 +53,13 @@ COUNT(DISTINCT customer.id) AS customer_deal_count FROM crm_customer AS customer LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id - WHERE customer.deleted = 0 - AND contract.deleted = 0 + WHERE customer.deleted = 0 AND contract.deleted = 0 AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} AND customer.owner_user_id IN #{userId} - AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} GROUP BY customer.owner_user_id @@ -223,42 +221,4 @@ GROUP BY customer.owner_user_id - - - - From 62c6c4b9bd7c6fa5ba555bb7f333fd73f357e8af Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 12 Apr 2024 19:17:49 +0800 Subject: [PATCH 72/86] =?UTF-8?q?=E5=90=8C=E6=AD=A5=20develop=20=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 ++-- yudao-server/pom.xml | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index 9cf34eb372..3a66524bc1 100644 --- a/pom.xml +++ b/pom.xml @@ -16,12 +16,12 @@ yudao-module-system yudao-module-infra - yudao-module-bpm + - yudao-module-crm + diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index ade54c0685..bc850b5902 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - cn.iocoder.boot - yudao-module-bpm-biz - ${revision} - + + + + + @@ -88,11 +88,11 @@ - - cn.iocoder.boot - yudao-module-crm-biz - ${revision} - + + + + + From 1274f925449e12f4fff9105d52cfc698ff5e3592 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 18 Apr 2024 22:19:26 +0800 Subject: [PATCH 73/86] =?UTF-8?q?=E4=BC=98=E5=8C=96=20job=20=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=EF=BC=9A=201.=20=E6=96=B0=E5=A2=9E=E6=88=96=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20job=20=E9=85=8D=E7=BD=AE=E6=97=B6=EF=BC=8C=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=20handlerName=20=E5=AF=B9=E5=BA=94=E7=9A=84=20Spring?= =?UTF-8?q?=20Bean=20=E5=AD=98=E5=9C=A8=202.=20=E5=88=A0=E9=99=A4=20job=20?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E9=A2=9D=E5=A4=96=E6=9A=82=E5=81=9C=20Trigge?= =?UTF-8?q?r=E3=80=81=E5=8F=96=E6=B6=88=E8=B0=83=E5=BA=A6=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/scheduler/SchedulerManager.java | 6 +- .../infra/enums/ErrorCodeConstants.java | 2 + .../infra/service/job/JobServiceImpl.java | 39 +++++++---- .../infra/service/job/JobServiceImplTest.java | 65 ++++++++++++------- 4 files changed, 76 insertions(+), 36 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java index cb2dad455a..d56682e0cd 100644 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java @@ -48,7 +48,7 @@ public class SchedulerManager { .withIdentity(jobHandlerName).build(); // 创建 Trigger 对象 Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); - // 新增调度 + // 新增 Job 调度 scheduler.scheduleJob(jobDetail, trigger); } @@ -80,6 +80,10 @@ public class SchedulerManager { */ public void deleteJob(String jobHandlerName) throws SchedulerException { validateScheduler(); + // 暂停 Trigger 对象 + scheduler.pauseTrigger(new TriggerKey(jobHandlerName)); + // 取消并删除 Job 调度 + scheduler.unscheduleJob(new TriggerKey(jobHandlerName)); scheduler.deleteJob(new JobKey(jobHandlerName)); } diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java index 19aa4e7186..3385596ad6 100644 --- a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java @@ -22,6 +22,8 @@ public interface ErrorCodeConstants { ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1_001_001_003, "定时任务已经处于该状态,无需修改"); ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1_001_001_004, "只有开启状态的任务,才可以修改"); ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1_001_001_005, "CRON 表达式不正确"); + ErrorCode JOB_HANDLER_BEAN_NOT_EXISTS = new ErrorCode(1_001_001_006, "定时任务的处理器 Bean 不存在"); + ErrorCode JOB_HANDLER_BEAN_TYPE_ERROR = new ErrorCode(1_001_001_007, "定时任务的处理器 Bean 类型不正确,未实现 JobHandler 接口"); // ========== API 错误日志 1-001-002-000 ========== ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1_001_002_000, "API 错误日志不存在"); diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java index 094177202e..dd887e165c 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.infra.service.job; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; import cn.iocoder.yudao.framework.quartz.core.util.CronUtils; import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobPageReqVO; @@ -9,13 +11,12 @@ import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; import cn.iocoder.yudao.module.infra.dal.mysql.job.JobMapper; import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum; +import jakarta.annotation.Resource; import org.quartz.SchedulerException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; - import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.containsAny; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; @@ -39,24 +40,25 @@ public class JobServiceImpl implements JobService { @Transactional(rollbackFor = Exception.class) public Long createJob(JobSaveReqVO createReqVO) throws SchedulerException { validateCronExpression(createReqVO.getCronExpression()); - // 校验唯一性 + // 1.1 校验唯一性 if (jobMapper.selectByHandlerName(createReqVO.getHandlerName()) != null) { throw exception(JOB_HANDLER_EXISTS); } - // 插入 + // 1.2 校验 JobHandler 是否存在 + validateJobHandlerExists(createReqVO.getHandlerName()); + + // 2. 插入 JobDO JobDO job = BeanUtils.toBean(createReqVO, JobDO.class); job.setStatus(JobStatusEnum.INIT.getStatus()); fillJobMonitorTimeoutEmpty(job); jobMapper.insert(job); - // 添加 Job 到 Quartz 中 + // 3.1 添加 Job 到 Quartz 中 schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression(), createReqVO.getRetryCount(), createReqVO.getRetryInterval()); - // 更新 + // 3.2 更新 JobDO JobDO updateObj = JobDO.builder().id(job.getId()).status(JobStatusEnum.NORMAL.getStatus()).build(); jobMapper.updateById(updateObj); - - // 返回 return job.getId(); } @@ -64,22 +66,35 @@ public class JobServiceImpl implements JobService { @Transactional(rollbackFor = Exception.class) public void updateJob(JobSaveReqVO updateReqVO) throws SchedulerException { validateCronExpression(updateReqVO.getCronExpression()); - // 校验存在 + // 1.1 校验存在 JobDO job = validateJobExists(updateReqVO.getId()); - // 只有开启状态,才可以修改.原因是,如果出暂停状态,修改 Quartz Job 时,会导致任务又开始执行 + // 1.2 只有开启状态,才可以修改.原因是,如果出暂停状态,修改 Quartz Job 时,会导致任务又开始执行 if (!job.getStatus().equals(JobStatusEnum.NORMAL.getStatus())) { throw exception(JOB_UPDATE_ONLY_NORMAL_STATUS); } - // 更新 + // 1.3 校验 JobHandler 是否存在 + validateJobHandlerExists(updateReqVO.getHandlerName()); + + // 2. 更新 JobDO JobDO updateObj = BeanUtils.toBean(updateReqVO, JobDO.class); fillJobMonitorTimeoutEmpty(updateObj); jobMapper.updateById(updateObj); - // 更新 Job 到 Quartz 中 + // 3. 更新 Job 到 Quartz 中 schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression(), updateReqVO.getRetryCount(), updateReqVO.getRetryInterval()); } + private void validateJobHandlerExists(String handlerName) { + Object handler = SpringUtil.getBean(handlerName); + if (handler == null) { + throw exception(JOB_HANDLER_BEAN_NOT_EXISTS); + } + if (!(handler instanceof JobHandler)) { + throw exception(JOB_HANDLER_BEAN_TYPE_ERROR); + } + } + @Override @Transactional(rollbackFor = Exception.class) public void updateJobStatus(Long id, Integer status) throws SchedulerException { diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java index eedbb1d507..7cd160c3d3 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.infra.service.job; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; @@ -8,7 +9,9 @@ import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; import cn.iocoder.yudao.module.infra.dal.mysql.job.JobMapper; import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum; +import cn.iocoder.yudao.module.infra.job.job.JobLogCleanJob; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; import org.quartz.SchedulerException; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -23,6 +26,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.verify; @Import(JobServiceImpl.class) @@ -35,6 +39,9 @@ public class JobServiceImplTest extends BaseDbUnitTest { @MockBean private SchedulerManager schedulerManager; + @MockBean + private JobLogCleanJob jobLogCleanJob; + @Test public void testCreateJob_cronExpressionValid() { // 准备参数。Cron 表达式为 String 类型,默认随机字符串。 @@ -48,11 +55,15 @@ public class JobServiceImplTest extends BaseDbUnitTest { public void testCreateJob_jobHandlerExists() throws SchedulerException { // 准备参数 指定 Cron 表达式 JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class, o -> o.setCronExpression("0 0/1 * * * ? *")); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(reqVO.getHandlerName()))) + .thenReturn(jobLogCleanJob); - // 调用 - jobService.createJob(reqVO); - // 调用,并断言异常 - assertServiceException(() -> jobService.createJob(reqVO), JOB_HANDLER_EXISTS); + // 调用 + jobService.createJob(reqVO); + // 调用,并断言异常 + assertServiceException(() -> jobService.createJob(reqVO), JOB_HANDLER_EXISTS); + } } @Test @@ -60,18 +71,22 @@ public class JobServiceImplTest extends BaseDbUnitTest { // 准备参数 指定 Cron 表达式 JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class, o -> o.setCronExpression("0 0/1 * * * ? *")) .setId(null); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(reqVO.getHandlerName()))) + .thenReturn(jobLogCleanJob); - // 调用 - Long jobId = jobService.createJob(reqVO); - // 断言 - assertNotNull(jobId); - // 校验记录的属性是否正确 - JobDO job = jobMapper.selectById(jobId); - assertPojoEquals(reqVO, job, "id"); - assertEquals(JobStatusEnum.NORMAL.getStatus(), job.getStatus()); - // 校验调用 - verify(schedulerManager).addJob(eq(job.getId()), eq(job.getHandlerName()), eq(job.getHandlerParam()), - eq(job.getCronExpression()), eq(reqVO.getRetryCount()), eq(reqVO.getRetryInterval())); + // 调用 + Long jobId = jobService.createJob(reqVO); + // 断言 + assertNotNull(jobId); + // 校验记录的属性是否正确 + JobDO job = jobMapper.selectById(jobId); + assertPojoEquals(reqVO, job, "id"); + assertEquals(JobStatusEnum.NORMAL.getStatus(), job.getStatus()); + // 校验调用 + verify(schedulerManager).addJob(eq(job.getId()), eq(job.getHandlerName()), eq(job.getHandlerParam()), + eq(job.getCronExpression()), eq(reqVO.getRetryCount()), eq(reqVO.getRetryInterval())); + } } @Test @@ -109,15 +124,19 @@ public class JobServiceImplTest extends BaseDbUnitTest { o.setId(job.getId()); o.setCronExpression("0 0/1 * * * ? *"); }); + try (MockedStatic springUtilMockedStatic = mockStatic(SpringUtil.class)) { + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(updateReqVO.getHandlerName()))) + .thenReturn(jobLogCleanJob); - // 调用 - jobService.updateJob(updateReqVO); - // 校验记录的属性是否正确 - JobDO updateJob = jobMapper.selectById(updateReqVO.getId()); - assertPojoEquals(updateReqVO, updateJob); - // 校验调用 - verify(schedulerManager).updateJob(eq(job.getHandlerName()), eq(updateReqVO.getHandlerParam()), - eq(updateReqVO.getCronExpression()), eq(updateReqVO.getRetryCount()), eq(updateReqVO.getRetryInterval())); + // 调用 + jobService.updateJob(updateReqVO); + // 校验记录的属性是否正确 + JobDO updateJob = jobMapper.selectById(updateReqVO.getId()); + assertPojoEquals(updateReqVO, updateJob); + // 校验调用 + verify(schedulerManager).updateJob(eq(job.getHandlerName()), eq(updateReqVO.getHandlerParam()), + eq(updateReqVO.getCronExpression()), eq(updateReqVO.getRetryCount()), eq(updateReqVO.getRetryInterval())); + } } @Test From 5d58037d05ccf8623cba01a5b539d69bd00cabeb Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 22 Apr 2024 19:01:25 +0800 Subject: [PATCH 74/86] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E5=B0=86=20hu?= =?UTF-8?q?tool-all=206.0=20=E7=89=88=E6=9C=AC=E6=9B=BF=E6=8D=A2=E6=88=90?= =?UTF-8?q?=20hutool-extra=EF=BC=8C=E5=87=8F=E5=B0=91=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 2 +- yudao-framework/yudao-common/pom.xml | 4 ---- .../BpmTaskCandidateExpressionStrategy.java | 4 ++-- .../yudao-module-system-biz/pom.xml | 6 ++++++ .../convert/mail/MailAccountConvert.java | 21 ------------------- .../service/mail/MailSendServiceImpl.java | 15 ++++++++----- .../service/mail/MailSendServiceImplTest.java | 3 +-- 7 files changed, 20 insertions(+), 35 deletions(-) delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 09067a2a4e..2ee3a30371 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -443,7 +443,7 @@ org.dromara.hutool - hutool-all + hutool-extra ${hutool-6.version} diff --git a/yudao-framework/yudao-common/pom.xml b/yudao-framework/yudao-common/pom.xml index e735856a81..b28da08fe2 100644 --- a/yudao-framework/yudao-common/pom.xml +++ b/yudao-framework/yudao-common/pom.xml @@ -127,10 +127,6 @@ cn.hutool hutool-all - - org.dromara.hutool - hutool-all - com.alibaba diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java index e51ab76e00..e0f9dabe5a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; -import org.dromara.hutool.core.convert.Convert; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import org.flowable.engine.delegate.DelegateExecution; import org.springframework.stereotype.Component; diff --git a/yudao-module-system/yudao-module-system-biz/pom.xml b/yudao-module-system/yudao-module-system-biz/pom.xml index 6de1a58a15..082b6b470d 100644 --- a/yudao-module-system/yudao-module-system-biz/pom.xml +++ b/yudao-module-system/yudao-module-system-biz/pom.xml @@ -127,6 +127,12 @@ com.xingyuv spring-boot-starter-captcha-plus + + + org.dromara.hutool + hutool-extra + + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java deleted file mode 100644 index f538197d79..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.system.convert.mail; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; -import org.dromara.hutool.extra.mail.MailAccount; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -@Mapper -public interface MailAccountConvert { - - MailAccountConvert INSTANCE = Mappers.getMapper(MailAccountConvert.class); - - default MailAccount convert(MailAccountDO account, String nickname) { - String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail(); - return new MailAccount().setFrom(from).setAuth(true) - .setUser(account.getUsername()).setPass(account.getPassword().toCharArray()) - .setHost(account.getHost()).setPort(account.getPort()).setSslEnable(account.getSslEnable()); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java index 61ff83d8be..178a64aec9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.service.mail; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; @@ -12,13 +11,12 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; import cn.iocoder.yudao.module.system.service.member.MemberService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import com.google.common.annotations.VisibleForTesting; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.dromara.hutool.extra.mail.MailAccount; -import org.dromara.hutool.extra.mail.MailUtil; +import org.dromara.hutool.extra.mail.*; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -105,7 +103,7 @@ public class MailSendServiceImpl implements MailSendService { public void doSendMail(MailSendMessage message) { // 1. 创建发送账号 MailAccountDO account = validateMailAccount(message.getAccountId()); - MailAccount mailAccount = MailAccountConvert.INSTANCE.convert(account, message.getNickname()); + MailAccount mailAccount = buildMailAccount(account, message.getNickname()); // 2. 发送邮件 try { String messageId = MailUtil.send(mailAccount, message.getMail(), @@ -118,6 +116,13 @@ public class MailSendServiceImpl implements MailSendService { } } + private MailAccount buildMailAccount(MailAccountDO account, String nickname) { + String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail(); + return new MailAccount().setFrom(from).setAuth(true) + .setUser(account.getUsername()).setPass(account.getPassword().toCharArray()) + .setHost(account.getHost()).setPort(account.getPort()).setSslEnable(account.getSslEnable()); + } + @VisibleForTesting MailTemplateDO validateMailTemplate(String templateCode) { // 获得邮件模板。考虑到效率,从缓存中获取 diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java index eaea39fe96..1ef1e12322 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java @@ -13,8 +13,7 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; import cn.iocoder.yudao.module.system.service.member.MemberService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import org.assertj.core.util.Lists; -import org.dromara.hutool.extra.mail.MailAccount; -import org.dromara.hutool.extra.mail.MailUtil; +import org.dromara.hutool.extra.mail.*; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; From ff5276998cb956fc0878bf39a194040378ce7363 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 22 Apr 2024 19:14:10 +0800 Subject: [PATCH 75/86] =?UTF-8?q?=E3=80=90=E7=A7=BB=E9=99=A4=E3=80=91?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E6=96=87=E6=A1=A3=EF=BC=8C=E7=AE=80?= =?UTF-8?q?=E5=8C=96=E9=A1=B9=E7=9B=AE=E7=9A=84=E5=A4=8D=E6=9D=82=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 16 -- .../yudao-module-infra-biz/pom.xml | 5 - .../admin/db/DatabaseDocController.java | 154 ------------------ 3 files changed, 175 deletions(-) delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 2ee3a30371..e25014d419 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -475,22 +475,6 @@ ${fastjson.version} - - cn.smallbun.screw - screw-core - ${screw.version} - - - org.freemarker - freemarker - - - com.alibaba - fastjson - - - - com.google.guava guava diff --git a/yudao-module-infra/yudao-module-infra-biz/pom.xml b/yudao-module-infra/yudao-module-infra-biz/pom.xml index 44f3aef67b..f2840cfc7a 100644 --- a/yudao-module-infra/yudao-module-infra-biz/pom.xml +++ b/yudao-module-infra/yudao-module-infra-biz/pom.xml @@ -95,11 +95,6 @@ velocity-engine-core - - cn.smallbun.screw - screw-core - - cn.iocoder.boot diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java deleted file mode 100644 index ea66645b4f..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/db/DatabaseDocController.java +++ /dev/null @@ -1,154 +0,0 @@ -package cn.iocoder.yudao.module.infra.controller.admin.db; - -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.util.IdUtil; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.smallbun.screw.core.Configuration; -import cn.smallbun.screw.core.engine.EngineConfig; -import cn.smallbun.screw.core.engine.EngineFileType; -import cn.smallbun.screw.core.engine.EngineTemplateType; -import cn.smallbun.screw.core.execute.DocumentationExecute; -import cn.smallbun.screw.core.process.ProcessConfig; -import com.baomidou.dynamic.datasource.creator.DataSourceProperty; -import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; - -@Tag(name = "管理后台 - 数据库文档") -@RestController -@RequestMapping("/infra/db-doc") -public class DatabaseDocController { - - @Resource - private DynamicDataSourceProperties dynamicDataSourceProperties; - - private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator - + "db-doc"; - private static final String DOC_FILE_NAME = "数据库文档"; - private static final String DOC_VERSION = "1.0.0"; - private static final String DOC_DESCRIPTION = "文档描述"; - - @GetMapping("/export-html") - @Operation(summary = "导出 html 格式的数据文档") - @Parameter(name = "deleteFile", description = "是否删除在服务器本地生成的数据库文档", example = "true") - public void exportHtml(@RequestParam(defaultValue = "true") Boolean deleteFile, - HttpServletResponse response) throws IOException { - doExportFile(EngineFileType.HTML, deleteFile, response); - } - - @GetMapping("/export-word") - @Operation(summary = "导出 word 格式的数据文档") - @Parameter(name = "deleteFile", description = "是否删除在服务器本地生成的数据库文档", example = "true") - public void exportWord(@RequestParam(defaultValue = "true") Boolean deleteFile, - HttpServletResponse response) throws IOException { - doExportFile(EngineFileType.WORD, deleteFile, response); - } - - @GetMapping("/export-markdown") - @Operation(summary = "导出 markdown 格式的数据文档") - @Parameter(name = "deleteFile", description = "是否删除在服务器本地生成的数据库文档", example = "true") - public void exportMarkdown(@RequestParam(defaultValue = "true") Boolean deleteFile, - HttpServletResponse response) throws IOException { - doExportFile(EngineFileType.MD, deleteFile, response); - } - - private void doExportFile(EngineFileType fileOutputType, Boolean deleteFile, - HttpServletResponse response) throws IOException { - String docFileName = DOC_FILE_NAME + "_" + IdUtil.fastSimpleUUID(); - String filePath = doExportFile(fileOutputType, docFileName); - String downloadFileName = DOC_FILE_NAME + fileOutputType.getFileSuffix(); //下载后的文件名 - try { - // 读取,返回 - ServletUtils.writeAttachment(response, downloadFileName, FileUtil.readBytes(filePath)); - } finally { - handleDeleteFile(deleteFile, filePath); - } - } - - /** - * 输出文件,返回文件路径 - * - * @param fileOutputType 文件类型 - * @param fileName 文件名, 无需 ".docx" 等文件后缀 - * @return 生成的文件所在路径 - */ - private String doExportFile(EngineFileType fileOutputType, String fileName) { - try (HikariDataSource dataSource = buildDataSource()) { - // 创建 screw 的配置 - Configuration config = Configuration.builder() - .version(DOC_VERSION) // 版本 - .description(DOC_DESCRIPTION) // 描述 - .dataSource(dataSource) // 数据源 - .engineConfig(buildEngineConfig(fileOutputType, fileName)) // 引擎配置 - .produceConfig(buildProcessConfig()) // 处理配置 - .build(); - - // 执行 screw,生成数据库文档 - new DocumentationExecute(config).execute(); - - return FILE_OUTPUT_DIR + File.separator + fileName + fileOutputType.getFileSuffix(); - } - } - - private void handleDeleteFile(Boolean deleteFile, String filePath) { - if (!deleteFile) { - return; - } - FileUtil.del(filePath); - } - - /** - * 创建数据源 - */ - // TODO 芋艿:screw 暂时不支持 druid,尴尬 - private HikariDataSource buildDataSource() { - // 获得 DataSource 数据源,目前只支持首个 - String primary = dynamicDataSourceProperties.getPrimary(); - DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(primary); - // 创建 HikariConfig 配置类 - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setJdbcUrl(dataSourceProperty.getUrl()); - hikariConfig.setUsername(dataSourceProperty.getUsername()); - hikariConfig.setPassword(dataSourceProperty.getPassword()); - hikariConfig.addDataSourceProperty("useInformationSchema", "true"); // 设置可以获取 tables remarks 信息 - // 创建数据源 - return new HikariDataSource(hikariConfig); - } - - /** - * 创建 screw 的引擎配置 - */ - private static EngineConfig buildEngineConfig(EngineFileType fileOutputType, String docFileName) { - return EngineConfig.builder() - .fileOutputDir(FILE_OUTPUT_DIR) // 生成文件路径 - .openOutputDir(false) // 打开目录 - .fileType(fileOutputType) // 文件类型 - .produceType(EngineTemplateType.velocity) // 文件类型 - .fileName(docFileName) // 自定义文件名称 - .build(); - } - - /** - * 创建 screw 的处理配置,一般可忽略 - * 指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置 - */ - private static ProcessConfig buildProcessConfig() { - return ProcessConfig.builder() - .ignoreTablePrefix(Arrays.asList("QRTZ_", "ACT_", "FLW_")) // 忽略表前缀 - .build(); - } - -} From 8093ef3b968d566c9b42e9442a100932540683a7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 22 Apr 2024 19:42:45 +0800 Subject: [PATCH 76/86] =?UTF-8?q?=E3=80=90=E7=A7=BB=E9=99=A4=E3=80=91?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=A0=81=E7=9A=84=E7=AE=A1=E7=90=86=EF=BC=8C?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E9=A1=B9=E7=9B=AE=E7=9A=84=E5=A4=8D=E6=9D=82?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/util/ServiceExceptionUtil.java | 54 +-- .../errorcode/config/ErrorCodeProperties.java | 30 -- .../YudaoErrorCodeAutoConfiguration.java | 39 --- .../generator/ErrorCodeAutoGenerator.java | 15 - .../generator/ErrorCodeAutoGeneratorImpl.java | 108 ------ .../core/loader/ErrorCodeLoader.java | 34 -- .../core/loader/ErrorCodeLoaderImpl.java | 82 ----- .../framework/errorcode/package-info.java | 10 - ...ot.autoconfigure.AutoConfiguration.imports | 3 +- .../system/api/errorcode/ErrorCodeApi.java | 35 -- .../dto/ErrorCodeAutoGenerateReqDTO.java | 34 -- .../api/errorcode/dto/ErrorCodeRespDTO.java | 28 -- .../enums/errorcode/ErrorCodeTypeEnum.java | 39 --- .../api/errorcode/ErrorCodeApiImpl.java | 33 -- .../admin/errorcode/ErrorCodeController.http | 13 - .../admin/errorcode/ErrorCodeController.java | 93 ------ .../errorcode/vo/ErrorCodePageReqVO.java | 36 -- .../admin/errorcode/vo/ErrorCodeRespVO.java | 47 --- .../errorcode/vo/ErrorCodeSaveReqVO.java | 30 -- .../dal/dataobject/errorcode/ErrorCodeDO.java | 52 --- .../dal/mysql/errorcode/ErrorCodeMapper.java | 40 --- .../service/errorcode/ErrorCodeService.java | 77 ----- .../errorcode/ErrorCodeServiceImpl.java | 167 ---------- .../errorcode/ErrorCodeServiceTest.java | 308 ------------------ .../src/test/resources/sql/clean.sql | 1 - .../src/test/resources/sql/create_tables.sql | 15 - .../src/main/resources/application-local.yaml | 2 - .../src/main/resources/application.yaml | 8 - 28 files changed, 3 insertions(+), 1430 deletions(-) delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/ErrorCodeProperties.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeAutoConfiguration.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGenerator.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGeneratorImpl.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoader.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoaderImpl.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/package-info.java delete mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApi.java delete mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeAutoGenerateReqDTO.java delete mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeRespDTO.java delete mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/errorcode/ErrorCodeTypeEnum.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApiImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.http delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeRespVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeSaveReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/errorcode/ErrorCodeDO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeService.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java index 966109fbf8..03c0859408 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java @@ -6,74 +6,24 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - /** * {@link ServiceException} 工具类 * * 目的在于,格式化异常信息提示。 * 考虑到 String.format 在参数不正确时会报错,因此使用 {} 作为占位符,并使用 {@link #doFormat(int, String, Object...)} 方法来格式化 * - * 因为 {@link #MESSAGES} 里面默认是没有异常信息提示的模板的,所以需要使用方自己初始化进去。目前想到的有几种方式: - * - * 1. 异常提示信息,写在枚举类中,例如说,cn.iocoder.oceans.user.api.constants.ErrorCodeEnum 类 + ServiceExceptionConfiguration - * 2. 异常提示信息,写在 .properties 等等配置文件 - * 3. 异常提示信息,写在 Apollo 等等配置中心中,从而实现可动态刷新 - * 4. 异常提示信息,存储在 db 等等数据库中,从而实现可动态刷新 */ @Slf4j public class ServiceExceptionUtil { - /** - * 错误码提示模板 - */ - private static final ConcurrentMap MESSAGES = new ConcurrentHashMap<>(); - - public static void putAll(Map messages) { - ServiceExceptionUtil.MESSAGES.putAll(messages); - } - - public static void put(Integer code, String message) { - ServiceExceptionUtil.MESSAGES.put(code, message); - } - - public static void delete(Integer code, String message) { - ServiceExceptionUtil.MESSAGES.remove(code, message); - } - // ========== 和 ServiceException 的集成 ========== public static ServiceException exception(ErrorCode errorCode) { - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg()); - return exception0(errorCode.getCode(), messagePattern); + return exception0(errorCode.getCode(), errorCode.getMsg()); } public static ServiceException exception(ErrorCode errorCode, Object... params) { - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg()); - return exception0(errorCode.getCode(), messagePattern, params); - } - - /** - * 创建指定编号的 ServiceException 的异常 - * - * @param code 编号 - * @return 异常 - */ - public static ServiceException exception(Integer code) { - return exception0(code, MESSAGES.get(code)); - } - - /** - * 创建指定编号的 ServiceException 的异常 - * - * @param code 编号 - * @param params 消息提示的占位符对应的参数 - * @return 异常 - */ - public static ServiceException exception(Integer code, Object... params) { - return exception0(code, MESSAGES.get(code), params); + return exception0(errorCode.getCode(), errorCode.getMsg(), params); } public static ServiceException exception0(Integer code, String messagePattern, Object... params) { diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/ErrorCodeProperties.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/ErrorCodeProperties.java deleted file mode 100644 index 5e6aab49a7..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/ErrorCodeProperties.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.framework.errorcode.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.validation.annotation.Validated; - -import jakarta.validation.constraints.NotNull; -import java.util.List; - -/** - * 错误码的配置属性类 - * - * @author dlyan - */ -@ConfigurationProperties("yudao.error-code") -@Data -@Validated -public class ErrorCodeProperties { - - /** - * 是否开启 - */ - private Boolean enable = true; - /** - * 错误码枚举类 - */ - @NotNull(message = "错误码枚举类不能为空") - private List constantsClassList; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeAutoConfiguration.java deleted file mode 100644 index ed2c92fc2a..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/config/YudaoErrorCodeAutoConfiguration.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.framework.errorcode.config; - -import cn.iocoder.yudao.framework.errorcode.core.generator.ErrorCodeAutoGenerator; -import cn.iocoder.yudao.framework.errorcode.core.generator.ErrorCodeAutoGeneratorImpl; -import cn.iocoder.yudao.framework.errorcode.core.loader.ErrorCodeLoader; -import cn.iocoder.yudao.framework.errorcode.core.loader.ErrorCodeLoaderImpl; -import cn.iocoder.yudao.module.system.api.errorcode.ErrorCodeApi; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.scheduling.annotation.EnableScheduling; - -/** - * 错误码配置类 - * - * @author 芋道源码 - */ -@AutoConfiguration -@ConditionalOnProperty(prefix = "yudao.error-code", value = "enable", matchIfMissing = true) // 允许使用 yudao.error-code.enable=false 禁用访问日志 -@EnableConfigurationProperties(ErrorCodeProperties.class) -@EnableScheduling // 开启调度任务的功能,因为 ErrorCodeRemoteLoader 通过定时刷新错误码 -public class YudaoErrorCodeAutoConfiguration { - - @Bean - public ErrorCodeAutoGenerator errorCodeAutoGenerator(@Value("${spring.application.name}") String applicationName, - ErrorCodeProperties errorCodeProperties, - ErrorCodeApi errorCodeApi) { - return new ErrorCodeAutoGeneratorImpl(applicationName, errorCodeProperties.getConstantsClassList(), errorCodeApi); - } - - @Bean - public ErrorCodeLoader errorCodeLoader(@Value("${spring.application.name}") String applicationName, - ErrorCodeApi errorCodeApi) { - return new ErrorCodeLoaderImpl(applicationName, errorCodeApi); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGenerator.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGenerator.java deleted file mode 100644 index b13cacaa2f..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGenerator.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.iocoder.yudao.framework.errorcode.core.generator; - -/** - * 错误码的自动生成器 - * - * @author dylan - */ -public interface ErrorCodeAutoGenerator { - - /** - * 将配置类到错误码写入数据库 - */ - void execute(); - -} diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGeneratorImpl.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGeneratorImpl.java deleted file mode 100644 index 00fbc03ca4..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/generator/ErrorCodeAutoGeneratorImpl.java +++ /dev/null @@ -1,108 +0,0 @@ -package cn.iocoder.yudao.framework.errorcode.core.generator; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.exceptions.ExceptionUtil; -import cn.hutool.core.util.ClassUtil; -import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import cn.iocoder.yudao.module.system.api.errorcode.ErrorCodeApi; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * ErrorCodeAutoGenerator 的实现类 - * 目的是,扫描指定的 {@link #constantsClassList} 类,写入到 system 服务中 - * - * @author dylan - */ -@RequiredArgsConstructor -@Slf4j -public class ErrorCodeAutoGeneratorImpl implements ErrorCodeAutoGenerator { - - /** - * 应用分组 - */ - private final String applicationName; - /** - * 错误码枚举类 - */ - private final List constantsClassList; - /** - * 错误码 Api - */ - private final ErrorCodeApi errorCodeApi; - - @Override - @EventListener(ApplicationReadyEvent.class) - @Async // 异步,保证项目的启动过程,毕竟非关键流程 - public void execute() { - // 第一步,解析错误码 - List autoGenerateDTOs = parseErrorCode(); - log.info("[execute][解析到错误码数量为 ({}) 个]", autoGenerateDTOs.size()); - - // 第二步,写入到 system 服务 - try { - errorCodeApi.autoGenerateErrorCodeList(autoGenerateDTOs); - log.info("[execute][写入到 system 组件完成]"); - } catch (Exception ex) { - log.error("[execute][写入到 system 组件失败({})]", ExceptionUtil.getRootCauseMessage(ex)); - } - } - - /** - * 解析 constantsClassList 变量,转换成错误码数组 - * - * @return 错误码数组 - */ - private List parseErrorCode() { - // 校验 errorCodeConstantsClass 参数 - if (CollUtil.isEmpty(constantsClassList)) { - log.info("[execute][未配置 yudao.error-code.constants-class-list 配置项,不进行自动写入到 system 服务中]"); - return new ArrayList<>(); - } - - // 解析错误码 - List autoGenerateDTOs = new ArrayList<>(); - constantsClassList.forEach(constantsClass -> { - try { - // 解析错误码枚举类 - Class errorCodeConstantsClazz = ClassUtil.loadClass(constantsClass); - // 解析错误码 - autoGenerateDTOs.addAll(parseErrorCode(errorCodeConstantsClazz)); - } catch (Exception ex) { - log.warn("[parseErrorCode][constantsClass({}) 加载失败({})]", constantsClass, - ExceptionUtil.getRootCauseMessage(ex)); - } - }); - return autoGenerateDTOs; - } - - /** - * 解析错误码类,获得错误码数组 - * - * @return 错误码数组 - */ - private List parseErrorCode(Class constantsClass) { - List autoGenerateDTOs = new ArrayList<>(); - Arrays.stream(constantsClass.getFields()).forEach(field -> { - if (field.getType() != ErrorCode.class) { - return; - } - // 转换成 ErrorCodeAutoGenerateReqDTO 对象 - ErrorCode errorCode = (ErrorCode) ReflectUtil.getFieldValue(constantsClass, field); - autoGenerateDTOs.add(new ErrorCodeAutoGenerateReqDTO().setApplicationName(applicationName) - .setCode(errorCode.getCode()).setMessage(errorCode.getMsg())); - }); - return autoGenerateDTOs; - } - -} - diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoader.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoader.java deleted file mode 100644 index 0bf70211f2..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoader.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.framework.errorcode.core.loader; - -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; - -/** - * 错误码加载器 - * - * 注意,错误码最终加载到 {@link ServiceExceptionUtil} 的 MESSAGES 变量中! - * - * @author dlyan - */ -public interface ErrorCodeLoader { - - /** - * 添加错误码 - * - * @param code 错误码的编号 - * @param msg 错误码的提示 - */ - default void putErrorCode(Integer code, String msg) { - ServiceExceptionUtil.put(code, msg); - } - - /** - * 刷新错误码 - */ - void refreshErrorCodes(); - - /** - * 加载错误码 - */ - void loadErrorCodes(); - -} diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoaderImpl.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoaderImpl.java deleted file mode 100644 index 4d1febfd72..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/core/loader/ErrorCodeLoaderImpl.java +++ /dev/null @@ -1,82 +0,0 @@ -package cn.iocoder.yudao.framework.errorcode.core.loader; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.exceptions.ExceptionUtil; -import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import cn.iocoder.yudao.module.system.api.errorcode.ErrorCodeApi; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.Scheduled; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * ErrorCodeLoader 的实现类,从 infra 的数据库中,加载错误码。 - * - * 考虑到错误码会刷新,所以按照 {@link #REFRESH_ERROR_CODE_PERIOD} 频率,增量加载错误码。 - * - * @author dlyan - */ -@RequiredArgsConstructor -@Slf4j -public class ErrorCodeLoaderImpl implements ErrorCodeLoader { - - /** - * 刷新错误码的频率,单位:毫秒 - */ - private static final int REFRESH_ERROR_CODE_PERIOD = 60 * 1000; - - /** - * 应用分组 - */ - private final String applicationName; - /** - * 错误码 Api - */ - private final ErrorCodeApi errorCodeApi; - - /** - * 缓存错误码的最大更新时间,用于后续的增量轮询,判断是否有更新 - */ - private LocalDateTime maxUpdateTime; - - @Override - @EventListener(ApplicationReadyEvent.class) - @Async // 异步,保证项目的启动过程,毕竟非关键流程 - public void loadErrorCodes() { - loadErrorCodes0(); - } - - @Override - @Scheduled(fixedDelay = REFRESH_ERROR_CODE_PERIOD, initialDelay = REFRESH_ERROR_CODE_PERIOD) - public void refreshErrorCodes() { - loadErrorCodes0(); - } - - private void loadErrorCodes0() { - try { - // 加载错误码 - List errorCodeRespDTOs = errorCodeApi.getErrorCodeList(applicationName, maxUpdateTime); - if (CollUtil.isEmpty(errorCodeRespDTOs)) { - return; - } - log.info("[loadErrorCodes0][加载到 ({}) 个错误码]", errorCodeRespDTOs.size()); - - // 刷新错误码的缓存 - errorCodeRespDTOs.forEach(errorCodeRespDTO -> { - // 写入到错误码的缓存 - putErrorCode(errorCodeRespDTO.getCode(), errorCodeRespDTO.getMessage()); - // 记录下更新时间,方便增量更新 - maxUpdateTime = DateUtils.max(maxUpdateTime, errorCodeRespDTO.getUpdateTime()); - }); - } catch (Exception ex) { - log.error("[loadErrorCodes0][加载错误码失败({})]", ExceptionUtil.getRootCauseMessage(ex)); - } - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/package-info.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/package-info.java deleted file mode 100644 index ddba4f78a5..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/errorcode/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/** - * 错误码 ErrorCode 的自动配置功能,提供如下功能: - * - * 1. 远程读取:项目启动时,从 system-service 服务,读取数据库中的 ErrorCode 错误码,实现错误码的提水可配置; - * 2. 自动更新:管理员在管理后台修数据库中的 ErrorCode 错误码时,项目自动从 system-service 服务加载最新的 ErrorCode 错误码; - * 3. 自动写入:项目启动时,将项目本地的错误码写到 system-server 服务中,方便管理员在管理后台编辑; - * - * @author 芋道源码 - */ -package cn.iocoder.yudao.framework.errorcode; diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 36ba94cbb7..9cdcd09c4e 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -3,5 +3,4 @@ cn.iocoder.yudao.framework.jackson.config.YudaoJacksonAutoConfiguration cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration cn.iocoder.yudao.framework.xss.config.YudaoXssAutoConfiguration -cn.iocoder.yudao.framework.banner.config.YudaoBannerAutoConfiguration -cn.iocoder.yudao.framework.errorcode.config.YudaoErrorCodeAutoConfiguration \ No newline at end of file +cn.iocoder.yudao.framework.banner.config.YudaoBannerAutoConfiguration \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApi.java deleted file mode 100644 index a86a999af6..0000000000 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApi.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.system.api.errorcode; - -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO; - -import jakarta.validation.Valid; -import java.time.LocalDateTime; -import java.util.List; - -/** - * 错误码 Api 接口 - * - * @author 芋道源码 - */ -public interface ErrorCodeApi { - - /** - * 自动创建错误码 - * - * @param autoGenerateDTOs 错误码信息 - */ - void autoGenerateErrorCodeList(@Valid List autoGenerateDTOs); - - /** - * 增量获得错误码数组 - * - * 如果 minUpdateTime 为空时,则获取所有错误码 - * - * @param applicationName 应用名 - * @param minUpdateTime 最小更新时间 - * @return 错误码数组 - */ - List getErrorCodeList(String applicationName, LocalDateTime minUpdateTime); - -} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeAutoGenerateReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeAutoGenerateReqDTO.java deleted file mode 100644 index cb8935a0ac..0000000000 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeAutoGenerateReqDTO.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.system.api.errorcode.dto; - -import lombok.Data; -import lombok.experimental.Accessors; - -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; - -/** - * 错误码自动生成 DTO - * - * @author dylan - */ -@Data -@Accessors(chain = true) -public class ErrorCodeAutoGenerateReqDTO { - - /** - * 应用名 - */ - @NotNull(message = "应用名不能为空") - private String applicationName; - /** - * 错误码编码 - */ - @NotNull(message = "错误码编码不能为空") - private Integer code; - /** - * 错误码错误提示 - */ - @NotEmpty(message = "错误码错误提示不能为空") - private String message; - -} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeRespDTO.java deleted file mode 100644 index 99372300b9..0000000000 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/dto/ErrorCodeRespDTO.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.system.api.errorcode.dto; - -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 错误码的 Response DTO - * - * @author 芋道源码 - */ -@Data -public class ErrorCodeRespDTO { - - /** - * 错误码编码 - */ - private Integer code; - /** - * 错误码错误提示 - */ - private String message; - /** - * 更新时间 - */ - private LocalDateTime updateTime; - -} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/errorcode/ErrorCodeTypeEnum.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/errorcode/ErrorCodeTypeEnum.java deleted file mode 100644 index 97349e763c..0000000000 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/errorcode/ErrorCodeTypeEnum.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.system.enums.errorcode; - -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -/** - * 错误码的类型枚举 - * - * @author dylan - */ -@AllArgsConstructor -@Getter -public enum ErrorCodeTypeEnum implements IntArrayValuable { - - /** - * 自动生成 - */ - AUTO_GENERATION(1), - /** - * 手动编辑 - */ - MANUAL_OPERATION(2); - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErrorCodeTypeEnum::getType).toArray(); - - /** - * 类型 - */ - private final Integer type; - - @Override - public int[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApiImpl.java deleted file mode 100644 index dd630205cc..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/errorcode/ErrorCodeApiImpl.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.system.api.errorcode; - -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO; -import cn.iocoder.yudao.module.system.service.errorcode.ErrorCodeService; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import java.time.LocalDateTime; -import java.util.List; - -/** - * 错误码 Api 实现类 - * - * @author 芋道源码 - */ -@Service -public class ErrorCodeApiImpl implements ErrorCodeApi { - - @Resource - private ErrorCodeService errorCodeService; - - @Override - public void autoGenerateErrorCodeList(List autoGenerateDTOs) { - errorCodeService.autoGenerateErrorCodes(autoGenerateDTOs); - } - - @Override - public List getErrorCodeList(String applicationName, LocalDateTime minUpdateTime) { - return errorCodeService.getErrorCodeList(applicationName, minUpdateTime); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.http deleted file mode 100644 index 06b8723185..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.http +++ /dev/null @@ -1,13 +0,0 @@ -### 创建错误码 -POST {{baseUrl}}/inra/error-code/create -Authorization: Bearer {{token}} -Content-Type: application/json -tenant-id: {{adminTenentId}} - -{ - "code": 200, - "message": "成功", - "group": "test", - "type": 1 -} - diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java deleted file mode 100644 index a0d14c5570..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/ErrorCodeController.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.errorcode; - -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodePageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeRespVO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeSaveReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; -import cn.iocoder.yudao.module.system.service.errorcode.ErrorCodeService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.io.IOException; -import java.util.List; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - 错误码") -@RestController -@RequestMapping("/system/error-code") -@Validated -public class ErrorCodeController { - - @Resource - private ErrorCodeService errorCodeService; - - @PostMapping("/create") - @Operation(summary = "创建错误码") - @PreAuthorize("@ss.hasPermission('system:error-code:create')") - public CommonResult createErrorCode(@Valid @RequestBody ErrorCodeSaveReqVO createReqVO) { - return success(errorCodeService.createErrorCode(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新错误码") - @PreAuthorize("@ss.hasPermission('system:error-code:update')") - public CommonResult updateErrorCode(@Valid @RequestBody ErrorCodeSaveReqVO updateReqVO) { - errorCodeService.updateErrorCode(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除错误码") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('system:error-code:delete')") - public CommonResult deleteErrorCode(@RequestParam("id") Long id) { - errorCodeService.deleteErrorCode(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得错误码") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('system:error-code:query')") - public CommonResult getErrorCode(@RequestParam("id") Long id) { - ErrorCodeDO errorCode = errorCodeService.getErrorCode(id); - return success(BeanUtils.toBean(errorCode, ErrorCodeRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得错误码分页") - @PreAuthorize("@ss.hasPermission('system:error-code:query')") - public CommonResult> getErrorCodePage(@Valid ErrorCodePageReqVO pageVO) { - PageResult pageResult = errorCodeService.getErrorCodePage(pageVO); - return success(BeanUtils.toBean(pageResult, ErrorCodeRespVO.class)); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出错误码 Excel") - @PreAuthorize("@ss.hasPermission('system:error-code:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportErrorCodeExcel(@Valid ErrorCodePageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = errorCodeService.getErrorCodePage(exportReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "错误码.xls", "数据", ErrorCodeRespVO.class, - BeanUtils.toBean(list, ErrorCodeRespVO.class)); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java deleted file mode 100644 index ba565d94c0..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodePageReqVO.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - 错误码分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class ErrorCodePageReqVO extends PageParam { - - @Schema(description = "错误码类型,参见 ErrorCodeTypeEnum 枚举类", example = "1") - private Integer type; - - @Schema(description = "应用名", example = "dashboard") - private String applicationName; - - @Schema(description = "错误码编码", example = "1234") - private Integer code; - - @Schema(description = "错误码错误提示", example = "帅气") - private String message; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @Schema(description = "创建时间") - private LocalDateTime[] createTime; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeRespVO.java deleted file mode 100644 index 31f72bf930..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeRespVO.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.system.enums.DictTypeConstants; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 错误码 Response VO") -@Data -@ExcelIgnoreUnannotated -public class ErrorCodeRespVO { - - @Schema(description = "错误码编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @ExcelProperty("错误码编号") - private Long id; - - @Schema(description = "错误码类型,参见 ErrorCodeTypeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty(value = "错误码类型", converter = DictConvert.class) - @DictFormat(DictTypeConstants.ERROR_CODE_TYPE) - private Integer type; - - @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard") - @ExcelProperty("应用名") - private String applicationName; - - @Schema(description = "错误码编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1234") - @ExcelProperty("错误码编码") - private Integer code; - - @Schema(description = "错误码错误提示", requiredMode = Schema.RequiredMode.REQUIRED, example = "帅气") - @ExcelProperty("错误码错误提示") - private String message; - - @Schema(description = "备注", example = "哈哈哈") - @ExcelProperty("备注") - private String memo; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeSaveReqVO.java deleted file mode 100644 index 1fd2e0cc94..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/errorcode/vo/ErrorCodeSaveReqVO.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.errorcode.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import jakarta.validation.constraints.NotNull; - -@Schema(description = "管理后台 - 错误码创建/修改 Request VO") -@Data -public class ErrorCodeSaveReqVO { - - @Schema(description = "错误码编号", example = "1024") - private Long id; - - @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "dashboard") - @NotNull(message = "应用名不能为空") - private String applicationName; - - @Schema(description = "错误码编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1234") - @NotNull(message = "错误码编码不能为空") - private Integer code; - - @Schema(description = "错误码错误提示", requiredMode = Schema.RequiredMode.REQUIRED, example = "帅气") - @NotNull(message = "错误码错误提示不能为空") - private String message; - - @Schema(description = "备注", example = "哈哈哈") - private String memo; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/errorcode/ErrorCodeDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/errorcode/ErrorCodeDO.java deleted file mode 100644 index 9ad5633957..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/errorcode/ErrorCodeDO.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.system.dal.dataobject.errorcode; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.system.enums.errorcode.ErrorCodeTypeEnum; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -/** - * 错误码表 - * - * @author 芋道源码 - */ -@TableName(value = "system_error_code") -@KeySequence("system_error_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class ErrorCodeDO extends BaseDO { - - /** - * 错误码编号,自增 - */ - @TableId - private Long id; - /** - * 错误码类型 - * - * 枚举 {@link ErrorCodeTypeEnum} - */ - private Integer type; - /** - * 应用名 - */ - private String applicationName; - /** - * 错误码编码 - */ - private Integer code; - /** - * 错误码错误提示 - */ - private String message; - /** - * 错误码备注 - */ - private String memo; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java deleted file mode 100644 index 2e345e3ad3..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/errorcode/ErrorCodeMapper.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.system.dal.mysql.errorcode; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodePageReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; -import org.apache.ibatis.annotations.Mapper; - -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; - -@Mapper -public interface ErrorCodeMapper extends BaseMapperX { - - default PageResult selectPage(ErrorCodePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(ErrorCodeDO::getType, reqVO.getType()) - .likeIfPresent(ErrorCodeDO::getApplicationName, reqVO.getApplicationName()) - .eqIfPresent(ErrorCodeDO::getCode, reqVO.getCode()) - .likeIfPresent(ErrorCodeDO::getMessage, reqVO.getMessage()) - .betweenIfPresent(ErrorCodeDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(ErrorCodeDO::getCode)); - } - - default List selectListByCodes(Collection codes) { - return selectList(ErrorCodeDO::getCode, codes); - } - - default ErrorCodeDO selectByCode(Integer code) { - return selectOne(ErrorCodeDO::getCode, code); - } - - default List selectListByApplicationNameAndUpdateTimeGt(String applicationName, LocalDateTime minUpdateTime) { - return selectList(new LambdaQueryWrapperX().eq(ErrorCodeDO::getApplicationName, applicationName) - .gtIfPresent(ErrorCodeDO::getUpdateTime, minUpdateTime)); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeService.java deleted file mode 100644 index 1c7db3e315..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeService.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.yudao.module.system.service.errorcode; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodePageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeSaveReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; - -import jakarta.validation.Valid; -import java.time.LocalDateTime; -import java.util.List; - -/** - * 错误码 Service 接口 - * - * @author 芋道源码 - */ -public interface ErrorCodeService { - - /** - * 自动创建错误码 - * - * @param autoGenerateDTOs 错误码信息 - */ - void autoGenerateErrorCodes(@Valid List autoGenerateDTOs); - - /** - * 增量获得错误码数组 - * - * 如果 minUpdateTime 为空时,则获取所有错误码 - * - * @param applicationName 应用名 - * @param minUpdateTime 最小更新时间 - * @return 错误码数组 - */ - List getErrorCodeList(String applicationName, LocalDateTime minUpdateTime); - - /** - * 创建错误码 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createErrorCode(@Valid ErrorCodeSaveReqVO createReqVO); - - /** - * 更新错误码 - * - * @param updateReqVO 更新信息 - */ - void updateErrorCode(@Valid ErrorCodeSaveReqVO updateReqVO); - - /** - * 删除错误码 - * - * @param id 编号 - */ - void deleteErrorCode(Long id); - - /** - * 获得错误码 - * - * @param id 编号 - * @return 错误码 - */ - ErrorCodeDO getErrorCode(Long id); - - /** - * 获得错误码分页 - * - * @param pageReqVO 分页查询 - * @return 错误码分页 - */ - PageResult getErrorCodePage(ErrorCodePageReqVO pageReqVO); - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceImpl.java deleted file mode 100644 index 2664f28714..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package cn.iocoder.yudao.module.system.service.errorcode; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodePageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeSaveReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; -import cn.iocoder.yudao.module.system.dal.mysql.errorcode.ErrorCodeMapper; -import cn.iocoder.yudao.module.system.enums.errorcode.ErrorCodeTypeEnum; -import com.google.common.annotations.VisibleForTesting; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import jakarta.annotation.Resource; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_DUPLICATE; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_NOT_EXISTS; - -/** - * 错误码 Service 实现类 - * - * @author dlyan - */ -@Service -@Validated -@Slf4j -public class ErrorCodeServiceImpl implements ErrorCodeService { - - @Resource - private ErrorCodeMapper errorCodeMapper; - - @Override - public Long createErrorCode(ErrorCodeSaveReqVO createReqVO) { - // 校验 code 重复 - validateCodeDuplicate(createReqVO.getCode(), null); - - // 插入 - ErrorCodeDO errorCode = BeanUtils.toBean(createReqVO, ErrorCodeDO.class) - .setType(ErrorCodeTypeEnum.MANUAL_OPERATION.getType()); - errorCodeMapper.insert(errorCode); - // 返回 - return errorCode.getId(); - } - - @Override - public void updateErrorCode(ErrorCodeSaveReqVO updateReqVO) { - // 校验存在 - validateErrorCodeExists(updateReqVO.getId()); - // 校验 code 重复 - validateCodeDuplicate(updateReqVO.getCode(), updateReqVO.getId()); - - // 更新 - ErrorCodeDO updateObj = BeanUtils.toBean(updateReqVO, ErrorCodeDO.class) - .setType(ErrorCodeTypeEnum.MANUAL_OPERATION.getType()); - errorCodeMapper.updateById(updateObj); - } - - @Override - public void deleteErrorCode(Long id) { - // 校验存在 - validateErrorCodeExists(id); - // 删除 - errorCodeMapper.deleteById(id); - } - - /** - * 校验错误码的唯一字段是否重复 - * - * 是否存在相同编码的错误码 - * - * @param code 错误码编码 - * @param id 错误码编号 - */ - @VisibleForTesting - public void validateCodeDuplicate(Integer code, Long id) { - ErrorCodeDO errorCodeDO = errorCodeMapper.selectByCode(code); - if (errorCodeDO == null) { - return; - } - // 如果 id 为空,说明不用比较是否为相同 id 的错误码 - if (id == null) { - throw exception(ERROR_CODE_DUPLICATE); - } - if (!errorCodeDO.getId().equals(id)) { - throw exception(ERROR_CODE_DUPLICATE); - } - } - - @VisibleForTesting - void validateErrorCodeExists(Long id) { - if (errorCodeMapper.selectById(id) == null) { - throw exception(ERROR_CODE_NOT_EXISTS); - } - } - - @Override - public ErrorCodeDO getErrorCode(Long id) { - return errorCodeMapper.selectById(id); - } - - @Override - public PageResult getErrorCodePage(ErrorCodePageReqVO pageReqVO) { - return errorCodeMapper.selectPage(pageReqVO); - } - - @Override - @Transactional - public void autoGenerateErrorCodes(List autoGenerateDTOs) { - if (CollUtil.isEmpty(autoGenerateDTOs)) { - return; - } - // 获得错误码 - List errorCodeDOs = errorCodeMapper.selectListByCodes( - convertSet(autoGenerateDTOs, ErrorCodeAutoGenerateReqDTO::getCode)); - Map errorCodeDOMap = convertMap(errorCodeDOs, ErrorCodeDO::getCode); - - // 遍历 autoGenerateBOs 数组,逐个插入或更新。考虑到每次量级不大,就不走批量了 - autoGenerateDTOs.forEach(autoGenerateDTO -> { - ErrorCodeDO errorCode = errorCodeDOMap.get(autoGenerateDTO.getCode()); - // 不存在,则进行新增 - if (errorCode == null) { - errorCode = BeanUtils.toBean(autoGenerateDTO, ErrorCodeDO.class) - .setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType()); - errorCodeMapper.insert(errorCode); - return; - } - // 存在,则进行更新。更新有三个前置条件: - // 条件 1. 只更新自动生成的错误码,即 Type 为 ErrorCodeTypeEnum.AUTO_GENERATION - if (!ErrorCodeTypeEnum.AUTO_GENERATION.getType().equals(errorCode.getType())) { - return; - } - // 条件 2. 分组 applicationName 必须匹配,避免存在错误码冲突的情况 - if (!autoGenerateDTO.getApplicationName().equals(errorCode.getApplicationName())) { - log.error("[autoGenerateErrorCodes][自动创建({}/{}) 错误码失败,数据库中已经存在({}/{})]", - autoGenerateDTO.getCode(), autoGenerateDTO.getApplicationName(), - errorCode.getCode(), errorCode.getApplicationName()); - return; - } - // 条件 3. 错误提示语存在差异 - if (autoGenerateDTO.getMessage().equals(errorCode.getMessage())) { - return; - } - // 最终匹配,进行更新 - errorCodeMapper.updateById(new ErrorCodeDO().setId(errorCode.getId()).setMessage(autoGenerateDTO.getMessage())); - }); - } - - @Override - public List getErrorCodeList(String applicationName, LocalDateTime minUpdateTime) { - List list = errorCodeMapper.selectListByApplicationNameAndUpdateTimeGt( - applicationName, minUpdateTime); - return BeanUtils.toBean(list, ErrorCodeRespDTO.class); - } - -} - diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java deleted file mode 100644 index b337e037af..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/errorcode/ErrorCodeServiceTest.java +++ /dev/null @@ -1,308 +0,0 @@ -package cn.iocoder.yudao.module.system.service.errorcode; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeAutoGenerateReqDTO; -import cn.iocoder.yudao.module.system.api.errorcode.dto.ErrorCodeRespDTO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodePageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.errorcode.vo.ErrorCodeSaveReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.errorcode.ErrorCodeDO; -import cn.iocoder.yudao.module.system.dal.mysql.errorcode.ErrorCodeMapper; -import cn.iocoder.yudao.module.system.enums.errorcode.ErrorCodeTypeEnum; -import org.assertj.core.util.Lists; -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Import; - -import jakarta.annotation.Resource; -import java.time.LocalDateTime; -import java.util.List; -import java.util.function.Consumer; - -import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_DUPLICATE; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.ERROR_CODE_NOT_EXISTS; -import static org.junit.jupiter.api.Assertions.*; - -@Import(ErrorCodeServiceImpl.class) -public class ErrorCodeServiceTest extends BaseDbUnitTest { - - @Resource - private ErrorCodeServiceImpl errorCodeService; - - @Resource - private ErrorCodeMapper errorCodeMapper; - - @Test - public void testCreateErrorCode_success() { - // 准备参数 - ErrorCodeSaveReqVO reqVO = randomPojo(ErrorCodeSaveReqVO.class) - .setId(null); // 防止 id 被赋值 - - // 调用 - Long errorCodeId = errorCodeService.createErrorCode(reqVO); - // 断言 - assertNotNull(errorCodeId); - // 校验记录的属性是否正确 - ErrorCodeDO errorCode = errorCodeMapper.selectById(errorCodeId); - assertPojoEquals(reqVO, errorCode, "id"); - assertEquals(ErrorCodeTypeEnum.MANUAL_OPERATION.getType(), errorCode.getType()); - } - - @Test - public void testUpdateErrorCode_success() { - // mock 数据 - ErrorCodeDO dbErrorCode = randomErrorCodeDO(); - errorCodeMapper.insert(dbErrorCode);// @Sql: 先插入出一条存在的数据 - // 准备参数 - ErrorCodeSaveReqVO reqVO = randomPojo(ErrorCodeSaveReqVO.class, o -> { - o.setId(dbErrorCode.getId()); // 设置更新的 ID - }); - - // 调用 - errorCodeService.updateErrorCode(reqVO); - // 校验是否更新正确 - ErrorCodeDO errorCode = errorCodeMapper.selectById(reqVO.getId()); // 获取最新的 - assertPojoEquals(reqVO, errorCode); - assertEquals(ErrorCodeTypeEnum.MANUAL_OPERATION.getType(), errorCode.getType()); - } - - @Test - public void testDeleteErrorCode_success() { - // mock 数据 - ErrorCodeDO dbErrorCode = randomErrorCodeDO(); - errorCodeMapper.insert(dbErrorCode);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbErrorCode.getId(); - - // 调用 - errorCodeService.deleteErrorCode(id); - // 校验数据不存在了 - assertNull(errorCodeMapper.selectById(id)); - } - - @Test - public void testGetErrorCodePage() { - // mock 数据 - ErrorCodeDO dbErrorCode = initGetErrorCodePage(); - // 准备参数 - ErrorCodePageReqVO reqVO = new ErrorCodePageReqVO(); - reqVO.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType()); - reqVO.setApplicationName("tu"); - reqVO.setCode(1); - reqVO.setMessage("ma"); - reqVO.setCreateTime(buildBetweenTime(2020, 11, 1, 2020, 11, 30)); - - // 调用 - PageResult pageResult = errorCodeService.getErrorCodePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbErrorCode, pageResult.getList().get(0)); - } - - /** - * 初始化 getErrorCodePage 方法的测试数据 - */ - private ErrorCodeDO initGetErrorCodePage() { - ErrorCodeDO dbErrorCode = randomErrorCodeDO(o -> { // 等会查询到 - o.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType()); - o.setApplicationName("tudou"); - o.setCode(1); - o.setMessage("yuanma"); - o.setCreateTime(buildTime(2020, 11, 11)); - }); - errorCodeMapper.insert(dbErrorCode); - // 测试 type 不匹配 - errorCodeMapper.insert(cloneIgnoreId(dbErrorCode, o -> o.setType(ErrorCodeTypeEnum.MANUAL_OPERATION.getType()))); - // 测试 applicationName 不匹配 - errorCodeMapper.insert(cloneIgnoreId(dbErrorCode, o -> o.setApplicationName("yuan"))); - // 测试 code 不匹配 - errorCodeMapper.insert(cloneIgnoreId(dbErrorCode, o -> o.setCode(2))); - // 测试 message 不匹配 - errorCodeMapper.insert(cloneIgnoreId(dbErrorCode, o -> o.setMessage("nai"))); - // 测试 createTime 不匹配 - errorCodeMapper.insert(cloneIgnoreId(dbErrorCode, o -> o.setCreateTime(buildTime(2020, 12, 12)))); - return dbErrorCode; - } - - @Test - public void testValidateCodeDuplicate_codeDuplicateForCreate() { - // 准备参数 - Integer code = randomInteger(); - // mock 数据 - errorCodeMapper.insert(randomErrorCodeDO(o -> o.setCode(code))); - - // 调用,校验异常 - assertServiceException(() -> errorCodeService.validateCodeDuplicate(code, null), - ERROR_CODE_DUPLICATE); - } - - @Test - public void testValidateCodeDuplicate_codeDuplicateForUpdate() { - // 准备参数 - Long id = randomLongId(); - Integer code = randomInteger(); - // mock 数据 - errorCodeMapper.insert(randomErrorCodeDO(o -> o.setCode(code))); - - // 调用,校验异常 - assertServiceException(() -> errorCodeService.validateCodeDuplicate(code, id), - ERROR_CODE_DUPLICATE); - } - - @Test - public void testValidateErrorCodeExists_notExists() { - assertServiceException(() -> errorCodeService.validateErrorCodeExists(null), - ERROR_CODE_NOT_EXISTS); - } - - /** - * 情况 1,错误码不存在的情况 - */ - @Test - public void testAutoGenerateErrorCodes_01() { - // 准备参数 - ErrorCodeAutoGenerateReqDTO generateReqDTO = randomPojo(ErrorCodeAutoGenerateReqDTO.class); - // mock 方法 - - // 调用 - errorCodeService.autoGenerateErrorCodes(Lists.newArrayList(generateReqDTO)); - // 断言 - ErrorCodeDO errorCode = errorCodeMapper.selectOne(null); - assertPojoEquals(generateReqDTO, errorCode); - assertEquals(ErrorCodeTypeEnum.AUTO_GENERATION.getType(), errorCode.getType()); - } - - /** - * 情况 2.1,错误码存在,但是是 ErrorCodeTypeEnum.MANUAL_OPERATION 类型 - */ - @Test - public void testAutoGenerateErrorCodes_021() { - // mock 数据 - ErrorCodeDO dbErrorCode = randomErrorCodeDO(o -> o.setType(ErrorCodeTypeEnum.MANUAL_OPERATION.getType())); - errorCodeMapper.insert(dbErrorCode); - // 准备参数 - ErrorCodeAutoGenerateReqDTO generateReqDTO = randomPojo(ErrorCodeAutoGenerateReqDTO.class, - o -> o.setCode(dbErrorCode.getCode())); - // mock 方法 - - // 调用 - errorCodeService.autoGenerateErrorCodes(Lists.newArrayList(generateReqDTO)); - // 断言,相等,说明不会更新 - ErrorCodeDO errorCode = errorCodeMapper.selectById(dbErrorCode.getId()); - assertPojoEquals(dbErrorCode, errorCode); - } - - /** - * 情况 2.2,错误码存在,但是是 applicationName 不匹配 - */ - @Test - public void testAutoGenerateErrorCodes_022() { - // mock 数据 - ErrorCodeDO dbErrorCode = randomErrorCodeDO(o -> o.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType())); - errorCodeMapper.insert(dbErrorCode); - // 准备参数 - ErrorCodeAutoGenerateReqDTO generateReqDTO = randomPojo(ErrorCodeAutoGenerateReqDTO.class, - o -> o.setCode(dbErrorCode.getCode()).setApplicationName(randomString())); - // mock 方法 - - // 调用 - errorCodeService.autoGenerateErrorCodes(Lists.newArrayList(generateReqDTO)); - // 断言,相等,说明不会更新 - ErrorCodeDO errorCode = errorCodeMapper.selectById(dbErrorCode.getId()); - assertPojoEquals(dbErrorCode, errorCode); - } - - /** - * 情况 2.3,错误码存在,但是是 message 相同 - */ - @Test - public void testAutoGenerateErrorCodes_023() { - // mock 数据 - ErrorCodeDO dbErrorCode = randomErrorCodeDO(o -> o.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType())); - errorCodeMapper.insert(dbErrorCode); - // 准备参数 - ErrorCodeAutoGenerateReqDTO generateReqDTO = randomPojo(ErrorCodeAutoGenerateReqDTO.class, - o -> o.setCode(dbErrorCode.getCode()).setApplicationName(dbErrorCode.getApplicationName()) - .setMessage(dbErrorCode.getMessage())); - // mock 方法 - - // 调用 - errorCodeService.autoGenerateErrorCodes(Lists.newArrayList(generateReqDTO)); - // 断言,相等,说明不会更新 - ErrorCodeDO errorCode = errorCodeMapper.selectById(dbErrorCode.getId()); - assertPojoEquals(dbErrorCode, errorCode); - } - - /** - * 情况 2.3,错误码存在,但是是 message 不同,则进行更新 - */ - @Test - public void testAutoGenerateErrorCodes_024() { - // mock 数据 - ErrorCodeDO dbErrorCode = randomErrorCodeDO(o -> o.setType(ErrorCodeTypeEnum.AUTO_GENERATION.getType())); - errorCodeMapper.insert(dbErrorCode); - // 准备参数 - ErrorCodeAutoGenerateReqDTO generateReqDTO = randomPojo(ErrorCodeAutoGenerateReqDTO.class, - o -> o.setCode(dbErrorCode.getCode()).setApplicationName(dbErrorCode.getApplicationName())); - // mock 方法 - - // 调用 - errorCodeService.autoGenerateErrorCodes(Lists.newArrayList(generateReqDTO)); - // 断言,匹配 - ErrorCodeDO errorCode = errorCodeMapper.selectById(dbErrorCode.getId()); - assertPojoEquals(generateReqDTO, errorCode); - } - - @Test - public void testGetErrorCode() { - // 准备参数 - ErrorCodeDO errorCodeDO = randomErrorCodeDO(); - errorCodeMapper.insert(errorCodeDO); - // mock 方法 - Long id = errorCodeDO.getId(); - - // 调用 - ErrorCodeDO dbErrorCode = errorCodeService.getErrorCode(id); - // 断言 - assertPojoEquals(errorCodeDO, dbErrorCode); - } - - @Test - public void testGetErrorCodeList() { - // 准备参数 - ErrorCodeDO errorCodeDO01 = randomErrorCodeDO( - o -> o.setApplicationName("yunai_server").setUpdateTime(buildTime(2022, 1, 10))); - errorCodeMapper.insert(errorCodeDO01); - ErrorCodeDO errorCodeDO02 = randomErrorCodeDO( - o -> o.setApplicationName("yunai_server").setUpdateTime(buildTime(2022, 1, 12))); - errorCodeMapper.insert(errorCodeDO02); - // mock 方法 - String applicationName = "yunai_server"; - LocalDateTime minUpdateTime = buildTime(2022, 1, 11); - - // 调用 - List errorCodeList = errorCodeService.getErrorCodeList(applicationName, minUpdateTime); - // 断言 - assertEquals(1, errorCodeList.size()); - assertPojoEquals(errorCodeDO02, errorCodeList.get(0)); - } - - // ========== 随机对象 ========== - - @SafeVarargs - private static ErrorCodeDO randomErrorCodeDO(Consumer... consumers) { - Consumer consumer = (o) -> { - o.setType(randomEle(ErrorCodeTypeEnum.values()).getType()); // 保证 key 的范围 - }; - return randomPojo(ErrorCodeDO.class, ArrayUtils.append(consumer, consumers)); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql index 55778022ec..8b516869f2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql @@ -16,7 +16,6 @@ DELETE FROM "system_sms_channel"; DELETE FROM "system_sms_template"; DELETE FROM "system_sms_log"; DELETE FROM "system_sms_code"; -DELETE FROM "system_error_code"; DELETE FROM "system_social_client"; DELETE FROM "system_social_user"; DELETE FROM "system_social_user_bind"; diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql index 731b2850e8..9a213ef12d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql @@ -332,21 +332,6 @@ CREATE TABLE IF NOT EXISTS "system_sms_code" ( PRIMARY KEY ("id") ) COMMENT '短信日志'; -CREATE TABLE IF NOT EXISTS "system_error_code" ( - "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "type" tinyint NOT NULL DEFAULT '0', - "application_name" varchar(50) NOT NULL, - "code" int NOT NULL DEFAULT '0', - "message" varchar(512) NOT NULL DEFAULT '', - "memo" varchar(512) DEFAULT '', - "creator" varchar(64) DEFAULT '', - "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updater" varchar(64) DEFAULT '', - "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - "deleted" bit NOT NULL DEFAULT FALSE, - PRIMARY KEY ("id") -) COMMENT '错误码表'; - CREATE TABLE IF NOT EXISTS "system_social_client" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" varchar(255) NOT NULL, diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 555030b576..9917ac9e73 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -227,8 +227,6 @@ yudao: refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 access-log: # 访问日志的配置项 enable: false - error-code: # 错误码相关配置项 - enable: false demo: false # 关闭演示模式 tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index d8d6c493d0..ae336f4293 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -181,14 +181,6 @@ yudao: base-package: ${yudao.info.base-package} db-schemas: ${spring.datasource.dynamic.datasource.master.name} front-type: 10 # 前端模版的类型,参见 CodegenFrontTypeEnum 枚举类 - error-code: # 错误码相关配置项 - constants-class-list: - - cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants - - cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants - - cn.iocoder.yudao.module.member.enums.ErrorCodeConstants - - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants - - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants - - cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants tenant: # 多租户相关配置项 enable: true ignore-urls: From 9a31613e5b766977df62a4977a40ef08bdeefa0b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 22 Apr 2024 19:53:01 +0800 Subject: [PATCH 77/86] =?UTF-8?q?=E3=80=90=E7=A7=BB=E9=99=A4=E3=80=91?= =?UTF-8?q?=E6=95=8F=E6=84=9F=E8=AF=8D=E7=9A=84=E7=AE=A1=E7=90=86=EF=BC=8C?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E9=A1=B9=E7=9B=AE=E7=9A=84=E5=A4=8D=E6=9D=82?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/sensitiveword/SensitiveWordApi.java | 30 -- .../system/enums/ErrorCodeConstants.java | 8 - .../sensitiveword/SensitiveWordApiImpl.java | 29 -- .../SensitiveWordController.http | 4 - .../SensitiveWordController.java | 108 ------- .../vo/SensitiveWordPageReqVO.java | 33 -- .../sensitiveword/vo/SensitiveWordRespVO.java | 45 --- .../sensitiveword/vo/SensitiveWordSaveVO.java | 31 -- .../sensitiveword/SensitiveWordDO.java | 58 ---- .../sensitiveword/SensitiveWordMapper.java | 36 --- .../sensitiveword/SensitiveWordService.java | 89 ----- .../SensitiveWordServiceImpl.java | 262 --------------- .../system/util/collection/SimpleTrie.java | 152 --------- .../SensitiveWordServiceImplTest.java | 303 ------------------ .../src/test/resources/sql/clean.sql | 1 - .../src/test/resources/sql/create_tables.sql | 14 - .../src/main/resources/application-local.yaml | 1 - 17 files changed, 1204 deletions(-) delete mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApi.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApiImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.http delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordRespVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordSaveVO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordService.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/collection/SimpleTrie.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApi.java deleted file mode 100644 index 951cfbc6f4..0000000000 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApi.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.system.api.sensitiveword; - -import java.util.List; - -/** - * 敏感词 API 接口 - * - * @author 永不言败 - */ -public interface SensitiveWordApi { - - /** - * 获得文本所包含的不合法的敏感词数组 - * - * @param text 文本 - * @param tags 标签数组 - * @return 不合法的敏感词数组 - */ - List validateText(String text, List tags); - - /** - * 判断文本是否包含敏感词 - * - * @param text 文本 - * @param tags 表述数组 - * @return 是否包含 - */ - boolean isTextValid(String text, List tags); - -} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 481c9be54c..1b4c313c83 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -115,10 +115,6 @@ public interface ErrorCodeConstants { ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "租户正在使用该套餐,请给租户重新设置套餐后再尝试删除"); ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用"); - // ========== 错误码模块 1-002-017-000 ========== - ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1_002_017_000, "错误码不存在"); - ErrorCode ERROR_CODE_DUPLICATE = new ErrorCode(1_002_017_001, "已经存在编码为【{}】的错误码"); - // ========== 社交用户 1-002-018-000 ========== ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}"); ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户"); @@ -127,10 +123,6 @@ public interface ErrorCodeConstants { ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_201, "社交客户端不存在"); ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_202, "社交客户端已存在配置"); - // ========== 系统敏感词 1-002-019-000 ========= - ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1_002_019_000, "系统敏感词在所有标签中都不存在"); - ErrorCode SENSITIVE_WORD_EXISTS = new ErrorCode(1_002_019_001, "系统敏感词已在标签中存在"); - // ========== OAuth2 客户端 1-002-020-000 ========= ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在"); ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在"); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApiImpl.java deleted file mode 100644 index 9dc25e4b8b..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/sensitiveword/SensitiveWordApiImpl.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.system.api.sensitiveword; - -import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import java.util.List; - -/** - * 敏感词 API 实现类 - * - * @author 永不言败 - */ -@Service -public class SensitiveWordApiImpl implements SensitiveWordApi { - - @Resource - private SensitiveWordService sensitiveWordService; - - @Override - public List validateText(String text, List tags) { - return sensitiveWordService.validateText(text, tags); - } - - @Override - public boolean isTextValid(String text, List tags) { - return sensitiveWordService.isTextValid(text, tags); - } -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.http deleted file mode 100644 index cd97d2de5c..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.http +++ /dev/null @@ -1,4 +0,0 @@ -### 请求 /system/sensitive-word/validate-text 接口 => 成功 -GET {{baseUrl}}/system/sensitive-word/validate-text?text=XXX&tags=短信&tags=蔬菜 -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java deleted file mode 100644 index 15da9d9529..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/SensitiveWordController.java +++ /dev/null @@ -1,108 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.sensitiveword; - -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordRespVO; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO; -import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; -import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.io.IOException; -import java.util.List; -import java.util.Set; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - 敏感词") -@RestController -@RequestMapping("/system/sensitive-word") -@Validated -public class SensitiveWordController { - - @Resource - private SensitiveWordService sensitiveWordService; - - @PostMapping("/create") - @Operation(summary = "创建敏感词") - @PreAuthorize("@ss.hasPermission('system:sensitive-word:create')") - public CommonResult createSensitiveWord(@Valid @RequestBody SensitiveWordSaveVO createReqVO) { - return success(sensitiveWordService.createSensitiveWord(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新敏感词") - @PreAuthorize("@ss.hasPermission('system:sensitive-word:update')") - public CommonResult updateSensitiveWord(@Valid @RequestBody SensitiveWordSaveVO updateReqVO) { - sensitiveWordService.updateSensitiveWord(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除敏感词") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('system:sensitive-word:delete')") - public CommonResult deleteSensitiveWord(@RequestParam("id") Long id) { - sensitiveWordService.deleteSensitiveWord(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得敏感词") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')") - public CommonResult getSensitiveWord(@RequestParam("id") Long id) { - SensitiveWordDO sensitiveWord = sensitiveWordService.getSensitiveWord(id); - return success(BeanUtils.toBean(sensitiveWord, SensitiveWordRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得敏感词分页") - @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')") - public CommonResult> getSensitiveWordPage(@Valid SensitiveWordPageReqVO pageVO) { - PageResult pageResult = sensitiveWordService.getSensitiveWordPage(pageVO); - return success(BeanUtils.toBean(pageResult, SensitiveWordRespVO.class)); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出敏感词 Excel") - @PreAuthorize("@ss.hasPermission('system:sensitive-word:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportSensitiveWordExcel(@Valid SensitiveWordPageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = sensitiveWordService.getSensitiveWordPage(exportReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "敏感词.xls", "数据", SensitiveWordRespVO.class, - BeanUtils.toBean(list, SensitiveWordRespVO.class)); - } - - @GetMapping("/get-tags") - @Operation(summary = "获取所有敏感词的标签数组") - @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')") - public CommonResult> getSensitiveWordTagSet() { - return success(sensitiveWordService.getSensitiveWordTagSet()); - } - - @GetMapping("/validate-text") - @Operation(summary = "获得文本所包含的不合法的敏感词数组") - public CommonResult> validateText(@RequestParam("text") String text, - @RequestParam(value = "tags", required = false) List tags) { - return success(sensitiveWordService.validateText(text, tags)); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java deleted file mode 100644 index 642773a551..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordPageReqVO.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - 敏感词分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class SensitiveWordPageReqVO extends PageParam { - - @Schema(description = "敏感词", example = "敏感词") - private String name; - - @Schema(description = "标签", example = "短信,评论") - private String tag; - - @Schema(description = "状态,参见 CommonStatusEnum 枚举类", example = "1") - private Integer status; - - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @Schema(description = "创建时间") - private LocalDateTime[] createTime; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordRespVO.java deleted file mode 100644 index 43d041ecc5..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordRespVO.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.framework.excel.core.convert.JsonConvert; -import cn.iocoder.yudao.module.system.enums.DictTypeConstants; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import java.time.LocalDateTime; -import java.util.List; - -@Schema(description = "管理后台 - 敏感词 Response VO") -@Data -public class SensitiveWordRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("编号") - private Long id; - - @Schema(description = "敏感词", requiredMode = Schema.RequiredMode.REQUIRED, example = "敏感词") - @ExcelProperty("敏感词") - private String name; - - @Schema(description = "标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "短信,评论") - @ExcelProperty(value = "标签", converter = JsonConvert.class) - private List tags; - - @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty(value = "状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.COMMON_STATUS) - private Integer status; - - @Schema(description = "描述", example = "污言秽语") - @ExcelProperty("描述") - private String description; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordSaveVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordSaveVO.java deleted file mode 100644 index 452086d7c9..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordSaveVO.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import jakarta.validation.constraints.NotNull; -import java.util.List; - -@Schema(description = "管理后台 - 敏感词创建/修改 Request VO") -@Data -public class SensitiveWordSaveVO { - - @Schema(description = "编号", example = "1") - private Long id; - - @Schema(description = "敏感词", requiredMode = Schema.RequiredMode.REQUIRED, example = "敏感词") - @NotNull(message = "敏感词不能为空") - private String name; - - @Schema(description = "标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "短信,评论") - @NotNull(message = "标签不能为空") - private List tags; - - @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "状态不能为空") - private Integer status; - - @Schema(description = "描述", example = "污言秽语") - private String description; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java deleted file mode 100644 index 37dc57968a..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.util.List; - -/** - * 敏感词 DO - * - * @author 永不言败 - */ -@TableName(value = "system_sensitive_word", autoResultMap = true) -@KeySequence("system_sensitive_word_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class SensitiveWordDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 敏感词 - */ - private String name; - /** - * 描述 - */ - private String description; - /** - * 标签数组 - * - * 用于实现不同的业务场景下,需要使用不同标签的敏感词。 - * 例如说,tag 有短信、论坛两种,敏感词 "推广" 在短信下是敏感词,在论坛下不是敏感词。 - * 此时,我们会存储一条敏感词记录,它的 name 为"推广",tag 为短信。 - */ - @TableField(typeHandler = StringListTypeHandler.class) - private List tags; - /** - * 状态 - * - * 枚举 {@link CommonStatusEnum} - */ - private Integer status; - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java deleted file mode 100644 index f4bf8cc691..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.yudao.module.system.dal.mysql.sensitiveword; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Select; - -import java.time.LocalDateTime; - -/** - * 敏感词 Mapper - * - * @author 永不言败 - */ -@Mapper -public interface SensitiveWordMapper extends BaseMapperX { - - default PageResult selectPage(SensitiveWordPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(SensitiveWordDO::getName, reqVO.getName()) - .likeIfPresent(SensitiveWordDO::getTags, reqVO.getTag()) - .eqIfPresent(SensitiveWordDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(SensitiveWordDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(SensitiveWordDO::getId)); - } - default SensitiveWordDO selectByName(String name) { - return selectOne(SensitiveWordDO::getName, name); - } - - @Select("SELECT COUNT(*) FROM system_sensitive_word WHERE update_time > #{maxUpdateTime}") - Long selectCountByUpdateTimeGt(LocalDateTime maxTime); - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordService.java deleted file mode 100644 index 0dd71d9701..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordService.java +++ /dev/null @@ -1,89 +0,0 @@ -package cn.iocoder.yudao.module.system.service.sensitiveword; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO; -import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; - -import jakarta.validation.Valid; -import java.util.List; -import java.util.Set; - -/** - * 敏感词 Service 接口 - * - * @author 永不言败 - */ -public interface SensitiveWordService { - - /** - * 创建敏感词 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createSensitiveWord(@Valid SensitiveWordSaveVO createReqVO); - - /** - * 更新敏感词 - * - * @param updateReqVO 更新信息 - */ - void updateSensitiveWord(@Valid SensitiveWordSaveVO updateReqVO); - - /** - * 删除敏感词 - * - * @param id 编号 - */ - void deleteSensitiveWord(Long id); - - /** - * 获得敏感词 - * - * @param id 编号 - * @return 敏感词 - */ - SensitiveWordDO getSensitiveWord(Long id); - - /** - * 获得敏感词列表 - * - * @return 敏感词列表 - */ - List getSensitiveWordList(); - - /** - * 获得敏感词分页 - * - * @param pageReqVO 分页查询 - * @return 敏感词分页 - */ - PageResult getSensitiveWordPage(SensitiveWordPageReqVO pageReqVO); - - /** - * 获得所有敏感词的标签数组 - * - * @return 标签数组 - */ - Set getSensitiveWordTagSet(); - - /** - * 获得文本所包含的不合法的敏感词数组 - * - * @param text 文本 - * @param tags 标签数组 - * @return 不合法的敏感词数组 - */ - List validateText(String text, List tags); - - /** - * 判断文本是否包含敏感词 - * - * @param text 文本 - * @param tags 标签数组 - * @return 是否包含敏感词 - */ - boolean isTextValid(String text, List tags); - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java deleted file mode 100644 index f6910e8ec8..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java +++ /dev/null @@ -1,262 +0,0 @@ -package cn.iocoder.yudao.module.system.service.sensitiveword; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO; -import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; -import cn.iocoder.yudao.module.system.dal.mysql.sensitiveword.SensitiveWordMapper; -import cn.iocoder.yudao.module.system.util.collection.SimpleTrie; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; -import org.springframework.validation.annotation.Validated; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import java.time.LocalDateTime; -import java.util.*; -import java.util.concurrent.TimeUnit; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_EXISTS; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_NOT_EXISTS; - -/** - * 敏感词 Service 实现类 - * - * @author 永不言败 - */ -@Service -@Slf4j -@Validated -public class SensitiveWordServiceImpl implements SensitiveWordService { - - /** - * 是否开启敏感词功能 - */ - public static Boolean ENABLED = false; - - /** - * 敏感词列表缓存 - */ - @Getter - private volatile List sensitiveWordCache = Collections.emptyList(); - /** - * 敏感词标签缓存 - * key:敏感词编号 {@link SensitiveWordDO#getId()} - *

- * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 - */ - @Getter - private volatile Set sensitiveWordTagsCache = Collections.emptySet(); - - @Resource - private SensitiveWordMapper sensitiveWordMapper; - - /** - * 默认的敏感词的字典树,包含所有敏感词 - */ - @Getter - private volatile SimpleTrie defaultSensitiveWordTrie = new SimpleTrie(Collections.emptySet()); - /** - * 标签与敏感词的字段数的映射 - */ - @Getter - private volatile Map tagSensitiveWordTries = Collections.emptyMap(); - - /** - * 初始化缓存 - */ - @PostConstruct - public void initLocalCache() { - if (!ENABLED) { - return; - } - - // 第一步:查询数据 - List sensitiveWords = sensitiveWordMapper.selectList(); - log.info("[initLocalCache][缓存敏感词,数量为:{}]", sensitiveWords.size()); - - // 第二步:构建缓存 - // 写入 sensitiveWordTagsCache 缓存 - Set tags = new HashSet<>(); - sensitiveWords.forEach(word -> tags.addAll(word.getTags())); - sensitiveWordTagsCache = tags; - sensitiveWordCache = sensitiveWords; - // 写入 defaultSensitiveWordTrie、tagSensitiveWordTries 缓存 - initSensitiveWordTrie(sensitiveWords); - } - - private void initSensitiveWordTrie(List wordDOs) { - // 过滤禁用的敏感词 - wordDOs = filterList(wordDOs, word -> word.getStatus().equals(CommonStatusEnum.ENABLE.getStatus())); - - // 初始化默认的 defaultSensitiveWordTrie - this.defaultSensitiveWordTrie = new SimpleTrie(CollectionUtils.convertList(wordDOs, SensitiveWordDO::getName)); - - // 初始化 tagSensitiveWordTries - Multimap tagWords = HashMultimap.create(); - for (SensitiveWordDO word : wordDOs) { - if (CollUtil.isEmpty(word.getTags())) { - continue; - } - word.getTags().forEach(tag -> tagWords.put(tag, word.getName())); - } - // 添加到 tagSensitiveWordTries 中 - Map tagSensitiveWordTries = new HashMap<>(); - tagWords.asMap().forEach((tag, words) -> tagSensitiveWordTries.put(tag, new SimpleTrie(words))); - this.tagSensitiveWordTries = tagSensitiveWordTries; - } - - /** - * 通过定时任务轮询,刷新缓存 - * - * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新 - */ - @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) - public void refreshLocalCache() { - // 情况一:如果缓存里没有数据,则直接刷新缓存 - if (CollUtil.isEmpty(sensitiveWordCache)) { - initLocalCache(); - return; - } - - // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 - LocalDateTime maxTime = getMaxValue(sensitiveWordCache, SensitiveWordDO::getUpdateTime); - if (sensitiveWordMapper.selectCountByUpdateTimeGt(maxTime) > 0) { - initLocalCache(); - } - } - - @Override - public Long createSensitiveWord(SensitiveWordSaveVO createReqVO) { - // 校验唯一性 - validateSensitiveWordNameUnique(null, createReqVO.getName()); - - // 插入 - SensitiveWordDO sensitiveWord = BeanUtils.toBean(createReqVO, SensitiveWordDO.class); - sensitiveWordMapper.insert(sensitiveWord); - - // 刷新缓存 - initLocalCache(); - return sensitiveWord.getId(); - } - - @Override - public void updateSensitiveWord(SensitiveWordSaveVO updateReqVO) { - // 校验唯一性 - validateSensitiveWordExists(updateReqVO.getId()); - validateSensitiveWordNameUnique(updateReqVO.getId(), updateReqVO.getName()); - - // 更新 - SensitiveWordDO updateObj = BeanUtils.toBean(updateReqVO, SensitiveWordDO.class); - sensitiveWordMapper.updateById(updateObj); - - // 刷新缓存 - initLocalCache(); - } - - @Override - public void deleteSensitiveWord(Long id) { - // 校验存在 - validateSensitiveWordExists(id); - // 删除 - sensitiveWordMapper.deleteById(id); - - // 刷新缓存 - initLocalCache(); - } - - private void validateSensitiveWordNameUnique(Long id, String name) { - SensitiveWordDO word = sensitiveWordMapper.selectByName(name); - if (word == null) { - return; - } - // 如果 id 为空,说明不用比较是否为相同 id 的敏感词 - if (id == null) { - throw exception(SENSITIVE_WORD_EXISTS); - } - if (!word.getId().equals(id)) { - throw exception(SENSITIVE_WORD_EXISTS); - } - } - - private void validateSensitiveWordExists(Long id) { - if (sensitiveWordMapper.selectById(id) == null) { - throw exception(SENSITIVE_WORD_NOT_EXISTS); - } - } - - @Override - public SensitiveWordDO getSensitiveWord(Long id) { - return sensitiveWordMapper.selectById(id); - } - - @Override - public List getSensitiveWordList() { - return sensitiveWordMapper.selectList(); - } - - @Override - public PageResult getSensitiveWordPage(SensitiveWordPageReqVO pageReqVO) { - return sensitiveWordMapper.selectPage(pageReqVO); - } - - @Override - public Set getSensitiveWordTagSet() { - return sensitiveWordTagsCache; - } - - @Override - public List validateText(String text, List tags) { - Assert.isTrue(ENABLED, "敏感词功能未开启,请将 ENABLED 设置为 true"); - - // 无标签时,默认所有 - if (CollUtil.isEmpty(tags)) { - return defaultSensitiveWordTrie.validate(text); - } - // 有标签的情况 - Set result = new HashSet<>(); - tags.forEach(tag -> { - SimpleTrie trie = tagSensitiveWordTries.get(tag); - if (trie == null) { - return; - } - result.addAll(trie.validate(text)); - }); - return new ArrayList<>(result); - } - - @Override - public boolean isTextValid(String text, List tags) { - Assert.isTrue(ENABLED, "敏感词功能未开启,请将 ENABLED 设置为 true"); - - // 无标签时,默认所有 - if (CollUtil.isEmpty(tags)) { - return defaultSensitiveWordTrie.isValid(text); - } - // 有标签的情况 - for (String tag : tags) { - SimpleTrie trie = tagSensitiveWordTries.get(tag); - if (trie == null) { - continue; - } - // 如果有一个标签不合法,则返回 false 不合法 - if (!trie.isValid(text)) { - return false; - } - } - return true; - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/collection/SimpleTrie.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/collection/SimpleTrie.java deleted file mode 100644 index 8c3e4bc0fa..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/collection/SimpleTrie.java +++ /dev/null @@ -1,152 +0,0 @@ -package cn.iocoder.yudao.module.system.util.collection; - -import cn.hutool.core.collection.CollUtil; - -import java.util.*; - -/** - * 基于前缀树,实现敏感词的校验 - *

- * 相比 Apache Common 提供的 PatriciaTrie 来说,性能可能会更加好一些。 - * - * @author 芋道源码 - */ -@SuppressWarnings("unchecked") -public class SimpleTrie { - - /** - * 一个敏感词结束后对应的 key - */ - private static final Character CHARACTER_END = '\0'; - - /** - * 使用敏感词,构建的前缀树 - */ - private final Map children; - - /** - * 基于字符串,构建前缀树 - * - * @param strs 字符串数组 - */ - public SimpleTrie(Collection strs) { - // 排序,优先使用较短的前缀 - strs = CollUtil.sort(strs, String::compareTo); - // 构建树 - children = new HashMap<>(); - for (String str : strs) { - Map child = children; - // 遍历每个字符 - for (Character c : str.toCharArray()) { - // 如果已经到达结束,就没必要在添加更长的敏感词。 - // 例如说,有两个敏感词是:吃饭啊、吃饭。输入一句话是 “我要吃饭啊”,则只要匹配到 “吃饭” 这个敏感词即可。 - if (child.containsKey(CHARACTER_END)) { - break; - } - if (!child.containsKey(c)) { - child.put(c, new HashMap<>()); - } - child = (Map) child.get(c); - } - // 结束 - child.put(CHARACTER_END, null); - } - } - - /** - * 验证文本是否合法,即不包含敏感词 - * - * @param text 文本 - * @return 是否 true-合法 false-不合法 - */ - public boolean isValid(String text) { - // 遍历 text,使用每一个 [i, n) 段的字符串,使用 children 前缀树匹配,是否包含敏感词 - for (int i = 0; i < text.length(); i++) { - Map child = (Map) children.get(text.charAt(i)); - if (child == null) { - continue; - } - boolean ok = recursion(text, i + 1, child); - if (!ok) { - return false; - } - } - return true; - } - - /** - * 验证文本从指定位置开始,是否不包含某个敏感词 - * - * @param text 文本 - * @param index 开始位置 - * @param child 节点(当前遍历到的) - * @return 是否不包含 true-不包含 false-包含 - */ - private boolean recursion(String text, int index, Map child) { - if (child.containsKey(CHARACTER_END)) { - return false; - } - if (index == text.length()) { - return true; - } - child = (Map) child.get(text.charAt(index)); - return child == null || !child.containsKey(CHARACTER_END) && recursion(text, ++index, child); - } - - /** - * 获得文本所包含的不合法的敏感词 - * - * 注意,才当即最短匹配原则。例如说:当敏感词存在 “煞笔”,“煞笔二货 ”时,只会返回 “煞笔”。 - * - * @param text 文本 - * @return 匹配的敏感词 - */ - public List validate(String text) { - Set results = new HashSet<>(); - for (int i = 0; i < text.length(); i++) { - Character c = text.charAt(i); - Map child = (Map) children.get(c); - if (child == null) { - continue; - } - StringBuilder result = new StringBuilder().append(c); - boolean ok = recursionWithResult(text, i + 1, child, result); - if (!ok) { - results.add(result.toString()); - } - } - return new ArrayList<>(results); - } - - /** - * 返回文本从 index 开始的敏感词,并使用 StringBuilder 参数进行返回 - * - * 逻辑和 {@link #recursion(String, int, Map)} 是一致,只是多了 result 返回结果 - * - * @param text 文本 - * @param index 开始未知 - * @param child 节点(当前遍历到的) - * @param result 返回敏感词 - * @return 是否有敏感词 - */ - @SuppressWarnings("unchecked") - private static boolean recursionWithResult(String text, int index, Map child, StringBuilder result) { - if (child.containsKey(CHARACTER_END)) { - return false; - } - if (index == text.length()) { - return true; - } - Character c = text.charAt(index); - child = (Map) child.get(c); - if (child == null) { - return true; - } - if (child.containsKey(CHARACTER_END)) { - result.append(c); - return false; - } - return recursionWithResult(text, ++index, child, result.append(c)); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java deleted file mode 100644 index ed5c896342..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java +++ /dev/null @@ -1,303 +0,0 @@ -package cn.iocoder.yudao.module.system.service.sensitiveword; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO; -import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; -import cn.iocoder.yudao.module.system.dal.mysql.sensitiveword.SensitiveWordMapper; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Import; - -import jakarta.annotation.Resource; -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_NOT_EXISTS; -import static java.util.Collections.singletonList; -import static org.junit.jupiter.api.Assertions.*; - -/** - * {@link SensitiveWordServiceImpl} 的单元测试类 - * - * @author 永不言败 - */ -@Import(SensitiveWordServiceImpl.class) -public class SensitiveWordServiceImplTest extends BaseDbUnitTest { - - @Resource - private SensitiveWordServiceImpl sensitiveWordService; - - @Resource - private SensitiveWordMapper sensitiveWordMapper; - - @BeforeEach - public void setUp() { - SensitiveWordServiceImpl.ENABLED = true; - } - - @Test - public void testInitLocalCache() { - SensitiveWordDO wordDO1 = randomPojo(SensitiveWordDO.class, o -> o.setName("傻瓜") - .setTags(singletonList("论坛")).setStatus(CommonStatusEnum.ENABLE.getStatus())); - sensitiveWordMapper.insert(wordDO1); - SensitiveWordDO wordDO2 = randomPojo(SensitiveWordDO.class, o -> o.setName("笨蛋") - .setTags(singletonList("蔬菜")).setStatus(CommonStatusEnum.ENABLE.getStatus())); - sensitiveWordMapper.insert(wordDO2); - SensitiveWordDO wordDO3 = randomPojo(SensitiveWordDO.class, o -> o.setName("白") - .setTags(singletonList("测试")).setStatus(CommonStatusEnum.ENABLE.getStatus())); - sensitiveWordMapper.insert(wordDO3); - SensitiveWordDO wordDO4 = randomPojo(SensitiveWordDO.class, o -> o.setName("白痴") - .setTags(singletonList("测试")).setStatus(CommonStatusEnum.ENABLE.getStatus())); - sensitiveWordMapper.insert(wordDO4); - - // 调用 - sensitiveWordService.initLocalCache(); - // 断言 sensitiveWordTagsCache 缓存 - assertEquals(SetUtils.asSet("论坛", "蔬菜", "测试"), sensitiveWordService.getSensitiveWordTagSet()); - // 断言 sensitiveWordCache - assertEquals(4, sensitiveWordService.getSensitiveWordCache().size()); - assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0)); - assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1)); - assertPojoEquals(wordDO3, sensitiveWordService.getSensitiveWordCache().get(2)); - // 断言 tagSensitiveWordTries 缓存 - assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie()); - assertEquals(3, sensitiveWordService.getTagSensitiveWordTries().size()); - assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("论坛")); - assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("蔬菜")); - assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("测试")); - } - - @Test - public void testRefreshLocalCache() { - // mock 数据 - SensitiveWordDO wordDO1 = randomPojo(SensitiveWordDO.class, o -> o.setName("傻瓜") - .setTags(singletonList("论坛")).setStatus(CommonStatusEnum.ENABLE.getStatus())); - wordDO1.setUpdateTime(LocalDateTime.now()); - sensitiveWordMapper.insert(wordDO1); - sensitiveWordService.initLocalCache(); - // mock 数据 ② - SensitiveWordDO wordDO2 = randomPojo(SensitiveWordDO.class, o -> o.setName("笨蛋") - .setTags(singletonList("蔬菜")).setStatus(CommonStatusEnum.ENABLE.getStatus())); - wordDO2.setUpdateTime(LocalDateTimeUtils.addTime(Duration.ofMinutes(1))); // 避免时间相同 - sensitiveWordMapper.insert(wordDO2); - - // 调用 - sensitiveWordService.refreshLocalCache(); - // 断言 sensitiveWordTagsCache 缓存 - assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTagSet()); - // 断言 sensitiveWordCache - assertEquals(2, sensitiveWordService.getSensitiveWordCache().size()); - assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0)); - assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1)); - // 断言 tagSensitiveWordTries 缓存 - assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie()); - assertEquals(2, sensitiveWordService.getTagSensitiveWordTries().size()); - assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("论坛")); - assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("蔬菜")); - } - - @Test - public void testCreateSensitiveWord_success() { - // 准备参数 - SensitiveWordSaveVO reqVO = randomPojo(SensitiveWordSaveVO.class) - .setId(null); // 防止 id 被赋值 - - // 调用 - Long sensitiveWordId = sensitiveWordService.createSensitiveWord(reqVO); - // 断言 - assertNotNull(sensitiveWordId); - // 校验记录的属性是否正确 - SensitiveWordDO sensitiveWord = sensitiveWordMapper.selectById(sensitiveWordId); - assertPojoEquals(reqVO, sensitiveWord, "id"); - } - - @Test - public void testUpdateSensitiveWord_success() { - // mock 数据 - SensitiveWordDO dbSensitiveWord = randomPojo(SensitiveWordDO.class); - sensitiveWordMapper.insert(dbSensitiveWord);// @Sql: 先插入出一条存在的数据 - // 准备参数 - SensitiveWordSaveVO reqVO = randomPojo(SensitiveWordSaveVO.class, o -> { - o.setId(dbSensitiveWord.getId()); // 设置更新的 ID - }); - - // 调用 - sensitiveWordService.updateSensitiveWord(reqVO); - // 校验是否更新正确 - SensitiveWordDO sensitiveWord = sensitiveWordMapper.selectById(reqVO.getId()); // 获取最新的 - assertPojoEquals(reqVO, sensitiveWord); - } - - @Test - public void testUpdateSensitiveWord_notExists() { - // 准备参数 - SensitiveWordSaveVO reqVO = randomPojo(SensitiveWordSaveVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> sensitiveWordService.updateSensitiveWord(reqVO), SENSITIVE_WORD_NOT_EXISTS); - } - - @Test - public void testDeleteSensitiveWord_success() { - // mock 数据 - SensitiveWordDO dbSensitiveWord = randomPojo(SensitiveWordDO.class); - sensitiveWordMapper.insert(dbSensitiveWord);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbSensitiveWord.getId(); - - // 调用 - sensitiveWordService.deleteSensitiveWord(id); - // 校验数据不存在了 - assertNull(sensitiveWordMapper.selectById(id)); - } - - @Test - public void testDeleteSensitiveWord_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> sensitiveWordService.deleteSensitiveWord(id), SENSITIVE_WORD_NOT_EXISTS); - } - - @Test - public void testGetSensitiveWord() { - // mock 数据 - SensitiveWordDO sensitiveWord = randomPojo(SensitiveWordDO.class); - sensitiveWordMapper.insert(sensitiveWord); - // 准备参数 - Long id = sensitiveWord.getId(); - - // 调用 - SensitiveWordDO dbSensitiveWord = sensitiveWordService.getSensitiveWord(id); - // 断言 - assertPojoEquals(sensitiveWord, dbSensitiveWord); - } - - @Test - public void testGetSensitiveWordList() { - // mock 数据 - SensitiveWordDO sensitiveWord01 = randomPojo(SensitiveWordDO.class); - sensitiveWordMapper.insert(sensitiveWord01); - SensitiveWordDO sensitiveWord02 = randomPojo(SensitiveWordDO.class); - sensitiveWordMapper.insert(sensitiveWord02); - - // 调用 - List list = sensitiveWordService.getSensitiveWordList(); - // 断言 - assertEquals(2, list.size()); - assertEquals(sensitiveWord01, list.get(0)); - assertEquals(sensitiveWord02, list.get(1)); - } - - @Test - public void testGetSensitiveWordPage() { - // mock 数据 - SensitiveWordDO dbSensitiveWord = randomPojo(SensitiveWordDO.class, o -> { // 等会查询到 - o.setName("笨蛋"); - o.setTags(Arrays.asList("论坛", "蔬菜")); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setCreateTime(buildTime(2022, 2, 8)); - }); - sensitiveWordMapper.insert(dbSensitiveWord); - // 测试 name 不匹配 - sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setName("傻瓜"))); - // 测试 tags 不匹配 - sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setTags(Arrays.asList("短信", "日用品")))); - // 测试 createTime 不匹配 - sensitiveWordMapper.insert(cloneIgnoreId(dbSensitiveWord, o -> o.setCreateTime(buildTime(2022, 2, 16)))); - // 准备参数 - SensitiveWordPageReqVO reqVO = new SensitiveWordPageReqVO(); - reqVO.setName("笨"); - reqVO.setTag("论坛"); - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 12)); - - // 调用 - PageResult pageResult = sensitiveWordService.getSensitiveWordPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbSensitiveWord, pageResult.getList().get(0)); - } - - @Test - public void testValidateText_noTag() { - testInitLocalCache(); - // 准备参数 - String text = "你是傻瓜,你是笨蛋"; - // 调用 - List result = sensitiveWordService.validateText(text, null); - // 断言 - assertEquals(Arrays.asList("傻瓜", "笨蛋"), result); - - // 准备参数 - String text2 = "你是傻瓜,你是笨蛋,你是白"; - // 调用 - List result2 = sensitiveWordService.validateText(text2, null); - // 断言 - assertEquals(Arrays.asList("傻瓜", "笨蛋","白"), result2); - } - - @Test - public void testValidateText_hasTag() { - testInitLocalCache(); - // 准备参数 - String text = "你是傻瓜,你是笨蛋"; - // 调用 - List result = sensitiveWordService.validateText(text, singletonList("论坛")); - // 断言 - assertEquals(singletonList("傻瓜"), result); - - - // 准备参数 - String text2 = "你是白"; - // 调用 - List result2 = sensitiveWordService.validateText(text2, singletonList("测试")); - // 断言 - assertEquals(singletonList("白"), result2); - } - - @Test - public void testIsTestValid_noTag() { - testInitLocalCache(); - // 准备参数 - String text = "你是傻瓜,你是笨蛋"; - // 调用,断言 - assertFalse(sensitiveWordService.isTextValid(text, null)); - - // 准备参数 - String text2 = "你是白"; - // 调用,断言 - assertFalse(sensitiveWordService.isTextValid(text2, null)); - } - - @Test - public void testIsTestValid_hasTag() { - testInitLocalCache(); - // 准备参数 - String text = "你是傻瓜,你是笨蛋"; - // 调用,断言 - assertFalse(sensitiveWordService.isTextValid(text, singletonList("论坛"))); - - // 准备参数 - String text2 = "你是白"; - // 调用,断言 - assertFalse(sensitiveWordService.isTextValid(text2, singletonList("测试"))); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql index 8b516869f2..e7946a105f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/clean.sql @@ -21,7 +21,6 @@ DELETE FROM "system_social_user"; DELETE FROM "system_social_user_bind"; DELETE FROM "system_tenant"; DELETE FROM "system_tenant_package"; -DELETE FROM "system_sensitive_word"; DELETE FROM "system_oauth2_client"; DELETE FROM "system_oauth2_approve"; DELETE FROM "system_oauth2_access_token"; diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql index 9a213ef12d..8f1ac5e0a0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql @@ -416,20 +416,6 @@ CREATE TABLE IF NOT EXISTS "system_tenant_package" ( PRIMARY KEY ("id") ) COMMENT '租户套餐表'; -CREATE TABLE IF NOT EXISTS "system_sensitive_word" ( - "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "name" varchar(255) NOT NULL, - "tags" varchar(1024) NOT NULL, - "status" bit NOT NULL DEFAULT FALSE, - "description" varchar(512), - "creator" varchar(64) DEFAULT '', - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updater" varchar(64) DEFAULT '', - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - "deleted" bit NOT NULL DEFAULT FALSE, - PRIMARY KEY ("id") -) COMMENT '系统敏感词'; - CREATE TABLE IF NOT EXISTS "system_oauth2_client" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "client_id" varchar NOT NULL, diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 9917ac9e73..328e9c27b9 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -170,7 +170,6 @@ logging: cn.iocoder.yudao.module.pay.dal.mysql: debug cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 JobLogMapper 的日志级别为 info cn.iocoder.yudao.module.system.dal.mysql: debug - cn.iocoder.yudao.module.system.dal.mysql.sensitiveword.SensitiveWordMapper: INFO # 配置 SensitiveWordMapper 的日志级别为 info cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 配置 SmsChannelMapper 的日志级别为 info cn.iocoder.yudao.module.tool.dal.mysql: debug cn.iocoder.yudao.module.member.dal.mysql: debug From 075157417c90218244e0c369eb15cf20ad912536 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 22 Apr 2024 21:00:02 +0800 Subject: [PATCH 78/86] =?UTF-8?q?=E6=B8=85=E7=90=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=9A=E6=97=A0=E7=94=A8=E7=9A=84=20test-integration=20?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=EF=BC=8C=E6=9A=82=E6=97=B6=E4=B8=8D=E8=80=83?= =?UTF-8?q?=E8=99=91=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/cache/CacheUtils.java | 34 +++++-- .../infra/enums/ErrorCodeConstants.java | 4 - .../system/job/SchedulerManagerTest.java | 53 ---------- .../module/system/mq/RedisStreamTest.java | 62 ------------ .../module/system/service/package-info.java | 4 - .../sms/SmsServiceIntegrationTest.java | 55 ----------- .../test/BaseDbAndRedisIntegrationTest.java | 38 ------- .../system/test/BaseRedisIntegrationTest.java | 23 ----- .../application-integration-test.yaml | 99 ------------------- 9 files changed, 25 insertions(+), 347 deletions(-) delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/job/SchedulerManagerTest.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/mq/RedisStreamTest.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/package-info.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/sms/SmsServiceIntegrationTest.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseDbAndRedisIntegrationTest.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseRedisIntegrationTest.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java index acd48aa121..12a6e17246 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/cache/CacheUtils.java @@ -1,13 +1,10 @@ package cn.iocoder.yudao.framework.common.util.cache; -import com.alibaba.ttl.threadpool.TtlExecutors; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.time.Duration; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** @@ -17,17 +14,36 @@ import java.util.concurrent.Executors; */ public class CacheUtils { + /** + * 构建异步刷新的 LoadingCache 对象 + * + * 注意:如果你的缓存和 ThreadLocal 有关系,要么自己处理 ThreadLocal 的传递,要么使用 {@link #buildCache(Duration, CacheLoader)} 方法 + * + * 或者简单理解: + * 1、和“人”相关的,使用 {@link #buildCache(Duration, CacheLoader)} 方法 + * 2、和“全局”、“系统”相关的,使用当前缓存方法 + * + * @param duration 过期时间 + * @param loader CacheLoader 对象 + * @return LoadingCache 对象 + */ public static LoadingCache buildAsyncReloadingCache(Duration duration, CacheLoader loader) { - // 1. 使用 TTL 包装 ExecutorService,实现 ThreadLocal 的透传 - // https://github.com/YunaiV/ruoyi-vue-pro/issues/432 - ExecutorService executorService = Executors.newCachedThreadPool(); // TODO 芋艿:可能要思考下,未来要不要做成可配置 - Executor executor = TtlExecutors.getTtlExecutorService(executorService); - // 2. 创建 Guava LoadingCache return CacheBuilder.newBuilder() // 只阻塞当前数据加载线程,其他线程返回旧值 .refreshAfterWrite(duration) // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程 - .build(CacheLoader.asyncReloading(loader, executor)); + .build(CacheLoader.asyncReloading(loader, Executors.newCachedThreadPool())); // TODO 芋艿:可能要思考下,未来要不要做成可配置 + } + + /** + * 构建同步刷新的 LoadingCache 对象 + * + * @param duration 过期时间 + * @param loader CacheLoader 对象 + * @return LoadingCache 对象 + */ + public static LoadingCache buildCache(Duration duration, CacheLoader loader) { + return CacheBuilder.newBuilder().refreshAfterWrite(duration).build(loader); } } diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java index 3385596ad6..e9f39a81fe 100644 --- a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java @@ -47,7 +47,6 @@ public interface ErrorCodeConstants { ErrorCode CODEGEN_MASTER_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_010, "主表(id={})定义不存在,请检查"); ErrorCode CODEGEN_SUB_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_011, "子表的字段(id={})不存在,请检查"); ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE = new ErrorCode(1_001_004_012, "主表生成代码失败,原因:它没有子表"); - ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_COLUMN = new ErrorCode(1_001_004_013, "主表生成代码失败,原因:它的子表({})没有字段"); // ========== 文件配置 1-001-006-000 ========== ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_006_000, "文件配置不存在"); @@ -57,9 +56,6 @@ public interface ErrorCodeConstants { ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_007_000, "数据源配置不存在"); ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1_001_007_001, "数据源配置不正确,无法进行连接"); - // ========== 数据源配置 1-001-107-000 ========== - ErrorCode DEMO_STUDENT_NOT_EXISTS = new ErrorCode(1_001_107_000, "学生不存在"); - // ========== 学生 1-001-201-000 ========== ErrorCode DEMO01_CONTACT_NOT_EXISTS = new ErrorCode(1_001_201_000, "示例联系人不存在"); ErrorCode DEMO02_CATEGORY_NOT_EXISTS = new ErrorCode(1_001_201_001, "示例分类不存在"); diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/job/SchedulerManagerTest.java b/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/job/SchedulerManagerTest.java deleted file mode 100644 index 2b145a741e..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/job/SchedulerManagerTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.iocoder.yudao.module.system.job; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; -import cn.iocoder.yudao.module.system.job.auth.UserSessionTimeoutJob; -import cn.iocoder.yudao.module.system.test.BaseDbUnitTest; -import org.junit.jupiter.api.Test; -import org.quartz.SchedulerException; - -import jakarta.annotation.Resource; - -public class SchedulerManagerTest extends BaseDbUnitTest { - - @Resource - private SchedulerManager schedulerManager; - - @Test - public void testAddJob() throws SchedulerException { - String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName()); - schedulerManager.addJob(1L, jobHandlerName, "test", "0/10 * * * * ? *", 0, 0); - } - - @Test - public void testUpdateJob() throws SchedulerException { - String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName()); - schedulerManager.updateJob(jobHandlerName, "hahaha", "0/20 * * * * ? *", 0, 0); - } - - @Test - public void testDeleteJob() throws SchedulerException { - String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName()); - schedulerManager.deleteJob(jobHandlerName); - } - - @Test - public void testPauseJob() throws SchedulerException { - String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName()); - schedulerManager.pauseJob(jobHandlerName); - } - - @Test - public void testResumeJob() throws SchedulerException { - String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName()); - schedulerManager.resumeJob(jobHandlerName); - } - - @Test - public void testTriggerJob() throws SchedulerException { - String jobHandlerName = StrUtil.lowerFirst(UserSessionTimeoutJob.class.getSimpleName()); - schedulerManager.triggerJob(1L, jobHandlerName, "niubi!!!"); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/mq/RedisStreamTest.java b/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/mq/RedisStreamTest.java deleted file mode 100644 index 9d431c288e..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/mq/RedisStreamTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.system.mq; - -import cn.hutool.core.thread.ThreadUtil; -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; -import cn.iocoder.yudao.module.system.mq.consumer.mail.MailSendConsumer; -import cn.iocoder.yudao.module.system.mq.consumer.sms.SmsSendConsumer; -import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; -import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; -import cn.iocoder.yudao.module.system.test.BaseRedisIntegrationTest; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Import; -import org.springframework.data.redis.core.RedisTemplate; - -import jakarta.annotation.Resource; -import java.util.concurrent.TimeUnit; - -public class RedisStreamTest { - - @Import({SmsSendConsumer.class, MailSendConsumer.class}) - @Disabled - public static class ConsumerTest extends BaseRedisIntegrationTest { - - @Test - public void testConsumer() { - ThreadUtil.sleep(1, TimeUnit.DAYS); - } - - } - - @Disabled - public static class ProducerTest extends BaseRedisIntegrationTest { - - @Resource - private RedisMQTemplate redisMQTemplate; - - @Resource - private RedisTemplate redisTemplate; - - @Test - public void testProducer01() { - for (int i = 0; i < 100; i++) { - // 创建消息 - SmsSendMessage message = new SmsSendMessage(); - message.setMobile("15601691300").setApiTemplateId("test:" + i); - // 发送消息 - redisMQTemplate.send(message); - } - } - - @Test - public void testProducer02() { - // 创建消息 - MailSendMessage message = new MailSendMessage(); - message.setAddress("fangfang@mihayou.com").setTemplateCode("test"); - // 发送消息 - redisMQTemplate.send(message); - } - - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/package-info.java b/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/package-info.java deleted file mode 100644 index 7b475e53e4..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 占位 - */ -package cn.iocoder.yudao.module.system.service; diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/sms/SmsServiceIntegrationTest.java b/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/sms/SmsServiceIntegrationTest.java deleted file mode 100644 index a8ce00a192..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/service/sms/SmsServiceIntegrationTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package cn.iocoder.yudao.module.system.service.sms; - -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.thread.ThreadUtil; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.sms.config.YudaoSmsAutoConfiguration; -import cn.iocoder.yudao.module.system.test.BaseDbAndRedisIntegrationTest; -import cn.iocoder.yudao.module.system.mq.consumer.sms.SmsSendConsumer; -import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; -import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import jakarta.annotation.Resource; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -// TODO @芋艿:需要迁移 -@Import({YudaoSmsAutoConfiguration.class, - SmsChannelServiceImpl.class, SmsSendServiceImpl.class, SmsTemplateServiceImpl.class, SmsLogServiceImpl.class, - SmsProducer.class, SmsSendConsumer.class}) -public class SmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest { - - @Resource - private SmsSendServiceImpl smsService; - @Resource - private SmsChannelServiceImpl smsChannelService; - - @MockBean - private AdminUserService userService; - - @Test - public void testSendSingleSms_aliyunSuccess() { - // 参数准备 - String mobile = "15601691399"; - Long userId = 1L; - Integer userType = UserTypeEnum.ADMIN.getValue(); - String templateCode = "test_02"; - Map templateParams = MapUtil.builder() - .put("code", "1234").build(); - // 调用 - smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams); - - // 等待 MQ 消费 - ThreadUtil.sleep(1, TimeUnit.HOURS); - } - -// @Test -// public void testDoSendSms() { -// // 等待 MQ 消费 -// ThreadUtil.sleep(1, TimeUnit.HOURS); -// } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseDbAndRedisIntegrationTest.java b/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseDbAndRedisIntegrationTest.java deleted file mode 100644 index 5b9b21ffd5..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseDbAndRedisIntegrationTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.module.system.test; - -import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; -import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; -import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; -import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; -import org.redisson.spring.starter.RedissonAutoConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisIntegrationTest.Application.class) -@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 -public class BaseDbAndRedisIntegrationTest { - - @Import({ - // DB 配置类 - DynamicDataSourceAutoConfiguration.class, // Dynamic Datasource 配置类 - YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 - DataSourceAutoConfiguration.class, // Spring DB 自动配置类 - DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 - // MyBatis 配置类 - YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 - MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 - - // Redis 配置类 - RedisAutoConfiguration.class, // Spring Redis 自动配置类 - YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 - RedissonAutoConfiguration.class, // Redisson 自动高配置类 - }) - public static class Application { - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseRedisIntegrationTest.java b/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseRedisIntegrationTest.java deleted file mode 100644 index f48b2891df..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/java/cn/iocoder/yudao/module/system/test/BaseRedisIntegrationTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.system.test; - -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; -import org.redisson.spring.starter.RedissonAutoConfiguration; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisIntegrationTest.Application.class) -@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 -public class BaseRedisIntegrationTest { - - @Import({ - // Redis 配置类 - RedisAutoConfiguration.class, // Spring Redis 自动配置类 - YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 - RedissonAutoConfiguration.class, // Redisson 自动高配置类 - }) - public static class Application { - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml b/yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml deleted file mode 100644 index 9b025ac8ef..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test-integration/resources/application-integration-test.yaml +++ /dev/null @@ -1,99 +0,0 @@ -spring: - main: - lazy-initialization: true # 开启懒加载,加快速度 - banner-mode: off # 单元测试,禁用 Banner - ---- #################### 数据库相关配置 #################### - -spring: - # 数据源配置项 - autoconfigure: - exclude: - - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 - datasource: - druid: # Druid 【监控】相关的全局配置 - web-stat-filter: - enabled: true - stat-view-servlet: - enabled: true - allow: # 设置白名单,不填则允许所有访问 - url-pattern: /druid/* - login-username: # 控制台管理用户名和密码 - login-password: - filter: - stat: - enabled: true - log-slow-sql: true # 慢 SQL 记录 - slow-sql-millis: 100 - merge-sql: true - wall: - config: - multi-statement-allow: true - dynamic: # 多数据源配置 - druid: # Druid 【连接池】相关的全局配置 - initial-size: 5 # 初始连接数 - min-idle: 10 # 最小连接池数量 - max-active: 20 # 最大连接池数量 - max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 - time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 - min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 - max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 - validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 - test-while-idle: true - test-on-borrow: false - test-on-return: false - primary: master - datasource: - master: - name: ruoyi-vue-pro - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT - driver-class-name: com.mysql.jdbc.Driver - username: root - password: 123456 - slave: # 模拟从库,可根据自己需要修改 - name: ruoyi-vue-pro - url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT - driver-class-name: com.mysql.jdbc.Driver - username: root - password: 123456 - - # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 - data: - redis: - host: 127.0.0.1 # 地址 - port: 16379 # 端口(单元测试,使用 16379 端口) - database: 0 # 数据库索引 - -mybatis: - lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 - ---- #################### 定时任务相关配置 #################### - ---- #################### 配置中心相关配置 #################### - ---- #################### 服务保障相关配置 #################### - -# Lock4j 配置项(单元测试,禁用 Lock4j) - ---- #################### 监控相关配置 #################### - ---- #################### 芋道相关配置 #################### - -# 芋道配置项,设置当前项目所有自定义的配置 -yudao: - security: - token-header: Authorization - token-secret: abcdefghijklmnopqrstuvwxyz - token-timeout: 1d - session-timeout: 30m - mock-enable: true - mock-secret: test - swagger: - enable: false # 单元测试,禁用 Swagger - file: - base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/file/get/ - xss: - enable: false - exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 - - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 - - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 From fd832e23fd1d5395d385d92dad0a31d59fb6d95d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 22 Apr 2024 23:31:50 +0800 Subject: [PATCH 79/86] =?UTF-8?q?bugfix=EF=BC=9A=E9=9D=9E=20json=20?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=EF=BC=88=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=EF=BC=89=E6=97=B6=EF=BC=8Ctoken=20=E8=BF=87=E6=9C=9F=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E9=94=99=E8=AF=AF=E8=AF=BB=E5=8F=96=20request=20body?= =?UTF-8?q?=20=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/servlet/ServletUtils.java | 12 ++++++++++-- .../src/test/resources/sql/clean.sql | 1 - .../src/test/resources/sql/create_tables.sql | 15 --------------- .../dal/mysql/oauth2/OAuth2AccessTokenMapper.java | 2 ++ .../src/main/resources/application-local.yaml | 3 ++- yudao-server/src/main/resources/application.yaml | 1 - 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java index bc592d8908..00b4687d42 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java @@ -93,11 +93,19 @@ public class ServletUtils { } public static String getBody(HttpServletRequest request) { - return JakartaServletUtil.getBody(request); + // 只有在 json 请求在读取,因为只有 CacheRequestBodyFilter 才会进行缓存,支持重复读取 + if (isJsonRequest(request)) { + return JakartaServletUtil.getBody(request); + } + return null; } public static byte[] getBodyBytes(HttpServletRequest request) { - return JakartaServletUtil.getBodyBytes(request); + // 只有在 json 请求在读取,因为只有 CacheRequestBodyFilter 才会进行缓存,支持重复读取 + if (isJsonRequest(request)) { + return JakartaServletUtil.getBodyBytes(request); + } + return null; } public static String getClientIP(HttpServletRequest request) { diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql index a3e0fd0299..58345edd85 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql @@ -6,7 +6,6 @@ DELETE FROM "infra_job_log"; DELETE FROM "infra_api_access_log"; DELETE FROM "infra_api_error_log"; DELETE FROM "infra_file_config"; -DELETE FROM "infra_test_demo"; DELETE FROM "infra_data_source_config"; DELETE FROM "infra_codegen_table"; DELETE FROM "infra_codegen_column"; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql index 9f383ac5a2..d4ca2b80eb 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql @@ -146,21 +146,6 @@ CREATE TABLE IF NOT EXISTS "infra_api_error_log" ( primary key ("id") ) COMMENT '系统异常日志'; -CREATE TABLE IF NOT EXISTS "infra_test_demo" ( - "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "name" varchar(100) NOT NULL, - "status" tinyint NOT NULL, - "type" tinyint NOT NULL, - "category" tinyint NOT NULL, - "remark" varchar(500), - "creator" varchar(64) DEFAULT '''', - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updater" varchar(64) DEFAULT '''', - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - "deleted" bit NOT NULL DEFAULT FALSE, - PRIMARY KEY ("id") -) COMMENT '字典类型表'; - CREATE TABLE IF NOT EXISTS "infra_data_source_config" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" varchar(100) NOT NULL, diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java index 8a1e2876de..81ca13fad7 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/oauth2/OAuth2AccessTokenMapper.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.oauth2; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import org.apache.ibatis.annotations.Mapper; @@ -13,6 +14,7 @@ import java.util.List; @Mapper public interface OAuth2AccessTokenMapper extends BaseMapperX { + @TenantIgnore // 获取 token 的时候,需要忽略租户编号。原因是:一些场景下,可能不会传递 tenant-id 请求头,例如说文件上传、积木报表等等 default OAuth2AccessTokenDO selectByAccessToken(String accessToken) { return selectOne(OAuth2AccessTokenDO::getAccessToken, accessToken); } diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 328e9c27b9..7f348da846 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -165,10 +165,11 @@ logging: # 配置自己写的 MyBatis Mapper 打印日志 cn.iocoder.yudao.module.bpm.dal.mysql: debug cn.iocoder.yudao.module.infra.dal.mysql: debug + cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper: INFO # 配置 ApiErrorLogMapper 的日志级别为 info,避免和 GlobalExceptionHandler 重复打印 cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 配置 JobLogMapper 的日志级别为 info cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper: INFO # 配置 FileConfigMapper 的日志级别为 info cn.iocoder.yudao.module.pay.dal.mysql: debug - cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 JobLogMapper 的日志级别为 info + cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 配置 PayNotifyTaskMapper 的日志级别为 info cn.iocoder.yudao.module.system.dal.mysql: debug cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 配置 SmsChannelMapper 的日志级别为 info cn.iocoder.yudao.module.tool.dal.mysql: debug diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index ae336f4293..6cb5386e3d 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -211,7 +211,6 @@ yudao: - system_notify_template - infra_codegen_column - infra_codegen_table - - infra_test_demo - infra_config - infra_file_config - infra_file From 7f0485e872ca78e6b98e8bbfa1a9af39da475611 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 23 Apr 2024 09:41:10 +0800 Subject: [PATCH 80/86] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=A7=86=E9=A2=91=E5=9C=B0=E5=9D=80=E5=9C=A8?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E6=92=AD=E6=94=BE=E7=9A=84=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E6=80=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/servlet/ServletUtils.java | 18 ------------ .../admin/codegen/CodegenController.java | 14 +++++----- .../controller/admin/file/FileController.java | 4 +-- .../file/core/utils/FileTypeUtils.java | 28 +++++++++++++++++++ 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java index 00b4687d42..12731edad6 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.framework.common.util.servlet; -import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.JakartaServletUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -12,8 +11,6 @@ import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import java.io.IOException; -import java.net.URLEncoder; import java.util.Map; /** @@ -35,21 +32,6 @@ public class ServletUtils { JakartaServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE); } - /** - * 返回附件 - * - * @param response 响应 - * @param filename 文件名 - * @param content 附件内容 - */ - public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { - // 设置 header 和 contentType - response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); - // 输出附件 - IoUtil.write(response.getOutputStream(), false, content); - } - /** * @param request 请求 * @return ua diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java index 356bb41394..ed4c34446e 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java @@ -5,7 +5,6 @@ import cn.hutool.core.util.ZipUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO; import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO; @@ -17,17 +16,17 @@ import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert; import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; import cn.iocoder.yudao.module.infra.service.codegen.CodegenService; -import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; -import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -36,6 +35,7 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; @Tag(name = "管理后台 - 代码生成器") @RestController @@ -145,7 +145,7 @@ public class CodegenController { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipUtil.zip(outputStream, paths, ins); // 输出 - ServletUtils.writeAttachment(response, "codegen.zip", outputStream.toByteArray()); + writeAttachment(response, "codegen.zip", outputStream.toByteArray()); } } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java index bbd29dc291..2f92adc0e0 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -6,7 +6,6 @@ import cn.hutool.core.util.URLUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.service.file.FileService; @@ -26,6 +25,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; @Tag(name = "管理后台 - 文件存储") @RestController @@ -88,7 +88,7 @@ public class FileController { response.setStatus(HttpStatus.NOT_FOUND.value()); return; } - ServletUtils.writeAttachment(response, path, content); + writeAttachment(response, path, content); } @GetMapping("/page") diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java index ea71f58810..8970c004cf 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java @@ -1,9 +1,15 @@ package cn.iocoder.yudao.module.infra.framework.file.core.utils; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; import com.alibaba.ttl.TransmittableThreadLocal; +import jakarta.servlet.http.HttpServletResponse; import lombok.SneakyThrows; import org.apache.tika.Tika; +import java.io.IOException; +import java.net.URLEncoder; + /** * 文件类型 Utils * @@ -45,4 +51,26 @@ public class FileTypeUtils { return TIKA.get().detect(data, name); } + /** + * 返回附件 + * + * @param response 响应 + * @param filename 文件名 + * @param content 附件内容 + */ + public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { + // 设置 header 和 contentType + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); + String contentType = getMineType(content, filename); + response.setContentType(contentType); + // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题 + if (StrUtil.containsIgnoreCase(contentType, "video")) { + response.setHeader("Content-Length", String.valueOf(content.length - 1)); + response.setHeader("Content-Range", String.valueOf(content.length - 1)); + response.setHeader("Accept-Ranges", "bytes"); + } + // 输出附件 + IoUtil.write(response.getOutputStream(), false, content); + } + } From 0649c315d10ffe9a3754575fe062db27ba19ab01 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 24 Apr 2024 09:14:51 +0800 Subject: [PATCH 81/86] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20sslEnable=20=E5=AD=97=E6=AE=B5=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20outlook=20=E9=82=AE=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/mail/vo/account/MailAccountRespVO.java | 3 +++ .../admin/mail/vo/account/MailAccountSaveReqVO.java | 4 ++++ .../module/system/dal/dataobject/mail/MailAccountDO.java | 4 ++++ .../yudao/module/system/service/mail/MailSendServiceImpl.java | 3 ++- .../src/test/resources/sql/create_tables.sql | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java index c1dc376dfa..15232b218b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountRespVO.java @@ -30,6 +30,9 @@ public class MailAccountRespVO { @Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") private Boolean sslEnable; + @Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean starttlsEnable; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java index f7c84a561c..5bac2c93e3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/account/MailAccountSaveReqVO.java @@ -38,4 +38,8 @@ public class MailAccountSaveReqVO { @NotNull(message = "是否开启 ssl 必填") private Boolean sslEnable; + @Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否开启 starttls 必填") + private Boolean starttlsEnable; + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java index 275fc8570e..0f9588616a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/mail/MailAccountDO.java @@ -49,5 +49,9 @@ public class MailAccountDO extends BaseDO { * 是否开启 SSL */ private Boolean sslEnable; + /** + * 是否开启 STARTTLS + */ + private Boolean starttlsEnable; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java index 178a64aec9..306b05c048 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java @@ -120,7 +120,8 @@ public class MailSendServiceImpl implements MailSendService { String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail(); return new MailAccount().setFrom(from).setAuth(true) .setUser(account.getUsername()).setPass(account.getPassword().toCharArray()) - .setHost(account.getHost()).setPort(account.getPort()).setSslEnable(account.getSslEnable()); + .setHost(account.getHost()).setPort(account.getPort()) + .setSslEnable(account.getSslEnable()).setStarttlsEnable(account.getStarttlsEnable()); } @VisibleForTesting diff --git a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql index 8f1ac5e0a0..087540a6e4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql @@ -520,6 +520,7 @@ CREATE TABLE IF NOT EXISTS "system_mail_account" ( "host" varchar NOT NULL, "port" int NOT NULL, "ssl_enable" bit NOT NULL, + "starttls_enable" bit NOT NULL, "creator" varchar DEFAULT '', "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, "updater" varchar DEFAULT '', From fb237fa22e955be3a473c8a255592a91f37a61e9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 24 Apr 2024 09:35:17 +0800 Subject: [PATCH 82/86] =?UTF-8?q?=E3=80=90=E5=AE=8C=E5=96=84=E3=80=91?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=AF=B9=20DM=20=E8=BE=BE?= =?UTF-8?q?=E6=A2=A6=E6=95=B0=E6=8D=AE=E7=9A=84=E5=85=BC=E5=AE=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 3 --- sql/mysql/ruoyi-vue-pro.sql | 1 - sql/oracle/ruoyi-vue-pro.sql | 2 -- sql/postgresql/ruoyi-vue-pro.sql | 3 --- sql/sqlserver/ruoyi-vue-pro.sql | 8 -------- .../admin/codegen/vo/column/CodegenColumnRespVO.java | 3 --- .../admin/codegen/vo/column/CodegenColumnSaveReqVO.java | 4 ---- .../module/infra/convert/codegen/CodegenConvert.java | 1 - .../infra/dal/dataobject/codegen/CodegenColumnDO.java | 6 ------ .../infra/service/codegen/inner/CodegenBuilderTest.java | 2 -- .../src/test/resources/codegen/table/category.json | 1 - .../src/test/resources/codegen/table/contact.json | 1 - .../src/test/resources/codegen/table/student.json | 1 - .../src/test/resources/codegen/table/teacher.json | 1 - .../src/test/resources/sql/create_tables.sql | 1 - 15 files changed, 38 deletions(-) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index e5369739ec..98c29b4318 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -249,7 +249,6 @@ CREATE TABLE "RUOYI_VUE_PRO"."INFRA_CODEGEN_COLUMN" "COLUMN_COMMENT" VARCHAR(500) NOT NULL, "NULLABLE" BIT NOT NULL, "PRIMARY_KEY" BIT NOT NULL, - "AUTO_INCREMENT" CHAR(1) NOT NULL, "ORDINAL_POSITION" INT NOT NULL, "JAVA_TYPE" VARCHAR(32) NOT NULL, "JAVA_FIELD" VARCHAR(64) NOT NULL, @@ -2512,8 +2511,6 @@ COMMENT ON COLUMN "RUOYI_VUE_PRO"."INFRA_CODEGEN_COLUMN"."NULLABLE" IS '是否 COMMENT ON COLUMN "RUOYI_VUE_PRO"."INFRA_CODEGEN_COLUMN"."PRIMARY_KEY" IS '是否主键'; -COMMENT ON COLUMN "RUOYI_VUE_PRO"."INFRA_CODEGEN_COLUMN"."AUTO_INCREMENT" IS '是否自增'; - COMMENT ON COLUMN "RUOYI_VUE_PRO"."INFRA_CODEGEN_COLUMN"."ORDINAL_POSITION" IS '排序'; COMMENT ON COLUMN "RUOYI_VUE_PRO"."INFRA_CODEGEN_COLUMN"."JAVA_TYPE" IS 'Java 属性类型'; diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 24385dab4e..5950b3fff2 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -409,7 +409,6 @@ CREATE TABLE `infra_codegen_column` ( `column_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '字段描述', `nullable` bit(1) NOT NULL COMMENT '是否允许为空', `primary_key` bit(1) NOT NULL COMMENT '是否主键', - `auto_increment` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '是否自增', `ordinal_position` int NOT NULL COMMENT '排序', `java_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Java 属性类型', `java_field` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Java 属性名', diff --git a/sql/oracle/ruoyi-vue-pro.sql b/sql/oracle/ruoyi-vue-pro.sql index 0eb0f64405..dbe0e6a7b6 100644 --- a/sql/oracle/ruoyi-vue-pro.sql +++ b/sql/oracle/ruoyi-vue-pro.sql @@ -622,7 +622,6 @@ CREATE TABLE "INFRA_CODEGEN_COLUMN" ( "COLUMN_COMMENT" NVARCHAR2(500), "NULLABLE" NUMBER(4,0), "PRIMARY_KEY" NUMBER(4,0), - "AUTO_INCREMENT" NUMBER(4,0), "ORDINAL_POSITION" NUMBER(11,0) NOT NULL, "JAVA_TYPE" NVARCHAR2(32), "JAVA_FIELD" NVARCHAR2(64), @@ -664,7 +663,6 @@ COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."DATA_TYPE" IS '字段类型'; COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."COLUMN_COMMENT" IS '字段描述'; COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."NULLABLE" IS '是否允许为空'; COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."PRIMARY_KEY" IS '是否主键'; -COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."AUTO_INCREMENT" IS '是否自增'; COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."ORDINAL_POSITION" IS '排序'; COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."JAVA_TYPE" IS 'Java 属性类型'; COMMENT ON COLUMN "INFRA_CODEGEN_COLUMN"."JAVA_FIELD" IS 'Java 属性名'; diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql index 206fdfce8e..cff06d5a7c 100644 --- a/sql/postgresql/ruoyi-vue-pro.sql +++ b/sql/postgresql/ruoyi-vue-pro.sql @@ -1225,7 +1225,6 @@ CREATE TABLE "infra_codegen_column" "column_comment" varchar(500) COLLATE "pg_catalog"."default" NOT NULL, "nullable" bool NOT NULL, "primary_key" bool NOT NULL, - "auto_increment" bool NOT NULL, "ordinal_position" int4 NOT NULL, "java_type" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, "java_field" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, @@ -1259,8 +1258,6 @@ ON COLUMN "infra_codegen_column"."nullable" IS '是否允许为空'; COMMENT ON COLUMN "infra_codegen_column"."primary_key" IS '是否主键'; COMMENT -ON COLUMN "infra_codegen_column"."auto_increment" IS '是否自增'; -COMMENT ON COLUMN "infra_codegen_column"."ordinal_position" IS '排序'; COMMENT ON COLUMN "infra_codegen_column"."java_type" IS 'Java 属性类型'; diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql index bfb10f6bd4..830a96ab33 100644 --- a/sql/sqlserver/ruoyi-vue-pro.sql +++ b/sql/sqlserver/ruoyi-vue-pro.sql @@ -1957,7 +1957,6 @@ CREATE TABLE [dbo].[infra_codegen_column] ( [column_comment] nvarchar(500) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [nullable] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [primary_key] varchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, - [auto_increment] nchar(1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [ordinal_position] int NOT NULL, [java_type] nvarchar(32) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [java_field] nvarchar(64) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, @@ -2029,13 +2028,6 @@ EXEC sp_addextendedproperty 'COLUMN', N'primary_key' GO -EXEC sp_addextendedproperty -'MS_Description', N'是否自增', -'SCHEMA', N'dbo', -'TABLE', N'infra_codegen_column', -'COLUMN', N'auto_increment' -GO - EXEC sp_addextendedproperty 'MS_Description', N'排序', 'SCHEMA', N'dbo', diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java index f5384ab51a..29a8c743ef 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java @@ -30,9 +30,6 @@ public class CodegenColumnRespVO { @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") private Boolean primaryKey; - @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") - private Boolean autoIncrement; - @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private Integer ordinalPosition; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java index edad804ba2..18067c2fa8 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java @@ -36,10 +36,6 @@ public class CodegenColumnSaveReqVO { @NotNull(message = "是否主键不能为空") private Boolean primaryKey; - @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") - @NotNull(message = "是否自增不能为空") - private Boolean autoIncrement; - @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @NotNull(message = "排序不能为空") private Integer ordinalPosition; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java index feb4b23840..6b976135c1 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java @@ -41,7 +41,6 @@ public interface CodegenConvert { @Mapping(source = "comment", target = "columnComment"), @Mapping(source = "metaInfo.nullable", target = "nullable"), @Mapping(source = "keyFlag", target = "primaryKey"), - @Mapping(source = "keyIdentityFlag", target = "autoIncrement"), @Mapping(source = "columnType.type", target = "javaType"), @Mapping(source = "propertyName", target = "javaField"), }) diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java index 3681622142..f90a3645a8 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java @@ -67,12 +67,6 @@ public class CodegenColumnDO extends BaseDO { * 关联 {@link TableField#isKeyFlag()} */ private Boolean primaryKey; - /** - * 是否自增 - * - * 关联 {@link TableField#isKeyIdentityFlag()} - */ - private Boolean autoIncrement; /** * 排序 */ diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java index 01a55be195..7a26ea9cc9 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java @@ -54,7 +54,6 @@ public class CodegenBuilderTest extends BaseMockitoUnitTest { when(metaInfo.getJdbcType()).thenReturn(JdbcType.BIGINT); when(tableField.getComment()).thenReturn("编号"); when(tableField.isKeyFlag()).thenReturn(true); - when(tableField.isKeyIdentityFlag()).thenReturn(true); IColumnType columnType = mock(IColumnType.class); when(tableField.getColumnType()).thenReturn(columnType); when(columnType.getType()).thenReturn("Long"); @@ -72,7 +71,6 @@ public class CodegenBuilderTest extends BaseMockitoUnitTest { assertEquals("编号", column.getColumnComment()); assertFalse(column.getNullable()); assertTrue(column.getPrimaryKey()); - assertTrue(column.getAutoIncrement()); assertEquals(1, column.getOrdinalPosition()); assertEquals("Long", column.getJavaType()); assertEquals("id", column.getJavaField()); diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json index 210613f5d9..033c048a51 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json @@ -18,7 +18,6 @@ "dataType" : "BIGINT", "columnComment" : "编号", "primaryKey" : true, - "autoIncrement" : true, "javaType" : "Long", "javaField" : "id", "example" : "1024", diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json index 6a310570f5..74f92cd1df 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json @@ -14,7 +14,6 @@ "dataType" : "BIGINT", "columnComment" : "编号", "primaryKey" : true, - "autoIncrement" : true, "javaType" : "Long", "javaField" : "id", "example" : "1024", diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json index 0cc29c5a93..efe8af4a24 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json @@ -17,7 +17,6 @@ "dataType" : "BIGINT", "columnComment" : "编号", "primaryKey" : true, - "autoIncrement" : true, "javaType" : "Long", "javaField" : "id", "example" : "1024", diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json index 7ef460400a..4d93518ebc 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json @@ -14,7 +14,6 @@ "dataType" : "BIGINT", "columnComment" : "编号", "primaryKey" : true, - "autoIncrement" : true, "javaType" : "Long", "javaField" : "id", "example" : "1024", diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql index d4ca2b80eb..d4b19c926d 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql @@ -196,7 +196,6 @@ CREATE TABLE IF NOT EXISTS "infra_codegen_column" ( "column_comment" varchar(500) NOT NULL, "nullable" tinyint not null, "primary_key" tinyint not null, - "auto_increment" varchar(5) not null, "ordinal_position" int not null, "java_type" varchar(32) NOT NULL, "java_field" varchar(64) NOT NULL, From b382ae4f858a73eddc5bef04b2fd1dbcba566213 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 24 Apr 2024 09:38:05 +0800 Subject: [PATCH 83/86] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2-?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9C=AA=E6=8C=89=E7=85=A7=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=8E=92=E5=BA=8F=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/system/dal/mysql/permission/RoleMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java index f6d86d1a1e..d41f9dd5c5 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java @@ -21,7 +21,7 @@ public interface RoleMapper extends BaseMapperX { .likeIfPresent(RoleDO::getCode, reqVO.getCode()) .eqIfPresent(RoleDO::getStatus, reqVO.getStatus()) .betweenIfPresent(BaseDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(RoleDO::getId)); + .orderByAsc(RoleDO::getId)); } default RoleDO selectByName(String name) { From eb1ca934b793bfe132f0775067f026b370e593e0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 24 Apr 2024 12:16:03 +0800 Subject: [PATCH 84/86] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2-?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9C=AA=E6=8C=89=E7=85=A7=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=8E=92=E5=BA=8F=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/system/dal/mysql/permission/RoleMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java index d41f9dd5c5..2e4da2bbdd 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java @@ -21,7 +21,7 @@ public interface RoleMapper extends BaseMapperX { .likeIfPresent(RoleDO::getCode, reqVO.getCode()) .eqIfPresent(RoleDO::getStatus, reqVO.getStatus()) .betweenIfPresent(BaseDO::getCreateTime, reqVO.getCreateTime()) - .orderByAsc(RoleDO::getId)); + .orderByAsc(RoleDO::getSort)); } default RoleDO selectByName(String name) { From 6f42da1b77436daab71b3a85089217c328d5071f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 24 Apr 2024 20:11:11 +0800 Subject: [PATCH 85/86] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91?= =?UTF-8?q?=E9=83=A8=E5=88=86=E8=8F=9C=E5=8D=95=EF=BC=8C=E7=A1=AE=E5=AE=9E?= =?UTF-8?q?=20menu.sql=20=E9=85=8D=E7=BD=AE=E7=9A=84=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/mysql/ruoyi-vue-pro.sql | 218 ++++++------------ .../admin/customer/CrmCustomerController.java | 4 +- .../followup/CrmFollowUpRecordController.java | 5 - .../operatelog/CrmOperateLogController.java | 1 - .../permission/CrmPermissionController.java | 21 +- .../seckill/SeckillConfigController.java | 2 +- .../admin/mail/MailAccountController.java | 2 +- .../admin/mail/MailTemplateController.java | 2 +- 8 files changed, 74 insertions(+), 181 deletions(-) diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 5950b3fff2..3da8b1ad60 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -11,7 +11,7 @@ Target Server Version : 80200 (8.2.0) File Encoding : 65001 - Date: 07/04/2024 19:33:28 + Date: 24/04/2024 20:07:36 */ SET NAMES utf8mb4; @@ -74,7 +74,6 @@ CREATE TABLE `QRTZ_CRON_TRIGGERS` ( BEGIN; INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', '0 * * * * ?', 'Asia/Shanghai'); -INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'demoJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', '0 0 0 * * ?', 'Asia/Shanghai'); INSERT INTO `QRTZ_CRON_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `CRON_EXPRESSION`, `TIME_ZONE_ID`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', '* * * * * ?', 'Asia/Shanghai'); @@ -145,7 +144,6 @@ CREATE TABLE `QRTZ_JOB_DETAILS` ( BEGIN; INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000197400104A4F425F48414E444C45525F4E414D457400116163636573734C6F67436C65616E4A6F627800); INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000187400104A4F425F48414E444C45525F4E414D4574001A62726F6B65726167655265636F7264556E667265657A654A6F627800); -INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'demoJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000147400104A4F425F48414E444C45525F4E414D4574000764656D6F4A6F627800); INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001A7400104A4F425F48414E444C45525F4E414D457400106572726F724C6F67436C65616E4A6F627800); INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000001B7400104A4F425F48414E444C45525F4E414D4574000E6A6F624C6F67436C65616E4A6F627800); INSERT INTO `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `JOB_CLASS_NAME`, `IS_DURABLE`, `IS_NONCONCURRENT`, `IS_UPDATE_DATA`, `REQUESTS_RECOVERY`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', NULL, 'cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000057400104A4F425F48414E444C45525F4E414D4574000C7061794E6F746966794A6F627800); @@ -207,7 +205,7 @@ CREATE TABLE `QRTZ_SCHEDULER_STATE` ( -- Records of QRTZ_SCHEDULER_STATE -- ---------------------------- BEGIN; -INSERT INTO `QRTZ_SCHEDULER_STATE` (`SCHED_NAME`, `INSTANCE_NAME`, `LAST_CHECKIN_TIME`, `CHECKIN_INTERVAL`) VALUES ('schedulerName', 'MacBook-Pro.local1701948801197', 1701948848400, 15000); +INSERT INTO `QRTZ_SCHEDULER_STATE` (`SCHED_NAME`, `INSTANCE_NAME`, `LAST_CHECKIN_TIME`, `CHECKIN_INTERVAL`) VALUES ('schedulerName', 'MacBook-Pro.local1713489703551', 1713742509534, 15000); COMMIT; -- ---------------------------- @@ -303,7 +301,6 @@ CREATE TABLE `QRTZ_TRIGGERS` ( BEGIN; INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'accessLogCleanJob', 'DEFAULT', 'accessLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696301981000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'brokerageRecordUnfreezeJob', 'DEFAULT', 'brokerageRecordUnfreezeJob', 'DEFAULT', NULL, 1695909720000, -1, 5, 'PAUSED', 'CRON', 1695909706000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); -INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'demoJob', 'DEFAULT', 'demoJob', 'DEFAULT', NULL, 1701964800000, 1701948834291, 5, 'PAUSED', 'CRON', 1694844083000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000A74000F4A4F425F52455452595F434F554E547371007E000A000000017800); INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'errorLogCleanJob', 'DEFAULT', 'errorLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302043000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'jobLogCleanJob', 'DEFAULT', 'jobLogCleanJob', 'DEFAULT', NULL, 1696348800000, -1, 5, 'PAUSED', 'CRON', 1696302092000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D7400007400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E547371007E000A000000037800); INSERT INTO `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `JOB_NAME`, `JOB_GROUP`, `DESCRIPTION`, `NEXT_FIRE_TIME`, `PREV_FIRE_TIME`, `PRIORITY`, `TRIGGER_STATE`, `TRIGGER_TYPE`, `START_TIME`, `END_TIME`, `CALENDAR_NAME`, `MISFIRE_INSTR`, `JOB_DATA`) VALUES ('schedulerName', 'payNotifyJob', 'DEFAULT', 'payNotifyJob', 'DEFAULT', NULL, 1688907102000, 1688907101000, 5, 'PAUSED', 'CRON', 1635294882000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B02000078700000000074000F4A4F425F52455452595F434F554E5471007E000B7800); @@ -389,7 +386,7 @@ CREATE TABLE `infra_api_error_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 16468 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 16513 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志'; -- ---------------------------- -- Records of infra_api_error_log @@ -693,7 +690,7 @@ CREATE TABLE `infra_file` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1302 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1307 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表'; -- ---------------------------- -- Records of infra_file @@ -771,7 +768,7 @@ CREATE TABLE `infra_job` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; +) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务表'; -- ---------------------------- -- Records of infra_job @@ -781,7 +778,6 @@ INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param` INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (17, '支付订单同步 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (18, '支付订单过期 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (19, '退款订单的同步 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', b'0'); -INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (20, 'Job 示例', 2, 'demoJob', '', '0 0 0 * * ?', 1, 10, 0, '1', '2023-09-16 14:01:23', '1', '2023-12-07 19:34:08', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (21, '交易订单的自动过期 Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-25 23:43:26', '1', '2023-09-26 19:23:30', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '交易订单的自动收货 Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 19:23:53', '1', '2023-09-26 23:38:08', b'0'); INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (23, '交易订单的自动评论 Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 23:38:29', '1', '2023-09-27 11:03:10', b'0'); @@ -812,7 +808,7 @@ CREATE TABLE `infra_job_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 235 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; +) ENGINE = InnoDB AUTO_INCREMENT = 395 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '定时任务日志表'; -- ---------------------------- -- Records of infra_job_log @@ -882,7 +878,7 @@ CREATE TABLE `system_dict_data` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1534 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1537 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; -- ---------------------------- -- Records of system_dict_data @@ -946,8 +942,6 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (75, 1, '接收成功', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (76, 2, '接收失败', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (78, 1, '自动生成', '1', 'system_error_code_type', 0, 'warning', '', NULL, '1', '2021-04-21 00:06:48', '1', '2022-02-16 13:57:20', b'0'); -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (79, 2, '手动编辑', '2', 'system_error_code_type', 0, 'primary', '', NULL, '1', '2021-04-21 00:07:14', '1', '2022-02-16 13:57:24', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (80, 100, '账号登录', '100', 'system_login_type', 0, 'primary', '', '账号登录', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (81, 101, '社交登录', '101', 'system_login_type', 0, 'info', '', '社交登录', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (83, 200, '主动登出', '200', 'system_login_type', 0, 'primary', '', '主动登出', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', b'0'); @@ -1261,6 +1255,9 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1531, 3, '月', '3', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1532, 4, '季度', '4', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1533, 5, '年', '5', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1534, 1, '赢单', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1535, 2, '输单', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1536, 3, '无效', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', b'0'); COMMIT; -- ---------------------------- @@ -1281,7 +1278,7 @@ CREATE TABLE `system_dict_type` ( `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 617 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; +) ENGINE = InnoDB AUTO_INCREMENT = 620 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; -- ---------------------------- -- Records of system_dict_type @@ -1303,7 +1300,6 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (112, '短信模板的类型', 'system_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (113, '短信发送状态', 'system_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (114, '短信接收状态', 'system_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', b'0', NULL); -INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (115, '错误码的类型', 'system_error_code_type', 0, NULL, '1', '2021-04-21 00:06:30', '1', '2022-02-01 16:36:49', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (116, '登陆日志的类型', 'system_login_type', 0, '登陆日志的类型', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (117, 'OA 请假类型', 'bpm_oa_leave_type', 0, NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (130, '支付渠道编码类型', 'pay_channel_code', 0, '支付渠道的编码', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', b'0', NULL); @@ -1371,31 +1367,7 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (613, 'BPM 监听器类型', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', b'0', '1970-01-01 00:00:00'); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (615, 'BPM 监听器值类型', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', b'0', '1970-01-01 00:00:00'); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (616, '时间间隔', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', b'0', '1970-01-01 00:00:00'); -COMMIT; - --- ---------------------------- --- Table structure for system_error_code --- ---------------------------- -DROP TABLE IF EXISTS `system_error_code`; -CREATE TABLE `system_error_code` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '错误码编号', - `type` tinyint NOT NULL DEFAULT 0 COMMENT '错误码类型', - `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用名', - `code` int NOT NULL DEFAULT 0 COMMENT '错误码编码', - `message` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '错误码错误提示', - `memo` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '备注', - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 6039 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '错误码表'; - --- ---------------------------- --- Records of system_error_code --- ---------------------------- -BEGIN; +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (619, 'CRM 商机结束状态类型', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', b'0', '1970-01-01 00:00:00'); COMMIT; -- ---------------------------- @@ -1419,7 +1391,7 @@ CREATE TABLE `system_login_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 3081 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; +) ENGINE = InnoDB AUTO_INCREMENT = 3094 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录'; -- ---------------------------- -- Records of system_login_log @@ -1439,6 +1411,7 @@ CREATE TABLE `system_mail_account` ( `host` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SMTP 服务器域名', `port` int NOT NULL COMMENT 'SMTP 服务器端口', `ssl_enable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否开启 SSL', + `starttls_enable` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否开启 STARTTLS', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', @@ -1451,10 +1424,10 @@ CREATE TABLE `system_mail_account` ( -- Records of system_mail_account -- ---------------------------- BEGIN; -INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, b'0', '1', '2023-01-25 17:39:52', '1', '2023-12-02 19:51:19', b'0'); -INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, b'1', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', b'0'); -INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, b'0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', b'1'); -INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, b'1', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', b'1'); +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, b'0', b'0', '1', '2023-01-25 17:39:52', '1', '2024-04-24 09:13:56', b'0'); +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, b'1', b'0', '1', '2023-01-26 01:26:03', '1', '2023-04-12 22:39:38', b'0'); +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, b'0', b'0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', b'1'); +INSERT INTO `system_mail_account` (`id`, `mail`, `username`, `password`, `host`, `port`, `ssl_enable`, `starttls_enable`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, b'1', b'0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', b'1'); COMMIT; -- ---------------------------- @@ -1549,7 +1522,7 @@ CREATE TABLE `system_menu` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 2738 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; +) ENGINE = InnoDB AUTO_INCREMENT = 2758 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表'; -- ---------------------------- -- Records of system_menu @@ -1564,17 +1537,17 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (103, '部门管理', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (104, '岗位管理', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (105, '字典管理', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:12', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (106, '配置管理', '', 2, 6, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:54:18', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (107, '通知公告', '', 2, 8, 1, 'notice', 'ep:message-box', 'system/notice/index', 'SystemNotice', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:50', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (106, '配置管理', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:02:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (107, '通知公告', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-22 23:56:17', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (108, '审计日志', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:08:30', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (109, '令牌管理', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:13:48', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (110, '定时任务', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:36', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (111, 'MySQL 监控', '', 2, 9, 2, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:55:51', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (112, 'Java 监控', '', 2, 11, 2, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:56:46', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (113, 'Redis 监控', '', 2, 10, 2, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:56:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (111, 'MySQL 监控', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:05:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (112, 'Java 监控', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:57', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (113, 'Redis 监控', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:09', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (114, '表单构建', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:35', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (115, '代码生成', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:06', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (116, 'API 接口文档', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:56', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (116, 'API 接口', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:01:24', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (500, '操作日志', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:09:59', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:10:29', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, b'1', b'1', b'1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', b'0'); @@ -1639,11 +1612,10 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1070, '代码生成案例', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1076, '数据库文档', '', 2, 4, 2, 'db-doc', 'fa:table', 'infra/dbDoc/index', 'InfraDBDoc', 0, b'1', b'1', b'1', '', '2021-02-08 01:41:47', '1', '2024-02-29 08:52:32', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1077, '监控平台', '', 2, 13, 2, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, b'1', b'1', b'1', '', '2021-02-08 20:41:31', '1', '2024-02-29 08:57:11', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1077, '链路追踪', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, b'1', b'1', b'1', '', '2021-02-08 20:41:31', '1', '2024-04-23 00:07:15', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, b'1', b'1', b'1', '', '2021-02-26 01:32:59', '1', '2024-02-29 08:54:57', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1083, 'API 日志', '', 2, 8, 2, 'log', 'fa:tasks', NULL, NULL, 0, b'1', b'1', b'1', '', '2021-02-26 02:18:24', '1', '2024-02-29 08:54:47', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1083, 'API 日志', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, b'1', b'1', b'1', '', '2021-02-26 02:18:24', '1', '2024-04-22 23:58:36', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, b'1', b'1', b'1', '', '2021-02-26 07:53:20', '1', '2024-02-29 08:55:17', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1085, '日志处理', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', b'0'); @@ -1653,7 +1625,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1090, '文件列表', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, b'1', b'1', b'1', '', '2021-03-12 20:16:20', '1', '2024-02-29 08:53:02', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1093, '短信管理', '', 1, 11, 1, 'sms', 'ep:message', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-04-05 01:10:16', '1', '2024-02-29 01:15:36', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1093, '短信管理', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-04-05 01:10:16', '1', '2024-04-22 23:56:03', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '1', '2024-02-29 01:15:54', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', b'0'); @@ -1669,12 +1641,6 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, b'1', b'1', b'1', '', '2021-04-11 08:37:05', '1', '2024-02-29 08:49:02', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1110, '错误码管理', '', 2, 12, 1, 'error-code', 'fa:bomb', 'system/errorCode/index', 'SystemErrorCode', 0, b'1', b'1', b'1', '', '2021-04-13 21:46:42', '1', '2024-02-29 08:49:54', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1111, '错误码查询', 'system:error-code:query', 3, 1, 1110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1112, '错误码创建', 'system:error-code:create', 3, 2, 1110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1113, '错误码更新', 'system:error-code:update', 3, 3, 1110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1114, '错误码删除', 'system:error-code:delete', 3, 4, 1110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1115, '错误码导出', 'system:error-code:export', 3, 5, 1110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-04-13 21:46:42', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1117, '支付管理', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, b'1', b'1', b'1', '1', '2021-12-25 16:43:41', '1', '2024-02-29 08:58:38', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1118, '请假查询', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, b'1', b'1', b'1', '', '2021-09-20 08:51:03', '1', '2024-02-29 12:38:21', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1119, '请假申请查询', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', b'0'); @@ -1754,13 +1720,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1240, '文件配置更新', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1241, '文件配置删除', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1242, '文件配置导出', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1243, '文件管理', '', 2, 5, 2, 'file', 'ep:files', NULL, '', 0, b'1', b'1', b'1', '1', '2022-03-16 23:47:40', '1', '2024-02-29 08:52:39', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1247, '敏感词管理', '', 2, 13, 1, 'sensitive-word', 'fa:intersex', 'system/sensitiveWord/index', 'SystemSensitiveWord', 0, b'1', b'1', b'1', '', '2022-04-07 16:55:03', '1', '2024-02-29 08:50:17', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1248, '敏感词查询', 'system:sensitive-word:query', 3, 1, 1247, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1249, '敏感词创建', 'system:sensitive-word:create', 3, 2, 1247, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1250, '敏感词更新', 'system:sensitive-word:update', 3, 3, 1247, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1251, '敏感词删除', 'system:sensitive-word:delete', 3, 4, 1247, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1252, '敏感词导出', 'system:sensitive-word:export', 3, 5, 1247, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-07 16:55:03', '', '2022-04-20 17:03:10', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1243, '文件管理', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, b'1', b'1', b'1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1254, '作者动态', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, b'1', b'1', b'1', '1', '2022-04-23 01:03:15', '1', '2023-12-08 23:40:01', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1255, '数据源配置', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1256, '数据源配置查询', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', b'0'); @@ -1885,7 +1845,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2127, '删除菜单', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:06:16', '1', '2023-01-17 23:06:16', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2128, '查询消息', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:07:14', '1', '2023-01-17 23:07:14', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2129, '发送消息', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-17 23:07:26', '1', '2023-01-17 23:07:26', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2130, '邮箱管理', '', 2, 11, 1, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-25 17:27:44', '1', '2024-02-29 01:16:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2130, '邮箱管理', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-25 17:27:44', '1', '2024-04-22 23:56:08', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2131, '邮箱账号', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '1', '2024-02-29 08:48:16', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2132, '账号查询', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2133, '账号创建', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', b'0'); @@ -1899,7 +1859,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, b'1', b'1', b'1', '', '2023-01-26 02:16:50', '1', '2024-02-29 08:48:51', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2144, '站内信管理', '', 1, 11, 1, 'notify', 'ep:message-box', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-28 10:25:18', '1', '2024-02-29 08:47:51', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2144, '站内信管理', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-01-28 10:25:18', '1', '2024-04-22 23:56:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '1', '2024-02-29 08:49:14', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', b'0'); @@ -1910,7 +1870,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2153, '大屏设计器', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'JimuReport', 0, b'1', b'1', b'1', '1', '2023-02-07 00:03:19', '1', '2024-02-29 12:34:02', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2154, '创建项目', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:14', '1', '2023-02-07 19:25:14', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2155, '更新项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:34', '1', '2023-02-07 19:25:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2155, '更新项目', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:34', '1', '2024-04-24 20:01:18', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2156, '查询项目', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2157, '使用 SQL 查询数据', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2158, '使用 HTTP 查询数据', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', b'0'); @@ -1942,8 +1902,8 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2209, '秒杀活动', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, b'1', b'1', b'1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2262, '会员中心', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2275, '会员配置', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-10-01 23:41:29', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2276, '积分设置查询', 'point:config:query', 3, 1, 2275, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '', '2023-06-10 02:07:44', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2277, '积分设置创建', 'point:config:save', 3, 2, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2023-06-27 20:32:31', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2276, '会员配置查询', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:48:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2277, '会员配置保存', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, b'1', b'1', b'1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:49:28', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2281, '签到配置', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2282, '积分签到规则查询', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2283, '积分签到规则创建', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', b'0'); @@ -2132,7 +2092,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2522, '客户限制配置删除', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2523, '客户限制配置导出', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2524, '系统配置', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, b'1', b'1', b'1', '1', '2023-11-18 21:58:00', '1', '2024-02-17 17:14:34', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2525, 'WebSocket 测试', '', 2, 7, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, b'1', b'1', b'1', '1', '2023-11-23 19:41:55', '1', '2023-11-24 19:22:30', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, b'1', b'1', b'1', '1', '2023-11-23 19:41:55', '1', '2024-04-23 00:02:00', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2526, '产品管理', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, b'1', b'1', b'1', '1', '2023-12-05 22:45:26', '1', '2024-02-20 20:36:20', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2527, '产品查询', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-05 22:47:16', '1', '2023-12-05 22:47:16', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2528, '产品创建', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-12-05 22:47:41', '1', '2023-12-05 22:47:48', b'0'); @@ -2162,7 +2122,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2558, '钱包余额查询', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2559, '转账订单', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, b'1', b'1', b'1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2560, '数据统计', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, b'1', b'1', b'1', '1', '2024-01-26 22:50:35', '1', '2024-02-24 20:10:07', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2561, '排行榜', '', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, b'1', b'1', b'1', '1', '2024-01-26 22:52:09', '1', '2024-02-24 20:11:17', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2561, '排行榜', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, b'1', b'1', b'1', '1', '2024-01-26 22:52:09', '1', '2024-04-24 19:39:11', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2562, '客户导入', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-01 13:09:00', '1', '2024-02-01 13:09:05', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2563, 'ERP 系统', '', 1, 300, 0, '/erp', 'fa-solid:store', '', '', 0, b'1', b'1', b'1', '1', '2024-02-04 15:37:25', '1', '2024-02-04 15:37:25', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2564, '产品管理', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, b'1', b'1', b'1', '1', '2024-02-04 15:38:43', '1', '2024-02-04 15:38:43', b'0'); @@ -2313,8 +2273,8 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2709, '客户公海配置查询', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2710, '合同配置更新', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2711, '合同配置查询', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2712, '客户分析', '', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, b'1', b'1', b'1', '1', '2024-03-09 16:43:56', '1', '2024-03-09 16:43:56', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2713, '抄送我的', '', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, b'1', b'1', b'1', '1', '2024-03-17 21:50:23', '1', '2024-03-17 22:12:23', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2712, '客户分析', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'views/crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, b'1', b'1', b'1', '1', '2024-03-09 16:43:56', '1', '2024-04-24 19:42:52', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2713, '抄送我的', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, b'1', b'1', b'1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2714, '流程分类', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2715, '分类查询', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2716, '分类创建', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, b'1', b'1', b'1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', b'0'); @@ -2336,8 +2296,28 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2733, '流程表达式创建', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2734, '流程表达式更新', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2735, '流程表达式删除', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2736, '员工业绩', '', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, b'1', b'1', b'1', '1', '2024-04-05 13:49:20', '1', '2024-04-05 13:49:20', b'0'); -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2737, '客户画像', '', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, b'1', b'1', b'1', '1', '2024-04-05 13:57:40', '1', '2024-04-05 13:57:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2736, '员工业绩', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, b'1', b'1', b'1', '1', '2024-04-05 13:49:20', '1', '2024-04-24 19:42:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2737, '客户画像', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, b'1', b'1', b'1', '1', '2024-04-05 13:57:40', '1', '2024-04-24 19:42:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2738, '销售漏斗', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, b'1', b'1', b'1', '1', '2024-04-13 10:53:26', '1', '2024-04-24 19:39:33', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2739, '消息中心', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, b'1', b'1', b'1', '1', '2024-04-22 23:54:30', '1', '2024-04-23 09:36:35', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2740, '监控中心', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, b'1', b'1', b'1', '1', '2024-04-23 00:04:44', '1', '2024-04-23 00:04:44', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2741, '领取公海客户', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:47:45', '1', '2024-04-24 19:47:45', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2742, '分配公海客户', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:48:05', '1', '2024-04-24 19:48:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2743, '商品统计查询', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:50:05', '1', '2024-04-24 19:50:05', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2744, '商品统计导出', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:50:26', '1', '2024-04-24 19:50:26', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2745, '支付渠道查询', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:53:01', '1', '2024-04-24 19:53:01', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2746, '支付渠道创建', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:53:18', '1', '2024-04-24 19:53:18', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2747, '支付渠道更新', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:53:32', '1', '2024-04-24 19:53:58', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2748, '支付渠道删除', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:54:34', '1', '2024-04-24 19:54:34', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2749, '商品收藏查询', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:55:47', '1', '2024-04-24 19:55:47', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2750, '商品浏览查询', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:57:43', '1', '2024-04-24 19:57:43', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2751, '售后同意', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:58:40', '1', '2024-04-24 19:58:40', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2752, '售后不同意', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 19:59:03', '1', '2024-04-24 19:59:03', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2753, '售后确认退货', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:00:07', '1', '2024-04-24 20:00:07', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2754, '售后确认退款', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:00:24', '1', '2024-04-24 20:00:24', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2755, '删除项目', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2756, '会员等级记录查询', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', b'0'); +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2757, '会员经验记录查询', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, b'1', b'1', b'1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', b'0'); COMMIT; -- ---------------------------- @@ -2459,7 +2439,7 @@ CREATE TABLE `system_oauth2_access_token` ( PRIMARY KEY (`id`) USING BTREE, INDEX `idx_access_token`(`access_token` ASC) USING BTREE, INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 6439 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 6566 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌'; -- ---------------------------- -- Records of system_oauth2_access_token @@ -2581,7 +2561,7 @@ CREATE TABLE `system_oauth2_refresh_token` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1463 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; +) ENGINE = InnoDB AUTO_INCREMENT = 1474 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌'; -- ---------------------------- -- Records of system_oauth2_refresh_token @@ -2614,7 +2594,7 @@ CREATE TABLE `system_operate_log` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 9035 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本'; +) ENGINE = InnoDB AUTO_INCREMENT = 9036 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录 V2 版本'; -- ---------------------------- -- Records of system_operate_log @@ -2728,7 +2708,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (455, 2, 1094, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (460, 2, 1100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (467, 2, 1107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (470, 2, 1110, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (476, 2, 1117, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (477, 2, 100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (478, 2, 101, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', b'0', 1); @@ -2768,7 +2747,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1500, 1, 1094, '1', '2022-02-23 20:03:57', '1', '2022-02-23 20:03:57', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1501, 1, 1100, '1', '2022-02-23 20:03:57', '1', '2022-02-23 20:03:57', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1502, 1, 1107, '1', '2022-02-23 20:03:57', '1', '2022-02-23 20:03:57', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1503, 1, 1110, '1', '2022-02-23 20:03:57', '1', '2022-02-23 20:03:57', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1505, 1, 1117, '1', '2022-02-23 20:03:57', '1', '2022-02-23 20:03:57', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1506, 1, 100, '1', '2022-02-23 20:03:57', '1', '2022-02-23 20:03:57', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1507, 1, 101, '1', '2022-02-23 20:03:57', '1', '2022-02-23 20:03:57', b'0', 1); @@ -2848,7 +2826,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1665, 101, 1076, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1667, 101, 1078, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1668, 101, 1082, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1); @@ -3165,7 +3142,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2035, 2, 1076, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2037, 2, 1085, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2038, 2, 1086, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); @@ -3186,11 +3162,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2053, 2, 1106, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2054, 2, 1108, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2055, 2, 1109, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2056, 2, 1111, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2057, 2, 1112, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2058, 2, 1113, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2059, 2, 1114, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2060, 2, 1115, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2061, 2, 1127, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2062, 2, 1128, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2063, 2, 1129, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); @@ -3233,12 +3204,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2107, 2, 1241, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2108, 2, 1242, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2109, 2, 1243, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2110, 2, 1247, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2111, 2, 1248, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2112, 2, 1249, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2113, 2, 1250, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2114, 2, 1251, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2115, 2, 1252, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2116, 2, 1254, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2117, 2, 1255, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2118, 2, 1256, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1); @@ -3345,17 +3310,11 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2228, 101, 1109, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2229, 101, 2133, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2230, 101, 2134, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2231, 101, 1110, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2232, 101, 2135, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2233, 101, 1111, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2234, 101, 2136, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2235, 101, 1112, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2236, 101, 2137, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2237, 101, 1113, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2238, 101, 2138, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2239, 101, 1114, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2240, 101, 2139, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2241, 101, 1115, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2242, 101, 2140, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2243, 101, 2141, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2244, 101, 2142, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); @@ -3390,12 +3349,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2273, 101, 1227, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2274, 101, 1228, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2275, 101, 1229, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2276, 101, 1247, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2277, 101, 1248, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2278, 101, 1249, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2279, 101, 1250, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2280, 101, 1251, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2281, 101, 1252, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2282, 101, 1261, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2283, 101, 1263, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2284, 101, 1264, '1', '2023-02-09 23:49:46', '1', '2023-02-09 23:49:46', b'0', 1); @@ -4072,7 +4025,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3431, 1, 2098, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3432, 1, 1075, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3433, 1, 2099, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3434, 1, 1076, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3435, 1, 2100, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3436, 1, 2101, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3437, 1, 2102, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); @@ -4129,15 +4081,10 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3488, 1, 2133, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3489, 1, 2134, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3490, 1, 2135, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3491, 1, 1111, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3492, 1, 2136, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3493, 1, 1112, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3494, 1, 2137, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3495, 1, 1113, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3496, 1, 2138, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3497, 1, 1114, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3498, 1, 2139, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3499, 1, 1115, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3500, 1, 2140, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3501, 1, 2141, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3502, 1, 2142, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); @@ -4262,13 +4209,7 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3621, 1, 1241, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3622, 1, 1242, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3623, 1, 1243, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3624, 1, 1247, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3625, 1, 1248, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3626, 1, 1249, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3627, 1, 1250, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3628, 1, 1251, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3629, 1, 2275, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3630, 1, 1252, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3631, 1, 2276, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3632, 1, 2277, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3633, 1, 1254, '1', '2024-01-02 17:35:25', '1', '2024-01-02 17:35:25', b'0', 1); @@ -5151,33 +5092,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4516, 144, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 154); COMMIT; --- ---------------------------- --- Table structure for system_sensitive_word --- ---------------------------- -DROP TABLE IF EXISTS `system_sensitive_word`; -CREATE TABLE `system_sensitive_word` ( - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '敏感词', - `description` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '描述', - `tags` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '标签数组', - `status` tinyint NOT NULL COMMENT '状态', - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '敏感词'; - --- ---------------------------- --- Records of system_sensitive_word --- ---------------------------- -BEGIN; -INSERT INTO `system_sensitive_word` (`id`, `name`, `description`, `tags`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '土豆', '好呀', '蔬菜,短信', 0, '1', '2022-04-08 21:07:12', '1', '2022-04-09 10:28:14', b'0'); -INSERT INTO `system_sensitive_word` (`id`, `name`, `description`, `tags`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, 'XXX', NULL, '短信', 0, '1', '2022-04-08 21:27:49', '1', '2022-06-19 00:36:50', b'0'); -INSERT INTO `system_sensitive_word` (`id`, `name`, `description`, `tags`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5, '白痴', 'lll', '测试', 0, '1', '2022-12-31 19:08:25', '1', '2023-12-02 21:57:17', b'0'); -COMMIT; - -- ---------------------------- -- Table structure for system_sms_channel -- ---------------------------- @@ -5271,7 +5185,7 @@ CREATE TABLE `system_sms_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 948 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; +) ENGINE = InnoDB AUTO_INCREMENT = 962 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志'; -- ---------------------------- -- Records of system_sms_log @@ -5441,7 +5355,7 @@ INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `c INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (151, '大租户', 126, '土豆大', NULL, 0, 'https://tudou.iocoder.cn', 111, '2023-12-08 00:00:00', 10, '1', '2023-12-02 23:35:05', '1', '2023-12-08 23:39:56', b'0'); INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (152, '新租户', 127, '土豆', NULL, 0, 'http://xx.iocoder.cn', 111, '2025-12-31 00:00:00', 50, '1', '2023-12-30 11:43:17', '1', '2023-12-30 11:43:17', b'0'); INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (153, '小明的租户', 128, 'xiaoming', '15601691301', 0, 'xiaoming.iocoder.cn', 111, '2025-12-01 00:00:00', 100, '1', '2024-02-27 21:58:25', '1', '2024-02-28 22:53:54', b'0'); -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (154, 'hh', 129, 'hh', NULL, 0, 'http://hh.iocoder.cn', 111, '2024-04-30 00:00:00', 123, '1', '2024-03-30 17:52:59', '1', '2024-04-03 15:06:42', b'0'); +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (154, 'hh', 129, 'hh', NULL, 0, 'http://hh.iocoder.cn', 111, '2024-04-30 00:00:00', 123, '1', '2024-03-30 17:52:59', '1', '2024-04-10 09:40:57', b'0'); COMMIT; -- ---------------------------- @@ -5587,7 +5501,7 @@ CREATE TABLE `system_users` ( -- Records of system_users -- ---------------------------- BEGIN; -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-07 03:16:30', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-07 03:16:30', b'0', 1); +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '18818260277', 2, 'http://test.yudao.iocoder.cn/96c787a2ce88bf6d0ce3cd8b6cf5314e80e7703cd41bf4af8cd2e2909dbd6b6d.png', 0, '0:0:0:0:0:0:0:1', '2024-04-23 23:51:16', 'admin', '2021-01-05 17:03:47', NULL, '2024-04-23 23:51:16', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '0:0:0:0:0:0:0:1', '2024-03-18 21:09:04', '', '2021-01-13 23:50:35', NULL, '2024-03-18 21:09:04', b'0', 1); INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$KhExCYl7lx6eWWZYKsibKOZ8IBJRyuNuCcEOLQ11RYhJKgHmlSwK.', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2024-03-26 07:11:35', '', '2021-01-21 02:13:53', NULL, '2024-03-26 07:11:35', b'0', 1); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index ed2cc109e2..34388dfdb2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -20,7 +19,6 @@ import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; @@ -264,7 +262,7 @@ public class CrmCustomerController { @PostMapping("/import") @Operation(summary = "导入客户") - @PreAuthorize("@ss.hasPermission('system:customer:import')") + @PreAuthorize("@ss.hasPermission('crm:customer:import')") public CommonResult importExcel(@Valid CrmCustomerImportReqVO importReqVO) throws Exception { List list = ExcelUtils.read(importReqVO.getFile(), CrmCustomerImportExcelVO.class); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java index 3f9e8cfeb3..7946aea0e8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java @@ -21,7 +21,6 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -52,7 +51,6 @@ public class CrmFollowUpRecordController { @PostMapping("/create") @Operation(summary = "创建跟进记录") - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:create')") public CommonResult createFollowUpRecord(@Valid @RequestBody CrmFollowUpRecordSaveReqVO createReqVO) { return success(followUpRecordService.createFollowUpRecord(createReqVO)); } @@ -60,7 +58,6 @@ public class CrmFollowUpRecordController { @DeleteMapping("/delete") @Operation(summary = "删除跟进记录") @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:delete')") public CommonResult deleteFollowUpRecord(@RequestParam("id") Long id) { followUpRecordService.deleteFollowUpRecord(id, getLoginUserId()); return success(true); @@ -69,7 +66,6 @@ public class CrmFollowUpRecordController { @GetMapping("/get") @Operation(summary = "获得跟进记录") @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") public CommonResult getFollowUpRecord(@RequestParam("id") Long id) { CrmFollowUpRecordDO followUpRecord = followUpRecordService.getFollowUpRecord(id); return success(BeanUtils.toBean(followUpRecord, CrmFollowUpRecordRespVO.class)); @@ -77,7 +73,6 @@ public class CrmFollowUpRecordController { @GetMapping("/page") @Operation(summary = "获得跟进记录分页") - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") public CommonResult> getFollowUpRecordPage(@Valid CrmFollowUpRecordPageReqVO pageReqVO) { PageResult pageResult = followUpRecordService.getFollowUpRecordPage(pageReqVO); // 1.1 查询联系人和商机 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java index 5b03191d8c..a981462466 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java @@ -53,7 +53,6 @@ public class CrmOperateLogController { @GetMapping("/page") @Operation(summary = "获得操作日志") - @PreAuthorize("@ss.hasPermission('crm:operate-log:query')") public CommonResult> getCustomerOperateLog(@Valid CrmOperateLogPageReqVO pageReqVO) { OperateLogPageReqDTO reqDTO = new OperateLogPageReqDTO(); reqDTO.setPageSize(PAGE_SIZE_NONE); // 默认不分页,需要分页需注释 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java index a39c4a6d8f..3373b104a3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.permission; import cn.hutool.core.collection.CollUtil; -import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; @@ -9,18 +8,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; -import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; -import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.PostApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -34,12 +25,13 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -65,7 +57,6 @@ public class CrmPermissionController { @PostMapping("/create") @Operation(summary = "创建数据权限") - @PreAuthorize("@ss.hasPermission('crm:permission:create')") public CommonResult create(@Valid @RequestBody CrmPermissionSaveReqVO reqVO) { permissionService.createPermission(reqVO, getLoginUserId()); return success(true); @@ -73,7 +64,6 @@ public class CrmPermissionController { @PutMapping("/update") @Operation(summary = "编辑数据权限") - @PreAuthorize("@ss.hasPermission('crm:permission:update')") @CrmPermission(bizTypeValue = "#updateReqVO.bizType", bizId = "#updateReqVO.bizId" , level = CrmPermissionLevelEnum.OWNER) public CommonResult updatePermission(@Valid @RequestBody CrmPermissionUpdateReqVO updateReqVO) { @@ -84,7 +74,6 @@ public class CrmPermissionController { @DeleteMapping("/delete") @Operation(summary = "删除数据权限") @Parameter(name = "ids", description = "数据权限编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:permission:delete')") public CommonResult deletePermission(@RequestParam("ids") Collection ids) { permissionService.deletePermissionBatch(ids, getLoginUserId()); return success(true); @@ -93,7 +82,6 @@ public class CrmPermissionController { @DeleteMapping("/delete-self") @Operation(summary = "删除自己的数据权限") @Parameter(name = "id", description = "数据权限编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:permission:delete')") public CommonResult deleteSelfPermission(@RequestParam("id") Long id) { permissionService.deleteSelfPermission(id, getLoginUserId()); return success(true); @@ -105,7 +93,6 @@ public class CrmPermissionController { @Parameter(name = "bizType", description = "CRM 类型", required = true, example = "2"), @Parameter(name = "bizId", description = "CRM 类型数据编号", required = true, example = "1024") }) - @PreAuthorize("@ss.hasPermission('crm:permission:query')") public CommonResult> getPermissionList(@RequestParam("bizType") Integer bizType, @RequestParam("bizId") Long bizId) { List permissions = permissionService.getPermissionListByBiz(bizType, bizId); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java index cfceb6d0f1..21b9a14008 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java @@ -46,7 +46,7 @@ public class SeckillConfigController { @PutMapping("/update-status") @Operation(summary = "修改时段配置状态") - @PreAuthorize("@ss.hasPermission('system:seckill-config:update')") + @PreAuthorize("@ss.hasPermission('promotion:seckill-config:update')") public CommonResult updateSeckillConfigStatus(@Valid @RequestBody SeckillConfigUpdateStatusReqVo reqVO) { seckillConfigService.updateSeckillConfigStatus(reqVO.getId(), reqVO.getStatus()); return success(true); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java index 28648567b3..4cd7c40a3d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailAccountController.java @@ -57,7 +57,7 @@ public class MailAccountController { @GetMapping("/get") @Operation(summary = "获得邮箱账号") @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('system:mail-account:get')") + @PreAuthorize("@ss.hasPermission('system:mail-account:query')") public CommonResult getMailAccount(@RequestParam("id") Long id) { MailAccountDO account = mailAccountService.getMailAccount(id); return success(BeanUtils.toBean(account, MailAccountRespVO.class)); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java index 96a53815f5..22e2658ef3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java @@ -57,7 +57,7 @@ public class MailTemplateController { @GetMapping("/get") @Operation(summary = "获得邮件模版") @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('system:mail-template:get')") + @PreAuthorize("@ss.hasPermission('system:mail-template:query')") public CommonResult getMailTemplate(@RequestParam("id") Long id) { MailTemplateDO template = mailTempleService.getMailTemplate(id); return success(BeanUtils.toBean(template, MailTemplateRespVO.class)); From 53db8309e994e2c95db289ed6ae2dec44d851c14 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 24 Apr 2024 21:08:53 +0800 Subject: [PATCH 86/86] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91CRM?= =?UTF-8?q?=20=E5=88=86=E7=B1=BB=E5=88=A0=E9=99=A4=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E5=95=86=E5=93=81=E6=95=B0=E9=87=8F=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E4=B8=BA=E7=A9=BA=E4=B8=8D=E6=AD=A3=E7=A1=AE=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E5=AF=BC=E8=87=B4=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=88=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java | 2 +- .../crm/service/product/CrmProductCategoryServiceImpl.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index 27fb6f9cea..07a6dad60d 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -87,7 +87,7 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_CATEGORY_USED = new ErrorCode(1_020_009_002, "产品分类已关联产品"); ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_020_009_003, "父分类不存在"); ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_020_009_004, "父分类不能是二级分类"); - ErrorCode product_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); + ErrorCode PRODUCT_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); // ========== 商机状态 1_020_010_000 ========== ErrorCode BUSINESS_STATUS_TYPE_NOT_EXISTS = new ErrorCode(1_020_010_000, "商机状态组不存在"); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java index 6399039ba0..ce168883af 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java @@ -110,10 +110,10 @@ public class CrmProductCategoryServiceImpl implements CrmProductCategoryService validateProductCategoryExists(id); // 1.2 校验是否还有子分类 if (productCategoryMapper.selectCountByParentId(id) > 0) { - throw exception(product_CATEGORY_EXISTS_CHILDREN); + throw exception(PRODUCT_CATEGORY_EXISTS_CHILDREN); } // 1.3 校验是否被产品使用 - if (crmProductService.getProductByCategoryId(id) !=null) { + if (crmProductService.getProductByCategoryId(id) > 0) { throw exception(PRODUCT_CATEGORY_USED); } // 2. 删除