feat:增加学生家长导入。
feat:钱包流水、批量充值增加tag。 feat:优化表格区域的搜索逻辑。
This commit is contained in:
1 parent
2a617c9460
commit
4816f151d6
33 files changed
+418
-47
No files matched your search
@@ -0,0 +1,6 @@
|
||||
-- 为充值导入记录及最终钱包流水补充财务统计标签;历史数据保持为空。
|
||||
ALTER TABLE wallet_recharge_import
|
||||
ADD COLUMN tags varchar(512) DEFAULT NULL COMMENT '财务统计标签,多个wallet_transaction_tag字典值使用英文逗号分隔' AFTER price;
|
||||
|
||||
ALTER TABLE wallet_transaction
|
||||
ADD COLUMN tags varchar(512) DEFAULT NULL COMMENT '财务统计标签,多个wallet_transaction_tag字典值使用英文逗号分隔' AFTER balance;
|
||||
@@ -455,6 +455,7 @@ CREATE TABLE wallet_transaction
|
||||
title varchar(128) NOT NULL COMMENT '流水标题',
|
||||
price int NOT NULL COMMENT '交易金额, 单位分',
|
||||
balance int NOT NULL COMMENT '余额, 单位分',
|
||||
tags varchar(512) DEFAULT NULL COMMENT '财务统计标签,多个wallet_transaction_tag字典值使用英文逗号分隔',
|
||||
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
update_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
|
||||
@@ -536,6 +537,7 @@ CREATE TABLE wallet_recharge_import
|
||||
apply_id bigint NOT NULL COMMENT '申请id',
|
||||
before_price int DEFAULT NULL COMMENT '导入前的金额',
|
||||
price int NOT NULL COMMENT '交易金额, 单位分',
|
||||
tags varchar(512) DEFAULT NULL COMMENT '财务统计标签,多个wallet_transaction_tag字典值使用英文逗号分隔',
|
||||
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
update_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
|
||||
|
||||
+8
@@ -9,6 +9,7 @@ import java.lang.annotation.Target;
|
||||
/**
|
||||
* Excel 字典字段。
|
||||
* <p>导入时校验单元格内容是否为字典标签,导出模板时将同一字典标签写入下拉选项。</p>
|
||||
* <p>多选字段在普通 Excel 中使用英文逗号分隔多个标签;原生下拉仅负责提供选项,无法自动追加多次选择。</p>
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -20,4 +21,11 @@ public @interface ExcelDict {
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* 是否允许一个单元格填写多个字典标签。
|
||||
*
|
||||
* @return {@code true} 时按英文逗号拆分并逐项校验,{@code false} 时整个单元格只能是一个字典标签
|
||||
*/
|
||||
boolean multiple() default false;
|
||||
|
||||
}
|
||||
+8
-1
@@ -8,11 +8,18 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Excel 模板增强。
|
||||
* <p>切面自动收集 {@link RequestExcel} 导入参数中的模型,下载接口无需感知文件名或具体业务模型。</p>
|
||||
* <p>切面默认自动收集当前服务 {@link RequestExcel} 导入参数中的模型;跨服务模型可通过注解参数显式补充。</p>
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExcelTemplate {
|
||||
|
||||
/**
|
||||
* 当前下载接口需要额外处理的 Excel 模型,用于补充当前服务无法自动扫描到的跨服务导入模型。
|
||||
*
|
||||
* @return 需要参与模板字典下拉增强的模型类型;默认不额外补充模型
|
||||
*/
|
||||
Class<?>[] value() default {};
|
||||
|
||||
}
|
||||
+15
-3
@@ -63,7 +63,7 @@ public class ExcelTemplateAspect {
|
||||
Object result = joinPoint.proceed(wrappedArgs);
|
||||
wrapper.flushBuffer();
|
||||
byte[] content = wrapper.getContentAsByteArray();
|
||||
byte[] enhancedContent = enhance(content, getModelClasses());
|
||||
byte[] enhancedContent = enhance(content, resolveModelClasses(excelTemplate));
|
||||
response.setContentLength(enhancedContent.length);
|
||||
response.getOutputStream().write(enhancedContent);
|
||||
response.getOutputStream().flush();
|
||||
@@ -72,6 +72,18 @@ public class ExcelTemplateAspect {
|
||||
throw new IllegalStateException("@ExcelTemplate 方法必须包含 HttpServletResponse 参数");
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并注解显式模型与当前服务自动扫描模型,保证跨服务模板可增强且保留原有自动发现能力。
|
||||
*
|
||||
* @param excelTemplate 当前下载方法的模板增强注解
|
||||
* @return 去重后的模板模型集合
|
||||
*/
|
||||
private Class<?>[] resolveModelClasses(ExcelTemplate excelTemplate) {
|
||||
return java.util.stream.Stream.concat(Arrays.stream(excelTemplate.value()), Arrays.stream(getModelClasses()))
|
||||
.distinct()
|
||||
.toArray(Class<?>[]::new);
|
||||
}
|
||||
|
||||
private boolean isExcelTemplateRequest(Object[] args) {
|
||||
for (Object arg : args) {
|
||||
if (arg instanceof String value) {
|
||||
@@ -85,7 +97,7 @@ public class ExcelTemplateAspect {
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入接口的 {@code @RequestExcel List<T>} 是模板模型的唯一来源,新增导入模型无需再修改下载接口或注册表。
|
||||
* 自动收集当前服务导入接口中的 {@code @RequestExcel List<T>} 模型,供未显式注册的同服务模板继续使用。
|
||||
*/
|
||||
private Class<?>[] getModelClasses() {
|
||||
Class<?>[] cachedModelClasses = modelClasses;
|
||||
@@ -162,7 +174,7 @@ public class ExcelTemplateAspect {
|
||||
HeaderCell headerCell = findHeaderCell(sheet, headerName);
|
||||
if (headerCell != null) {
|
||||
ExcelDictDataValidationWriter.write(sheet, headerCell.columnIndex(), headerCell.rowIndex() + 1,
|
||||
excelDict.value());
|
||||
excelDict.value(), excelDict.multiple());
|
||||
enhanced = true;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-6
@@ -31,9 +31,15 @@ public final class ExcelDictDataValidationWriter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字典标签写入隐藏页,并为目标列创建引用式下拉。
|
||||
* 将字典标签写入隐藏页,并为目标列创建引用式下拉;多选模式允许按英文逗号手工组合多个选项。
|
||||
*
|
||||
* @param dataSheet 数据页
|
||||
* @param columnIndex 字典字段所在列下标
|
||||
* @param firstDataRowIndex 首行数据的下标
|
||||
* @param dictType 字典类型
|
||||
* @param multiple 是否允许一个单元格包含多个字典标签
|
||||
*/
|
||||
public static void write(Sheet dataSheet, int columnIndex, int firstDataRowIndex, String dictType) {
|
||||
public static void write(Sheet dataSheet, int columnIndex, int firstDataRowIndex, String dictType, boolean multiple) {
|
||||
List<String> labels = ExcelDictHelper.getLabels(dictType);
|
||||
if (labels.isEmpty()) {
|
||||
throw new IllegalStateException("Excel 字典未配置或没有可用项: " + dictType);
|
||||
@@ -41,7 +47,7 @@ public final class ExcelDictDataValidationWriter {
|
||||
Workbook workbook = dataSheet.getWorkbook();
|
||||
String formulaName = writeDictColumn(workbook, dictType, labels);
|
||||
removeColumnValidations(dataSheet, columnIndex);
|
||||
addValidation(dataSheet, columnIndex, firstDataRowIndex, formulaName);
|
||||
addValidation(dataSheet, columnIndex, firstDataRowIndex, formulaName, multiple);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,15 +129,30 @@ public final class ExcelDictDataValidationWriter {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void addValidation(Sheet sheet, int columnIndex, int firstDataRowIndex, String formulaName) {
|
||||
/**
|
||||
* 为目标列添加字典下拉。多选时关闭 Excel 原生错误拦截,否则逗号组合值会被单选列表拒绝。
|
||||
*
|
||||
* @param sheet 数据页
|
||||
* @param columnIndex 字典字段所在列下标
|
||||
* @param firstDataRowIndex 首行数据的下标
|
||||
* @param formulaName 隐藏字典区域的名称
|
||||
* @param multiple 是否允许按英文逗号组合多个标签
|
||||
*/
|
||||
private static void addValidation(Sheet sheet, int columnIndex, int firstDataRowIndex, String formulaName, boolean multiple) {
|
||||
DataValidationHelper helper = sheet.getDataValidationHelper();
|
||||
DataValidationConstraint constraint = helper.createFormulaListConstraint(formulaName);
|
||||
CellRangeAddressList range = new CellRangeAddressList(firstDataRowIndex,
|
||||
sheet.getWorkbook().getSpreadsheetVersion().getLastRowIndex(), columnIndex, columnIndex);
|
||||
DataValidation validation = helper.createValidation(constraint, range);
|
||||
validation.setEmptyCellAllowed(true);
|
||||
validation.setShowErrorBox(true);
|
||||
validation.createErrorBox("填写错误", "请选择下拉中的有效字典项");
|
||||
validation.setShowErrorBox(!multiple);
|
||||
if (multiple) {
|
||||
validation.setShowPromptBox(true);
|
||||
validation.createPromptBox("填写说明", "可填写多个选项,请使用英文逗号分隔");
|
||||
}
|
||||
else {
|
||||
validation.createErrorBox("填写错误", "请选择下拉中的有效字典项");
|
||||
}
|
||||
sheet.addValidationData(validation);
|
||||
}
|
||||
|
||||
|
||||
+18
-4
@@ -12,6 +12,7 @@ import org.springframework.util.StringUtils;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
@@ -67,7 +68,10 @@ public class DefaultAnalysisEventListener extends ListAnalysisEventListener<Obje
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典字段统一按 Excel 中展示的标签校验,避免业务 Service 为每个字段重复编写字典判断。
|
||||
* 字典字段统一按 Excel 中展示的标签校验;多选字段按英文逗号拆分,避免业务 Service 重复编写字典判断。
|
||||
*
|
||||
* @param data 当前 Excel 行转换出的模型
|
||||
* @return 当前行字典字段的校验错误;没有错误时返回空集合
|
||||
*/
|
||||
private Set<String> validateExcelDict(Object data) {
|
||||
Set<String> messages = new LinkedHashSet<>();
|
||||
@@ -82,14 +86,24 @@ public class DefaultAnalysisEventListener extends ListAnalysisEventListener<Obje
|
||||
if (fieldValue == null || !StringUtils.hasText(fieldValue.toString())) {
|
||||
continue;
|
||||
}
|
||||
String label = fieldValue.toString().trim();
|
||||
String fieldText = fieldValue.toString().trim();
|
||||
List<String> labels = dictLabelCache.computeIfAbsent(excelDict.value(), ExcelDictHelper::getLabels);
|
||||
String fieldName = getExcelFieldName(field);
|
||||
if (labels.isEmpty()) {
|
||||
messages.add(fieldName + "字典未配置或没有可用项");
|
||||
}
|
||||
else if (!labels.contains(label)) {
|
||||
messages.add(fieldName + ":" + label + ",不在可选项中");
|
||||
else {
|
||||
List<String> selectedLabels = excelDict.multiple()
|
||||
? Arrays.stream(fieldText.split(",", -1)).map(String::trim).toList()
|
||||
: List.of(fieldText);
|
||||
if (selectedLabels.stream().anyMatch(label -> !StringUtils.hasText(label))) {
|
||||
messages.add(fieldName + "包含空选项,请使用英文逗号正确分隔");
|
||||
continue;
|
||||
}
|
||||
List<String> invalidLabels = selectedLabels.stream().filter(label -> !labels.contains(label)).distinct().toList();
|
||||
if (!invalidLabels.isEmpty()) {
|
||||
messages.add(fieldName + ":" + String.join(",", invalidLabels) + ",不在可选项中");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException exception) {
|
||||
|
||||
@@ -146,6 +146,13 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Sentinel BOM 会把 mockito-core 降至 2.28.2,此处与 Spring Boot 3.3.6 的 Mockito 5 测试套件保持一致。 -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--引入分布式事务-->
|
||||
<dependency>
|
||||
<groupId>com.bsd</groupId>
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import com.wechat.pay.java.core.notification.NotificationParser;
|
||||
import com.wechat.pay.java.core.notification.RequestParam;
|
||||
import com.wechat.pay.java.service.partnerpayments.app.AppServiceExtension;
|
||||
import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
|
||||
import com.wechat.pay.java.service.partnerpayments.app.model.TransactionAmount;
|
||||
import com.wechat.pay.java.service.partnerpayments.model.TransactionAmount;
|
||||
import com.wechat.pay.java.service.refund.RefundService;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
+13
-5
@@ -43,11 +43,6 @@ public class StudentUserExcelVO {
|
||||
*/
|
||||
private Long guardianUserId;
|
||||
|
||||
/**
|
||||
* 监护人部门id
|
||||
*/
|
||||
private Long guardianDeptId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@@ -55,6 +50,19 @@ public class StudentUserExcelVO {
|
||||
@ExcelProperty("学号")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生所属部门名称或路径,必须匹配当前租户已有部门。
|
||||
*/
|
||||
@NotBlank(message = "学生部门")
|
||||
@ExcelProperty("学生部门")
|
||||
private String studentDeptName;
|
||||
|
||||
/**
|
||||
* 同步校验阶段解析出的学生部门 ID,仅供异步写入使用,不直接读取 Excel。
|
||||
*/
|
||||
@ExcelIgnore
|
||||
private Long studentDeptId;
|
||||
|
||||
/**
|
||||
* 学校名称
|
||||
*/
|
||||
|
||||
+2
-1
@@ -31,6 +31,7 @@ import com.bsd.pjcloud.common.excel.annotation.ExcelTemplate;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
import com.bsd.pjcloud.common.security.annotation.HasPermission;
|
||||
import com.bsd.pjcloud.common.security.annotation.Inner;
|
||||
import com.bsd.pjcloud.wallet.api.dto.recharge.excel.WalletRechargeExcelDto;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -152,7 +153,7 @@ public class SysFileController {
|
||||
* @param response 本地文件
|
||||
*/
|
||||
@SneakyThrows
|
||||
@ExcelTemplate
|
||||
@ExcelTemplate(WalletRechargeExcelDto.class)
|
||||
@GetMapping("/local/file/{fileName}")
|
||||
public void localFile(@PathVariable String fileName, HttpServletResponse response) {
|
||||
ClassPathResource resource = new ClassPathResource("file/" + fileName);
|
||||
|
||||
+2
-2
@@ -421,7 +421,7 @@ public class SysUserController {
|
||||
* @return 校验失败时包含对应行号和错误原因;校验通过时包含异步任务 ID 和初始进度
|
||||
*/
|
||||
@PostMapping("/import")
|
||||
@HasPermission("sys_user_export")
|
||||
@HasPermission("sys_user_import")
|
||||
public R<?> importUser(@RequestExcel List<UserExcelVO> excelVOList, BindingResult bindingResult) {
|
||||
return userImportExportService.importUser(excelVOList, bindingResult);
|
||||
}
|
||||
@@ -479,7 +479,7 @@ public class SysUserController {
|
||||
* @return 校验失败时包含校验或图片处理错误;校验通过时包含异步任务 ID 和初始进度
|
||||
*/
|
||||
@PostMapping("/import-face")
|
||||
@HasPermission("sys_user_export")
|
||||
@HasPermission("sys_user_import")
|
||||
@Idempotent(expireTime = 5, key = "'/user/import-face:' + #file.getSize() + ':' + #excelList.hashCode() + ':' + T(com.bsd.pjcloud.common.security.util.SecurityUtils).getUser().getId()", info = "正在导入中,请勿重复操作")
|
||||
public R<?> importUserFace(@RequestParam("file") MultipartFile file, @RequestExcel List<UserExcelFaceVo> excelList, BindingResult bindingResult) {
|
||||
return userImportExportService.importUserFace(file, excelList, bindingResult);
|
||||
|
||||
+9
-3
@@ -254,10 +254,13 @@ public class SysUserImportExportServiceImpl implements SysUserImportExportServic
|
||||
excel.setUsername(StrUtil.trim(excel.getUsername()));
|
||||
excel.setGuardianPhone(StrUtil.trim(excel.getGuardianPhone()));
|
||||
excel.setStudentNo(StrUtil.trim(excel.getStudentNo()));
|
||||
excel.setStudentDeptName(StrUtil.trim(excel.getStudentDeptName()));
|
||||
excel.setSchoolName(StrUtil.trim(excel.getSchoolName()));
|
||||
excel.setClassName(StrUtil.trim(excel.getClassName()));
|
||||
});
|
||||
|
||||
DepartmentIndex departmentIndex = new DepartmentIndex(sysDeptService.list());
|
||||
|
||||
List<String> guardianPhones = studentUserExcelList.stream().map(StudentUserExcelVO::getGuardianPhone)
|
||||
.filter(StrUtil::isNotBlank).distinct().toList();
|
||||
Map<String, SysUser> guardianUserMap = guardianPhones.isEmpty() ? Map.of() : sysUserService.list(
|
||||
@@ -324,9 +327,12 @@ public class SysUserImportExportServiceImpl implements SysUserImportExportServic
|
||||
errorMessages.add("监护人手机号:" + excel.getGuardianPhone() + ",对应的用户未添加或未审批通过");
|
||||
} else {
|
||||
excel.setGuardianUserId(guardian.getUserId());
|
||||
excel.setGuardianDeptId(guardian.getDeptId());
|
||||
}
|
||||
}
|
||||
SysDept studentDepartment = resolveDepartment(excel.getStudentDeptName(), departmentIndex, errorMessages);
|
||||
if (studentDepartment != null) {
|
||||
excel.setStudentDeptId(studentDepartment.getDeptId());
|
||||
}
|
||||
if (CollUtil.isNotEmpty(errorMessages)) {
|
||||
errorMessageList.add(new ErrorMessage(excel.getLineNum(), errorMessages));
|
||||
}
|
||||
@@ -740,7 +746,7 @@ public class SysUserImportExportServiceImpl implements SysUserImportExportServic
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建学生用户及监护关系,学生扩展信息只属于 STUDENT 身份。
|
||||
* 创建学生用户及监护关系,学生扩展信息只属于 STUDENT 身份,用户部门使用模板中已校验的学生部门。
|
||||
*
|
||||
* @param excel 当前校验通过的学生行
|
||||
* @param guardianWardRelationTypeId 监护关系类型 ID
|
||||
@@ -757,7 +763,7 @@ public class SysUserImportExportServiceImpl implements SysUserImportExportServic
|
||||
relationUser.setStaffingType(UserStaffingTypeEnum.NONE_STAFFING.getType());
|
||||
relationUser.setIdentityTypes(List.of(UserIdentityTypeEnum.STUDENT.getType()));
|
||||
relationUser.setRole(studentRoleIds);
|
||||
relationUser.setDeptId(excel.getGuardianDeptId());
|
||||
relationUser.setDeptId(excel.getStudentDeptId());
|
||||
SysUserStudentDto studentInfo = new SysUserStudentDto();
|
||||
studentInfo.setStudentNo(excel.getStudentNo());
|
||||
studentInfo.setSchoolName(excel.getSchoolName());
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -219,6 +219,18 @@
|
||||
<if test="query.staffingType != null">
|
||||
AND u.staffing_type = #{query.staffingType}
|
||||
</if>
|
||||
<!-- 多身份查询按任一身份命中处理,EXISTS 可避免身份表的一对多关系放大用户结果集。 -->
|
||||
<if test="query.identityTypes != null and query.identityTypes.size() != 0">
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM sys_user_identity user_identity
|
||||
WHERE user_identity.user_id = u.user_id
|
||||
AND user_identity.identity_type IN
|
||||
<foreach collection="query.identityTypes" item="identityType" open="(" close=")" separator=",">
|
||||
#{identityType}
|
||||
</foreach>
|
||||
)
|
||||
</if>
|
||||
<if test="query.role != null and query.role.size() != 0">
|
||||
and urole.role_id IN
|
||||
<foreach collection="query.role" item="v" open="(" close=")" separator=",">
|
||||
@@ -307,6 +319,18 @@
|
||||
<if test="query.deptId != null and query.deptId != ''">
|
||||
AND u.dept_id = #{query.deptId}
|
||||
</if>
|
||||
<!-- 导出沿用列表页的身份筛选语义,确保导出结果与当前查询一致。 -->
|
||||
<if test="query.identityTypes != null and query.identityTypes.size() != 0">
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM sys_user_identity user_identity
|
||||
WHERE user_identity.user_id = u.user_id
|
||||
AND user_identity.identity_type IN
|
||||
<foreach collection="query.identityTypes" item="identityType" open="(" close=")" separator=",">
|
||||
#{identityType}
|
||||
</foreach>
|
||||
)
|
||||
</if>
|
||||
<if test="query.role != null and query.role.size() != 0">
|
||||
and urole.role_id IN
|
||||
<foreach collection="query.role" item="v" open="(" close=")" separator=",">
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.bsd.pjcloud.wallet.api.constant;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 充值流水tag
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum WalletTransactionTag {
|
||||
|
||||
BJZ_CZ("1", "不记账充值"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String desc;
|
||||
|
||||
public static WalletTransactionTag valueOfByCode(String code) {
|
||||
if (ObjectUtil.isEmpty(code)) return null;
|
||||
return Arrays.stream(values()).filter(v -> ObjectUtil.equals(code, v.getCode())).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public static WalletTransactionTag descOf(String description) {
|
||||
return Arrays.stream(WalletTransactionTag.values())
|
||||
.filter(v -> ObjectUtil.equal(v.getDesc(), description))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -23,12 +23,12 @@ public enum WalletTypeEnum {
|
||||
|
||||
public static WalletTypeEnum valueOfByCode(String code) {
|
||||
if (ObjectUtil.isEmpty(code)) return null;
|
||||
return Arrays.stream(values()).filter(v -> ObjectUtil.equals(code, v.getCode())).findFirst().get();
|
||||
return Arrays.stream(values()).filter(v -> ObjectUtil.equals(code, v.getCode())).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public static WalletTypeEnum descOf(String description) {
|
||||
return Arrays.stream(WalletTypeEnum.values())
|
||||
.filter(v -> ObjectUtil.equal(v.getDesc(), description))
|
||||
.findFirst().get();
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
+5
@@ -32,4 +32,9 @@ public class WalletBalanceTransactionDto {
|
||||
@NotNull(message = "是否暴力消费")
|
||||
private Boolean force = false;
|
||||
|
||||
/**
|
||||
* 财务统计标签字典值,多个值使用英文逗号分隔;未传时不为流水设置标签。
|
||||
*/
|
||||
private String tags;
|
||||
|
||||
}
|
||||
+5
@@ -39,6 +39,11 @@ public class WalletTransactionDto extends WalletTransactionEntity implements Bas
|
||||
|
||||
private List<String> bizTypes;
|
||||
|
||||
/**
|
||||
* 财务统计标签筛选值;传入多个字典值时匹配包含任一标签的流水。
|
||||
*/
|
||||
private List<String> tagList;
|
||||
|
||||
private LocalDate[] createTimeList;
|
||||
|
||||
/**
|
||||
|
||||
+5
@@ -18,6 +18,11 @@ public class WalletRechargeImportDto extends WalletRechargeImportEntity implemen
|
||||
|
||||
private List<Long> userUniqueIds;
|
||||
|
||||
/**
|
||||
* 财务统计标签筛选值;传入多个字典值时匹配包含任一标签的导入记录。
|
||||
*/
|
||||
private List<String> tagList;
|
||||
|
||||
private Long userDeptId;
|
||||
|
||||
|
||||
|
||||
+15
@@ -6,6 +6,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
|
||||
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
|
||||
import com.bsd.pjcloud.common.excel.annotation.ExcelDict;
|
||||
import com.bsd.pjcloud.common.excel.annotation.ExcelLine;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@@ -42,6 +43,20 @@ public class WalletRechargeExcelDto {
|
||||
@ExcelProperty("操作金额")
|
||||
private String price;
|
||||
|
||||
/**
|
||||
* Excel 中展示和填写的财务标签名称;支持使用英文逗号分隔多个 {@code wallet_transaction_tag} 字典标签。
|
||||
*/
|
||||
@ColumnWidth(100)
|
||||
@ExcelProperty("操作标签")
|
||||
@ExcelDict(value = "wallet_transaction_tag", multiple = true)
|
||||
private String tag;
|
||||
|
||||
/**
|
||||
* 导入校验后解析出的财务标签字典值,多个值使用英文逗号分隔,不直接读取 Excel。
|
||||
*/
|
||||
@ExcelIgnore
|
||||
private String tags;
|
||||
|
||||
// 操作余额
|
||||
private Integer priceNumber;
|
||||
|
||||
|
||||
+7
-1
@@ -78,6 +78,12 @@ public class WalletTransactionEntity extends Model<WalletTransactionEntity> {
|
||||
@Schema(description = "余额, 单位分")
|
||||
private Integer balance;
|
||||
|
||||
/**
|
||||
* 财务统计标签,保存 {@code wallet_transaction_tag} 字典值;多个值使用英文逗号分隔,历史流水可为空。
|
||||
*/
|
||||
@Schema(description = "财务统计标签,多个字典值使用英文逗号分隔")
|
||||
private String tags;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@@ -119,4 +125,4 @@ public class WalletTransactionEntity extends Model<WalletTransactionEntity> {
|
||||
*/
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -67,6 +67,12 @@ public class WalletRechargeImportEntity extends Model<WalletRechargeImportEntity
|
||||
@Schema(description = "交易金额, 单位分")
|
||||
private Integer price;
|
||||
|
||||
/**
|
||||
* 财务统计标签,保存 {@code wallet_transaction_tag} 字典值;多个值使用英文逗号分隔,未选择时为空。
|
||||
*/
|
||||
@Schema(description = "财务统计标签,多个字典值使用英文逗号分隔")
|
||||
private String tags;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@@ -108,4 +114,4 @@ public class WalletRechargeImportEntity extends Model<WalletRechargeImportEntity
|
||||
*/
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.bsd.pjcloud.wallet.config;
|
||||
|
||||
import com.bsd.pjcloud.admin.api.entity.SysDictItem;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteDictService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.excel.dict.ExcelDictProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 钱包服务 Excel 字典配置。
|
||||
*/
|
||||
@Configuration
|
||||
public class ExcelDictConfiguration {
|
||||
|
||||
/**
|
||||
* 通过 UPMS 远程字典接口提供当前租户的 Excel 下拉标签。
|
||||
*
|
||||
* @param remoteDictService UPMS 字典远程服务
|
||||
* @return 钱包服务使用的 Excel 字典数据提供者;远程响应异常或无数据时返回空标签列表
|
||||
*/
|
||||
@Bean
|
||||
public ExcelDictProvider excelDictProvider(RemoteDictService remoteDictService) {
|
||||
return dictType -> {
|
||||
R<List<SysDictItem>> result = remoteDictService.getDictByType(dictType);
|
||||
if (result == null || !result.isOk() || result.getData() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return result.getData().stream().map(SysDictItem::getLabel).toList();
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -56,7 +56,7 @@ public class WalletTransactionController {
|
||||
@Inner
|
||||
@PostMapping("/add-balance")
|
||||
public R<WalletTransactionEntity> addWalletBalance(@Valid @RequestBody WalletBalanceTransactionDto dto) {
|
||||
WalletTransactionEntity walletTransaction = walletTransactionService.addWalletBalance(dto.getWalletId(), dto.getPrice(), dto.getBizId(), dto.getBizType());
|
||||
WalletTransactionEntity walletTransaction = walletTransactionService.addWalletBalance(dto.getWalletId(), dto.getPrice(), dto.getBizId(), dto.getBizType(), dto.getTags());
|
||||
if (ObjectUtil.isEmpty(walletTransaction)) return R.failed("增加钱包余额错误");
|
||||
return R.ok(walletTransaction);
|
||||
}
|
||||
|
||||
+22
-2
@@ -61,6 +61,20 @@ public interface WalletTransactionMapper extends PjcloudBaseMapper<WalletTransac
|
||||
} else if (Objects.equals(dto.getType(), WalletTransactionDto.TYPE_EXPENSE)) {
|
||||
wrapper.lt(WalletTransactionEntity::getPrice, 0);
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(dto.getTagList())) {
|
||||
wrapper.and(nested -> {
|
||||
boolean first = true;
|
||||
for (String tag : dto.getTagList()) {
|
||||
if (first) {
|
||||
nested.apply("FIND_IN_SET({0}, tags) > 0", tag);
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
nested.or().apply("FIND_IN_SET({0}, tags) > 0", tag);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@@ -98,5 +112,11 @@ public interface WalletTransactionMapper extends PjcloudBaseMapper<WalletTransac
|
||||
|
||||
List<WalletTransactionSumAndCountVo> sumAndCount(@Param("dto") WalletTransactionSumAndCountDto dto);
|
||||
|
||||
List<WalletExportCzTotalPerson> exportCzTotalPerson();
|
||||
}
|
||||
/**
|
||||
* 查询固定金额范围内的个人充值统计明细,并按财务标签筛选。
|
||||
*
|
||||
* @param dto 充值统计筛选条件;标签多选时匹配包含任一标签的流水
|
||||
* @return 个人充值统计导出明细
|
||||
*/
|
||||
List<WalletExportCzTotalPerson> exportCzTotalPerson(@Param("dto") WalletTransactionDto dto);
|
||||
}
|
||||
+22
@@ -69,6 +69,18 @@ public interface WalletTransactionService extends IService<WalletTransactionEnti
|
||||
*/
|
||||
WalletTransactionEntity addWalletBalance(Long walletId, Integer price, String bizId, WalletBizEnum bizType);
|
||||
|
||||
/**
|
||||
* 增加钱包余额并记录财务统计标签。
|
||||
*
|
||||
* @param walletId 钱包 id
|
||||
* @param price 增加金额,单位分
|
||||
* @param bizId 业务关联 id
|
||||
* @param bizType 业务关联分类
|
||||
* @param tags 财务标签字典值,多个值使用英文逗号分隔,允许为空
|
||||
* @return 已保存的钱包流水
|
||||
*/
|
||||
WalletTransactionEntity addWalletBalance(Long walletId, Integer price, String bizId, WalletBizEnum bizType, String tags);
|
||||
|
||||
/**
|
||||
* 更新会员用户余额
|
||||
*
|
||||
@@ -85,6 +97,16 @@ public interface WalletTransactionService extends IService<WalletTransactionEnti
|
||||
*/
|
||||
Boolean resetWalletBalance(Long walletId, String bizId);
|
||||
|
||||
/**
|
||||
* 重置钱包余额并记录财务统计标签。
|
||||
*
|
||||
* @param walletId 钱包 id
|
||||
* @param bizId 业务关联 id
|
||||
* @param tags 财务标签字典值,多个值使用英文逗号分隔,允许为空
|
||||
* @return 重置成功返回 {@code true}
|
||||
*/
|
||||
Boolean resetWalletBalance(Long walletId, String bizId, String tags);
|
||||
|
||||
void exportByTemplate(HttpServletResponse response, WalletTransactionDto dto, String fileName, List<WalletTransactionVo> list);
|
||||
|
||||
/**
|
||||
|
||||
+34
-2
@@ -212,6 +212,22 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
// @CacheEvict(value = CacheConstants.WALLET_DETAIL, key = "#walletId")
|
||||
public WalletTransactionEntity addWalletBalance(Long walletId, Integer price, String bizId, WalletBizEnum bizType) {
|
||||
return getSelf().addWalletBalance(walletId, price, bizId, bizType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加钱包余额并将来源业务的财务标签同步到最终流水,供后续列表筛选和金额统计。
|
||||
*
|
||||
* @param walletId 钱包 id
|
||||
* @param price 增加金额,单位分
|
||||
* @param bizId 业务关联 id
|
||||
* @param bizType 业务关联分类
|
||||
* @param tags 财务标签字典值,多个值使用英文逗号分隔,允许为空
|
||||
* @return 已保存的钱包流水
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public WalletTransactionEntity addWalletBalance(Long walletId, Integer price, String bizId, WalletBizEnum bizType, String tags) {
|
||||
WalletManageEntity wallet = walletManageService.getById(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
log.error("|{}|,用户钱包id({})不存在.", TAG, walletId);
|
||||
@@ -241,6 +257,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
insetObj.setBizId(String.valueOf(bizId));
|
||||
insetObj.setBizType(bizType.getCode());
|
||||
insetObj.setTitle(bizType.getDesc());
|
||||
insetObj.setTags(tags);
|
||||
save(insetObj);
|
||||
return insetObj;
|
||||
}
|
||||
@@ -257,7 +274,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
throw new RuntimeException("用户钱包不存在");
|
||||
}
|
||||
// 更新钱包余额
|
||||
WalletTransactionEntity result = getSelf().addWalletBalance(wallet.getId(), dto.getBalance(), String.valueOf(dto.getUserId()), WalletBizEnum.UPDATE);
|
||||
WalletTransactionEntity result = getSelf().addWalletBalance(wallet.getId(), dto.getBalance(), String.valueOf(dto.getUserId()), WalletBizEnum.UPDATE, dto.getTags());
|
||||
// 查询钱包类型
|
||||
WalletTypeEntity walletType = walletTypeMapper.selectById(wallet.getWalletTypeId());
|
||||
if (ObjectUtil.isNotEmpty(walletType) && ObjectUtil.equals(walletType.getUniqueCode(), WalletTypeEnum.EAT.getCode())) {
|
||||
@@ -276,6 +293,20 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean resetWalletBalance(Long walletId, String bizId) {
|
||||
return getSelf().resetWalletBalance(walletId, bizId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置钱包余额并将来源导入记录的财务标签同步到重置流水。
|
||||
*
|
||||
* @param walletId 钱包 id
|
||||
* @param bizId 业务关联 id
|
||||
* @param tags 财务标签字典值,多个值使用英文逗号分隔,允许为空
|
||||
* @return 重置成功返回 {@code true}
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean resetWalletBalance(Long walletId, String bizId, String tags) {
|
||||
WalletManageEntity wallet = walletManageService.getById(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
log.error("|{}|重置余额,用户钱包id({})不存在.", TAG, walletId);
|
||||
@@ -298,6 +329,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
insetObj.setBizId(String.valueOf(bizId));
|
||||
insetObj.setBizType(WalletBizEnum.RESET.getCode());
|
||||
insetObj.setTitle(WalletBizEnum.RESET.getDesc());
|
||||
insetObj.setTags(tags);
|
||||
save(insetObj);
|
||||
return true;
|
||||
}
|
||||
@@ -535,7 +567,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
String fileName = "file/个人充值统计800、1600、2400.xlsx";
|
||||
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(ResourceUtil.getStream(fileName)).build()) {
|
||||
// 查询导出数据
|
||||
List<WalletExportCzTotalPerson> list = baseMapper.exportCzTotalPerson();
|
||||
List<WalletExportCzTotalPerson> list = baseMapper.exportCzTotalPerson(dto);
|
||||
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet().build();
|
||||
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
|
||||
|
||||
+52
-8
@@ -12,8 +12,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.admin.api.dto.UserInfo;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysDept;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysDictItem;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteDictService;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.admin.api.utils.DataUtil;
|
||||
import com.bsd.pjcloud.admin.api.vo.UserVO;
|
||||
@@ -90,6 +92,11 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
|
||||
static private final String TAG = "充值/扣款申请";
|
||||
|
||||
/**
|
||||
* 充值流水财务标签使用的 UPMS 字典类型,Excel 展示标签而数据库保存对应字典值。
|
||||
*/
|
||||
private static final String TRANSACTION_TAG_DICT_TYPE = "wallet_transaction_tag";
|
||||
|
||||
private final WalletRechargeImportServiceImpl rechargeImportService;
|
||||
private final WalletManageService walletManageService;
|
||||
private final WalletTransactionService walletTransactionService;
|
||||
@@ -103,6 +110,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
|
||||
private final RemoteUserService userService;
|
||||
private final RemoteDeptService deptService;
|
||||
private final RemoteDictService remoteDictService;
|
||||
private final RemoteFlowEngineService flowEngineService;
|
||||
|
||||
private final FlowUtil flowUtil;
|
||||
@@ -328,7 +336,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
if (i <= 0) {
|
||||
throw new RuntimeException("导入失败");
|
||||
}
|
||||
List<WalletRechargeImportEntity> batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(v.getPriceNumber()).userId(v.getUserId()).userDeptId(v.getUserDeptId()).build()).toList();
|
||||
List<WalletRechargeImportEntity> batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(v.getPriceNumber()).userId(v.getUserId()).userDeptId(v.getUserDeptId()).tags(v.getTags()).build()).toList();
|
||||
batchSaveList.forEach(v -> v.setApplyId(insertObj.getId()));
|
||||
rechargeImportService.saveBatch(batchSaveList);
|
||||
return R.ok(null, "导入成功");
|
||||
@@ -349,7 +357,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
if (i <= 0) {
|
||||
throw new RuntimeException("导入失败");
|
||||
}
|
||||
List<WalletRechargeImportEntity> batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(0).userId(v.getUserId()).userDeptId(v.getUserDeptId()).build()).toList();
|
||||
List<WalletRechargeImportEntity> batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(0).userId(v.getUserId()).userDeptId(v.getUserDeptId()).tags(v.getTags()).build()).toList();
|
||||
batchSaveList.forEach(v -> v.setApplyId(insertObj.getId()));
|
||||
rechargeImportService.saveBatch(batchSaveList);
|
||||
return R.ok(null, "导入成功");
|
||||
@@ -371,7 +379,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
WalletRechargeInvoiceEntity invoice = walletRechargeInvoiceService.createBaseInvoice(loginUser, totalPrice);
|
||||
if (ObjectUtil.isEmpty(invoice)) throw new RuntimeException("导入失败");
|
||||
// 导入数据
|
||||
List<WalletRechargeImportEntity> batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(v.getPriceNumber()).userId(v.getUserId()).userDeptId(v.getUserDeptId()).invoiceId(invoice.getId()).build()).toList();
|
||||
List<WalletRechargeImportEntity> batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(v.getPriceNumber()).userId(v.getUserId()).userDeptId(v.getUserDeptId()).invoiceId(invoice.getId()).tags(v.getTags()).build()).toList();
|
||||
rechargeImportService.saveBatch(batchSaveList);
|
||||
return R.ok(null, "导入成功");
|
||||
}
|
||||
@@ -388,6 +396,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
throw new RuntimeException("读取excel数据错误");
|
||||
}
|
||||
List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
|
||||
resolveTransactionTagValues(list, errorMessageList);
|
||||
List<String> usernameList = list.stream().map(WalletRechargeExcelDto::getUsername).toList();
|
||||
List<String> userPoneList = list.stream().map(WalletRechargeExcelDto::getUserMobile).toList();
|
||||
for (WalletRechargeExcelDto v : list) {
|
||||
@@ -442,6 +451,41 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
return ImmutablePair.of(null, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Excel 中展示的财务标签转换为稳定的字典值,供导入记录和最终钱包流水持久化及统计查询。
|
||||
*
|
||||
* @param list 已通过公共 Excel 字典标签校验的数据行
|
||||
* @param errorMessageList 当前导入任务的行级错误集合,字典服务异常或标签映射缺失时追加错误
|
||||
*/
|
||||
private void resolveTransactionTagValues(List<WalletRechargeExcelDto> list, List<ErrorMessage> errorMessageList) {
|
||||
List<WalletRechargeExcelDto> taggedRows = list.stream().filter(item -> ObjectUtil.isNotEmpty(item.getTag())).toList();
|
||||
if (taggedRows.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
R<List<SysDictItem>> result = remoteDictService.getDictByType(TRANSACTION_TAG_DICT_TYPE);
|
||||
if (result == null || !result.isOk() || ObjectUtil.isEmpty(result.getData())) {
|
||||
taggedRows.forEach(item -> errorMessageList.add(new ErrorMessage(item.getLineNum(), Set.of("操作标签字典查询失败"))));
|
||||
return;
|
||||
}
|
||||
Map<String, String> valueByLabel = result.getData().stream()
|
||||
.filter(item -> ObjectUtil.isNotEmpty(item.getLabel()) && ObjectUtil.isNotEmpty(item.getItemValue()))
|
||||
.collect(java.util.stream.Collectors.toMap(SysDictItem::getLabel, SysDictItem::getItemValue, (first, ignored) -> first));
|
||||
for (WalletRechargeExcelDto item : taggedRows) {
|
||||
List<String> tagValues = Arrays.stream(item.getTag().split(","))
|
||||
.map(String::trim)
|
||||
.distinct()
|
||||
.map(valueByLabel::get)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
long selectedTagCount = Arrays.stream(item.getTag().split(",")).map(String::trim).distinct().count();
|
||||
if (tagValues.size() != selectedTagCount) {
|
||||
errorMessageList.add(new ErrorMessage(item.getLineNum(), Set.of("操作标签包含无法映射的字典项")));
|
||||
continue;
|
||||
}
|
||||
item.setTags(String.join(",", tagValues));
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************* end excel end ************************************* */
|
||||
|
||||
@Override
|
||||
@@ -497,7 +541,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
}
|
||||
// 判断是`退还各自食堂`还是`批量更新余额`
|
||||
WalletBizEnum walletBiz = ObjectUtil.equal(WalletBizRechargeEnum.RETURN_CANTEEN.getCode(), detail.getBizType()) ? WalletBizEnum.RETURN_CANTEEN : WalletBizEnum.BATCH;
|
||||
walletTransactionService.addWalletBalance(wallet.getId(), v.getPrice(), String.valueOf(v.getId()), walletBiz);
|
||||
walletTransactionService.addWalletBalance(wallet.getId(), v.getPrice(), String.valueOf(v.getId()), walletBiz, v.getTags());
|
||||
}
|
||||
// 同步到正元钱包状态
|
||||
List<Long> userIds = importList.stream().map(WalletRechargeImportEntity::getUserId).distinct().toList();
|
||||
@@ -548,7 +592,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
continue;
|
||||
}
|
||||
walletTransactionService.resetWalletBalance(wallet.getId(), String.valueOf(v.getId()));
|
||||
walletTransactionService.resetWalletBalance(wallet.getId(), String.valueOf(v.getId()), v.getTags());
|
||||
}
|
||||
log.info("|{}|重置余额审批回调,dto:|{}", TAG, JSON.toJSONString(detail));
|
||||
} catch (Exception e) {
|
||||
@@ -766,9 +810,9 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
if (ObjectUtil.isEmpty(cardWalletVo)) continue;
|
||||
// 先判断消费钱包是不是够用
|
||||
int discountPrice = payWalletVo.getBalance() - i.getPrice();
|
||||
walletTransactionService.addWalletBalance(payWalletVo.getId(), payWalletVo.getBalance() * -1, String.valueOf(i.getId()), WalletBizEnum.BATCH);
|
||||
walletTransactionService.addWalletBalance(payWalletVo.getId(), payWalletVo.getBalance() * -1, String.valueOf(i.getId()), WalletBizEnum.BATCH, i.getTags());
|
||||
if (discountPrice < 0) {
|
||||
walletTransactionService.addWalletBalance(cardWalletVo.getId(), discountPrice, String.valueOf(i.getId()), WalletBizEnum.BATCH);
|
||||
walletTransactionService.addWalletBalance(cardWalletVo.getId(), discountPrice, String.valueOf(i.getId()), WalletBizEnum.BATCH, i.getTags());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -776,4 +820,4 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl<WalletRechargeAp
|
||||
private WalletRechargeApplyServiceImpl getSelf() {
|
||||
return SpringUtil.getBean(getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -124,7 +124,7 @@ public class WalletRechargeImportServiceImpl extends ServiceImpl<WalletRechargeI
|
||||
if (ObjectUtil.isNotEmpty(walletTransaction)) throw new RuntimeException("钱包已经充值过");
|
||||
WalletManageEntity wallet = walletManageService.getOrCreateWallet(rechargeImport.getUserId(), walletTypeEnum);
|
||||
if (ObjectUtil.isEmpty(wallet)) throw new RuntimeException("钱包错误");
|
||||
walletTransactionService.addWalletBalance(wallet.getId(), rechargeImport.getPrice(), String.valueOf(rechargeImport.getId()), WalletBizEnum.BATCH);
|
||||
walletTransactionService.addWalletBalance(wallet.getId(), rechargeImport.getPrice(), String.valueOf(rechargeImport.getId()), WalletBizEnum.BATCH, rechargeImport.getTags());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -149,4 +149,4 @@ public class WalletRechargeImportServiceImpl extends ServiceImpl<WalletRechargeI
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-1
@@ -10,6 +10,7 @@
|
||||
<result property="title" column="title"/>
|
||||
<result property="price" column="price"/>
|
||||
<result property="balance" column="balance"/>
|
||||
<result property="tags" column="tags"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectA">
|
||||
@@ -22,6 +23,7 @@
|
||||
a.title,
|
||||
a.price,
|
||||
a.balance,
|
||||
a.tags,
|
||||
a.create_by,
|
||||
a.create_time,
|
||||
a.update_by,
|
||||
@@ -44,6 +46,13 @@
|
||||
<if test="dto.bizType != null">
|
||||
and a.biz_type = #{dto.bizType}
|
||||
</if>
|
||||
<if test="dto.tagList != null and dto.tagList.size() != 0">
|
||||
and (
|
||||
<foreach collection="dto.tagList" item="tag" separator=" or ">
|
||||
FIND_IN_SET(#{tag}, a.tags) > 0
|
||||
</foreach>
|
||||
)
|
||||
</if>
|
||||
<if test="dto.deptId != null">
|
||||
and a.dept_id = #{dto.deptId}
|
||||
</if>
|
||||
@@ -286,6 +295,13 @@
|
||||
and t.biz_type in ('1', '2', '3')
|
||||
and t.price in (80000, 160000, 240000)
|
||||
and t.dept_id not in (1875013738914156546, 1910218102049226753, 1910218128624336898, 1942046316044144642)
|
||||
<if test="dto.tagList != null and dto.tagList.size() != 0">
|
||||
and (
|
||||
<foreach collection="dto.tagList" item="tag" separator=" or ">
|
||||
FIND_IN_SET(#{tag}, t.tags) > 0
|
||||
</foreach>
|
||||
)
|
||||
</if>
|
||||
order by v.mchId, v.deptId
|
||||
</select>
|
||||
|
||||
@@ -303,4 +319,4 @@
|
||||
</where>
|
||||
)
|
||||
</select>
|
||||
</mapper>
|
||||
</mapper>
|
||||
+10
-1
@@ -9,6 +9,7 @@
|
||||
<result property="applyId" column="apply_id"/>
|
||||
<result property="beforePrice" column="before_price"/>
|
||||
<result property="price" column="price"/>
|
||||
<result property="tags" column="tags"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
@@ -24,6 +25,7 @@
|
||||
a.apply_id,
|
||||
a.before_price,
|
||||
a.price,
|
||||
a.tags,
|
||||
a.create_by,
|
||||
a.create_time,
|
||||
a.update_by,
|
||||
@@ -71,6 +73,13 @@
|
||||
<if test="dto.createTimeList != null and dto.createTimeList.length == 2">
|
||||
and a.create_time between #{dto.createTimeList[0]} and #{dto.createTimeList[1]}
|
||||
</if>
|
||||
<if test="dto.tagList != null and dto.tagList.size() != 0">
|
||||
and (
|
||||
<foreach collection="dto.tagList" item="tag" separator=" or ">
|
||||
FIND_IN_SET(#{tag}, a.tags) > 0
|
||||
</foreach>
|
||||
)
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<sql id="selectJoin">
|
||||
@@ -134,4 +143,4 @@
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
||||
</mapper>
|
||||
Reference in new issue
Block a user