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