diff --git a/db/20260813_add_wallet_transaction_tags.sql b/db/20260813_add_wallet_transaction_tags.sql
new file mode 100644
index 00000000..cbe85615
--- /dev/null
+++ b/db/20260813_add_wallet_transaction_tags.sql
@@ -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;
diff --git a/db/800pjcloudx_wallet.sql b/db/800pjcloudx_wallet.sql
index 42efd830..c4583ce2 100644
--- a/db/800pjcloudx_wallet.sql
+++ b/db/800pjcloudx_wallet.sql
@@ -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 '修改人',
diff --git a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelDict.java b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelDict.java
index 2b88ff1f..828ceb59 100644
--- a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelDict.java
+++ b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelDict.java
@@ -9,6 +9,7 @@ import java.lang.annotation.Target;
/**
* Excel 字典字段。
*
导入时校验单元格内容是否为字典标签,导出模板时将同一字典标签写入下拉选项。
+ * 多选字段在普通 Excel 中使用英文逗号分隔多个标签;原生下拉仅负责提供选项,无法自动追加多次选择。
*/
@Documented
@Target(ElementType.FIELD)
@@ -20,4 +21,11 @@ public @interface ExcelDict {
*/
String value();
+ /**
+ * 是否允许一个单元格填写多个字典标签。
+ *
+ * @return {@code true} 时按英文逗号拆分并逐项校验,{@code false} 时整个单元格只能是一个字典标签
+ */
+ boolean multiple() default false;
+
}
diff --git a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelTemplate.java b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelTemplate.java
index b295cf39..1dc04717 100644
--- a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelTemplate.java
+++ b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/annotation/ExcelTemplate.java
@@ -8,11 +8,18 @@ import java.lang.annotation.Target;
/**
* Excel 模板增强。
- * 切面自动收集 {@link RequestExcel} 导入参数中的模型,下载接口无需感知文件名或具体业务模型。
+ * 切面默认自动收集当前服务 {@link RequestExcel} 导入参数中的模型;跨服务模型可通过注解参数显式补充。
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelTemplate {
+ /**
+ * 当前下载接口需要额外处理的 Excel 模型,用于补充当前服务无法自动扫描到的跨服务导入模型。
+ *
+ * @return 需要参与模板字典下拉增强的模型类型;默认不额外补充模型
+ */
+ Class>[] value() default {};
+
}
diff --git a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/aop/ExcelTemplateAspect.java b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/aop/ExcelTemplateAspect.java
index 9ba53d64..6918a987 100644
--- a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/aop/ExcelTemplateAspect.java
+++ b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/aop/ExcelTemplateAspect.java
@@ -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} 是模板模型的唯一来源,新增导入模型无需再修改下载接口或注册表。
+ * 自动收集当前服务导入接口中的 {@code @RequestExcel List} 模型,供未显式注册的同服务模板继续使用。
*/
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;
}
}
diff --git a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/dict/ExcelDictDataValidationWriter.java b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/dict/ExcelDictDataValidationWriter.java
index f0837dce..a9b73fb6 100644
--- a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/dict/ExcelDictDataValidationWriter.java
+++ b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/dict/ExcelDictDataValidationWriter.java
@@ -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 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);
}
diff --git a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/handler/DefaultAnalysisEventListener.java b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/handler/DefaultAnalysisEventListener.java
index ade9e13d..4bd9519b 100644
--- a/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/handler/DefaultAnalysisEventListener.java
+++ b/pjcloud-common/pjcloud-common-excel/src/main/java/com/bsd/pjcloud/common/excel/handler/DefaultAnalysisEventListener.java
@@ -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 validateExcelDict(Object data) {
Set messages = new LinkedHashSet<>();
@@ -82,14 +86,24 @@ public class DefaultAnalysisEventListener extends ListAnalysisEventListener 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 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 invalidLabels = selectedLabels.stream().filter(label -> !labels.contains(label)).distinct().toList();
+ if (!invalidLabels.isEmpty()) {
+ messages.add(fieldName + ":" + String.join(",", invalidLabels) + ",不在可选项中");
+ }
}
}
catch (IllegalAccessException exception) {
diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml
index 8778e507..11ab4640 100644
--- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml
+++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/pom.xml
@@ -146,6 +146,13 @@
spring-boot-starter-test
test
+
+
+ org.mockito
+ mockito-core
+ 5.11.0
+ test
+
com.bsd
diff --git a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusWechatServiceImplPayCallbackTest.java b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusWechatServiceImplPayCallbackTest.java
index 4692cfbc..a436cf11 100644
--- a/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusWechatServiceImplPayCallbackTest.java
+++ b/pjcloud-thirdparty/pjcloud-thirdparty-biz/src/test/java/com/bsd/pjcloud/thirdparty/service/impl/appplus/ThirdAppPlusWechatServiceImplPayCallbackTest.java
@@ -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;
diff --git a/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/vo/StudentUserExcelVO.java b/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/vo/StudentUserExcelVO.java
index f9c428ae..3fcd3fa3 100644
--- a/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/vo/StudentUserExcelVO.java
+++ b/pjcloud-upms/pjcloud-upms-api/src/main/java/com/bsd/pjcloud/admin/api/vo/StudentUserExcelVO.java
@@ -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;
+
/**
* 学校名称
*/
diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysFileController.java b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysFileController.java
index 8279a215..79075bee 100644
--- a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysFileController.java
+++ b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysFileController.java
@@ -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);
diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysUserController.java b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysUserController.java
index fd105598..68070e18 100644
--- a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysUserController.java
+++ b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/controller/SysUserController.java
@@ -421,7 +421,7 @@ public class SysUserController {
* @return 校验失败时包含对应行号和错误原因;校验通过时包含异步任务 ID 和初始进度
*/
@PostMapping("/import")
- @HasPermission("sys_user_export")
+ @HasPermission("sys_user_import")
public R> importUser(@RequestExcel List 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 excelList, BindingResult bindingResult) {
return userImportExportService.importUserFace(file, excelList, bindingResult);
diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysUserImportExportServiceImpl.java b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysUserImportExportServiceImpl.java
index 02dafddd..0b3123d5 100644
--- a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysUserImportExportServiceImpl.java
+++ b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysUserImportExportServiceImpl.java
@@ -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 guardianPhones = studentUserExcelList.stream().map(StudentUserExcelVO::getGuardianPhone)
.filter(StrUtil::isNotBlank).distinct().toList();
Map 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());
diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/student_user_import.xlsx b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/student_user_import.xlsx
index 284f54b7..320b9389 100644
Binary files a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/student_user_import.xlsx and b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/student_user_import.xlsx differ
diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/wallet_recharge.xlsx b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/wallet_recharge.xlsx
index 3d4d1cd2..d9a72455 100644
Binary files a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/wallet_recharge.xlsx and b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/file/wallet_recharge.xlsx differ
diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysUserMapper.xml b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysUserMapper.xml
index 45feeaad..5b261499 100644
--- a/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysUserMapper.xml
+++ b/pjcloud-upms/pjcloud-upms-biz/src/main/resources/mapper/SysUserMapper.xml
@@ -219,6 +219,18 @@
AND u.staffing_type = #{query.staffingType}
+
+
+ AND EXISTS (
+ SELECT 1
+ FROM sys_user_identity user_identity
+ WHERE user_identity.user_id = u.user_id
+ AND user_identity.identity_type IN
+
+ #{identityType}
+
+ )
+
and urole.role_id IN
@@ -307,6 +319,18 @@
AND u.dept_id = #{query.deptId}
+
+
+ AND EXISTS (
+ SELECT 1
+ FROM sys_user_identity user_identity
+ WHERE user_identity.user_id = u.user_id
+ AND user_identity.identity_type IN
+
+ #{identityType}
+
+ )
+
and urole.role_id IN
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/constant/WalletTransactionTag.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/constant/WalletTransactionTag.java
new file mode 100644
index 00000000..0eb4aeef
--- /dev/null
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/constant/WalletTransactionTag.java
@@ -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);
+ }
+
+}
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/constant/WalletTypeEnum.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/constant/WalletTypeEnum.java
index e71c525b..7630e505 100644
--- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/constant/WalletTypeEnum.java
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/constant/WalletTypeEnum.java
@@ -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);
}
}
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletBalanceTransactionDto.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletBalanceTransactionDto.java
index 2e7d0e0f..5faf255e 100644
--- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletBalanceTransactionDto.java
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletBalanceTransactionDto.java
@@ -32,4 +32,9 @@ public class WalletBalanceTransactionDto {
@NotNull(message = "是否暴力消费")
private Boolean force = false;
+ /**
+ * 财务统计标签字典值,多个值使用英文逗号分隔;未传时不为流水设置标签。
+ */
+ private String tags;
+
}
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletTransactionDto.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletTransactionDto.java
index 3fdf245f..4a98183d 100644
--- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletTransactionDto.java
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/WalletTransactionDto.java
@@ -39,6 +39,11 @@ public class WalletTransactionDto extends WalletTransactionEntity implements Bas
private List bizTypes;
+ /**
+ * 财务统计标签筛选值;传入多个字典值时匹配包含任一标签的流水。
+ */
+ private List tagList;
+
private LocalDate[] createTimeList;
/**
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeImportDto.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeImportDto.java
index 0220b420..32b451d6 100644
--- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeImportDto.java
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeImportDto.java
@@ -18,6 +18,11 @@ public class WalletRechargeImportDto extends WalletRechargeImportEntity implemen
private List userUniqueIds;
+ /**
+ * 财务统计标签筛选值;传入多个字典值时匹配包含任一标签的导入记录。
+ */
+ private List tagList;
+
private Long userDeptId;
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/excel/WalletRechargeExcelDto.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/excel/WalletRechargeExcelDto.java
index 6697c9df..577256eb 100644
--- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/excel/WalletRechargeExcelDto.java
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/excel/WalletRechargeExcelDto.java
@@ -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;
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/WalletTransactionEntity.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/WalletTransactionEntity.java
index 55d771e3..7e0529e8 100644
--- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/WalletTransactionEntity.java
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/WalletTransactionEntity.java
@@ -78,6 +78,12 @@ public class WalletTransactionEntity extends Model {
@Schema(description = "余额, 单位分")
private Integer balance;
+ /**
+ * 财务统计标签,保存 {@code wallet_transaction_tag} 字典值;多个值使用英文逗号分隔,历史流水可为空。
+ */
+ @Schema(description = "财务统计标签,多个字典值使用英文逗号分隔")
+ private String tags;
+
/**
* 创建人
*/
@@ -119,4 +125,4 @@ public class WalletTransactionEntity extends Model {
*/
@Schema(description = "租户ID")
private Long tenantId;
-}
\ No newline at end of file
+}
diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeImportEntity.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeImportEntity.java
index fc35e52f..d006d8dd 100644
--- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeImportEntity.java
+++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeImportEntity.java
@@ -67,6 +67,12 @@ public class WalletRechargeImportEntity extends Model {
+ R> result = remoteDictService.getDictByType(dictType);
+ if (result == null || !result.isOk() || result.getData() == null) {
+ return Collections.emptyList();
+ }
+ return result.getData().stream().map(SysDictItem::getLabel).toList();
+ };
+ }
+
+}
diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/WalletTransactionController.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/WalletTransactionController.java
index d9498856..e69a7a85 100644
--- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/WalletTransactionController.java
+++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/WalletTransactionController.java
@@ -56,7 +56,7 @@ public class WalletTransactionController {
@Inner
@PostMapping("/add-balance")
public R 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);
}
diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/mapper/WalletTransactionMapper.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/mapper/WalletTransactionMapper.java
index 24e1d0a8..225e311f 100644
--- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/mapper/WalletTransactionMapper.java
+++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/mapper/WalletTransactionMapper.java
@@ -61,6 +61,20 @@ public interface WalletTransactionMapper extends PjcloudBaseMapper {
+ 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 sumAndCount(@Param("dto") WalletTransactionSumAndCountDto dto);
- List exportCzTotalPerson();
-}
\ No newline at end of file
+ /**
+ * 查询固定金额范围内的个人充值统计明细,并按财务标签筛选。
+ *
+ * @param dto 充值统计筛选条件;标签多选时匹配包含任一标签的流水
+ * @return 个人充值统计导出明细
+ */
+ List exportCzTotalPerson(@Param("dto") WalletTransactionDto dto);
+}
diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletTransactionService.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletTransactionService.java
index 3f654347..7d3eeb85 100644
--- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletTransactionService.java
+++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletTransactionService.java
@@ -69,6 +69,18 @@ public interface WalletTransactionService extends IService list);
/**
diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/WalletTransactionServiceImpl.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/WalletTransactionServiceImpl.java
index 6e1d0128..36cefd52 100644
--- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/WalletTransactionServiceImpl.java
+++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/WalletTransactionServiceImpl.java
@@ -212,6 +212,22 @@ public class WalletTransactionServiceImpl extends ServiceImpl list = baseMapper.exportCzTotalPerson();
+ List list = baseMapper.exportCzTotalPerson(dto);
WriteSheet writeSheet = EasyExcel.writerSheet().build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeApplyServiceImpl.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeApplyServiceImpl.java
index e4a2f74e..a755fa87 100644
--- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeApplyServiceImpl.java
+++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeApplyServiceImpl.java
@@ -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 batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(v.getPriceNumber()).userId(v.getUserId()).userDeptId(v.getUserDeptId()).build()).toList();
+ List 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 batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(0).userId(v.getUserId()).userDeptId(v.getUserDeptId()).build()).toList();
+ List 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 batchSaveList = list.stream().map(v -> WalletRechargeImportEntity.builder().price(v.getPriceNumber()).userId(v.getUserId()).userDeptId(v.getUserDeptId()).invoiceId(invoice.getId()).build()).toList();
+ List 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 errorMessageList = (List) bindingResult.getTarget();
+ resolveTransactionTagValues(list, errorMessageList);
List usernameList = list.stream().map(WalletRechargeExcelDto::getUsername).toList();
List userPoneList = list.stream().map(WalletRechargeExcelDto::getUserMobile).toList();
for (WalletRechargeExcelDto v : list) {
@@ -442,6 +451,41 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl list, List errorMessageList) {
+ List taggedRows = list.stream().filter(item -> ObjectUtil.isNotEmpty(item.getTag())).toList();
+ if (taggedRows.isEmpty()) {
+ return;
+ }
+ R> 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 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 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 userIds = importList.stream().map(WalletRechargeImportEntity::getUserId).distinct().toList();
@@ -548,7 +592,7 @@ public class WalletRechargeApplyServiceImpl extends ServiceImpl
+
@@ -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 @@
and a.biz_type = #{dto.bizType}
+
+ and (
+
+ FIND_IN_SET(#{tag}, a.tags) > 0
+
+ )
+
and a.dept_id = #{dto.deptId}
@@ -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)
+
+ and (
+
+ FIND_IN_SET(#{tag}, t.tags) > 0
+
+ )
+
order by v.mchId, v.deptId
@@ -303,4 +319,4 @@
)
-
\ No newline at end of file
+
diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeImportMapper.xml b/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeImportMapper.xml
index 2d7394b3..086f0d75 100644
--- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeImportMapper.xml
+++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeImportMapper.xml
@@ -9,6 +9,7 @@
+
@@ -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 @@
and a.create_time between #{dto.createTimeList[0]} and #{dto.createTimeList[1]}
+
+ and (
+
+ FIND_IN_SET(#{tag}, a.tags) > 0
+
+ )
+
@@ -134,4 +143,4 @@
-
\ No newline at end of file
+