diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml
index 1d0a883..a51612f 100644
--- a/.idea/sqldialects.xml
+++ b/.idea/sqldialects.xml
@@ -3,7 +3,7 @@
-
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index bd2d695..885b084 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
com.imyeyu.timiserverapi
TimiServerAPI
- 1.0.11
+ 1.0.12
jar
TimiServerAPI
imyeyu.com API
diff --git a/src/main/java/com/imyeyu/api/bean/CorePermissionCode.java b/src/main/java/com/imyeyu/api/bean/CorePermissionCode.java
index fba6068..652cdb4 100644
--- a/src/main/java/com/imyeyu/api/bean/CorePermissionCode.java
+++ b/src/main/java/com/imyeyu/api/bean/CorePermissionCode.java
@@ -39,6 +39,12 @@ public enum CorePermissionCode implements BuiltinPermissionCode {
MULTILINGUAL_UPDATE("MULTILINGUAL:UPDATE", "多语言修改", false, true),
MULTILINGUAL_DELETE("MULTILINGUAL:DELETE", "多语言删除", false, true),
+ TAG_CREATE("TAG:CREATE", "标签创建", false, true),
+ TAG_READ("TAG:READ", "标签读取", false, true),
+ TAG_APPLY("TAG:APPLY", "标签应用", false, true),
+ TAG_UPDATE("TAG:UPDATE", "标签修改", false, true),
+ TAG_DELETE("TAG:DELETE", "标签删除", false, true),
+
USER_CREATE("USER:CREATE", "用户创建", false, true),
USER_READ("USER:READ", "用户读取", false, true),
USER_UPDATE("USER:UPDATE", "用户修改", false, true),
diff --git a/src/main/java/com/imyeyu/api/config/WebConfig.java b/src/main/java/com/imyeyu/api/config/WebConfig.java
index 6be5503..dbf545c 100644
--- a/src/main/java/com/imyeyu/api/config/WebConfig.java
+++ b/src/main/java/com/imyeyu/api/config/WebConfig.java
@@ -10,7 +10,6 @@ import com.imyeyu.api.annotation.EnableSettingInterceptor;
import com.imyeyu.api.annotation.RequestRateLimitInterceptor;
import com.imyeyu.api.annotation.RequireCorePermissionInterceptor;
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermissionInterceptor;
-import com.imyeyu.api.modules.gao.annotation.RequireGaoRoleInterceptor;
import com.imyeyu.api.modules.journal.util.JournalAPIInterceptor;
import com.imyeyu.api.modules.system.util.SystemAPIInterceptor;
import com.imyeyu.spring.annotation.RequestBodyValueArgumentResolver;
@@ -42,7 +41,6 @@ public class WebConfig implements WebMvcConfigurer {
private final SystemAPIInterceptor systemAPIInterceptor;
private final JournalAPIInterceptor journalAPIInterceptor;
private final EnableSettingInterceptor enableSettingInterceptor;
- private final RequireGaoRoleInterceptor requireGaoRoleInterceptor;
private final RequestRateLimitInterceptor requestRateLimitInterceptor;
private final RequireGaoPermissionInterceptor requireGaoPermissionInterceptor;
private final RequireCorePermissionInterceptor requireCorePermissionInterceptor;
@@ -58,7 +56,6 @@ public class WebConfig implements WebMvcConfigurer {
registry.addInterceptor(journalAPIInterceptor).addPathPatterns(JournalAPIInterceptor.PATH);
registry.addInterceptor(enableSettingInterceptor).addPathPatterns("/**");
registry.addInterceptor(requireCorePermissionInterceptor).addPathPatterns("/**");
- registry.addInterceptor(requireGaoRoleInterceptor).addPathPatterns("/**");
registry.addInterceptor(requireGaoPermissionInterceptor).addPathPatterns("/**");
registry.addInterceptor(requestRateLimitInterceptor).addPathPatterns("/**");
}
diff --git a/src/main/java/com/imyeyu/api/modules/common/controller/TagController.java b/src/main/java/com/imyeyu/api/modules/common/controller/TagController.java
new file mode 100644
index 0000000..604b4d4
--- /dev/null
+++ b/src/main/java/com/imyeyu/api/modules/common/controller/TagController.java
@@ -0,0 +1,111 @@
+package com.imyeyu.api.modules.common.controller;
+
+import com.fasterxml.jackson.annotation.JsonView;
+import com.imyeyu.api.modules.common.entity.Tag;
+import com.imyeyu.api.modules.common.entity.TagApply;
+import com.imyeyu.api.modules.common.service.TagService;
+import com.imyeyu.spring.annotation.AOPLog;
+import com.imyeyu.spring.annotation.RequestRateLimit;
+import com.imyeyu.spring.bean.Page;
+import com.imyeyu.spring.bean.PageResult;
+import com.imyeyu.spring.util.ResponseView;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/// 标签接口
+///
+/// @author 夜雨
+/// @since 2026-08-12 15:09
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/tag")
+public class TagController {
+
+ private final TagService service;
+
+ /// 查询标签列表
+ ///
+ /// @param page 分页参数
+ /// @return 标签分页
+ @RequestRateLimit
+ @JsonView(ResponseView.Public.class)
+ @PostMapping("/list")
+ public PageResult list(@RequestBody Page page) {
+ return service.page(page);
+ }
+
+ /// 查询标签详情
+ ///
+ /// @param id 标签 ID
+ /// @return 标签详情
+ @RequestRateLimit
+ @JsonView(ResponseView.Public.class)
+ @PostMapping("/detail")
+ public Tag detail(@RequestParam String id) {
+ return service.get(id);
+ }
+
+ /// 创建标签
+ ///
+ /// @param tag 标签
+ /// @return 标签
+ @AOPLog
+ @RequestRateLimit
+ @JsonView(ResponseView.Public.class)
+ @PostMapping("/create")
+ public Tag create(@RequestBody Tag tag) {
+ service.create(tag);
+ return tag;
+ }
+
+ /// 更新标签
+ ///
+ /// @param tag 标签
+ @AOPLog
+ @RequestRateLimit
+ @PostMapping("/update")
+ public void update(@RequestBody Tag tag) {
+ service.update(tag);
+ }
+
+ /// 删除标签
+ ///
+ /// @param id 标签 ID
+ @AOPLog
+ @RequestRateLimit
+ @PostMapping("/delete")
+ public void delete(@RequestParam String id) {
+ service.delete(id);
+ }
+
+ /// 按业务查询标签
+ ///
+ /// @param bizType 业务类型
+ /// @param bizId 业务 ID
+ /// @return 标签列表
+ @RequestRateLimit
+ @JsonView(ResponseView.Public.class)
+ @GetMapping("/list/biz/id")
+ public List listByBizType(@RequestParam TagApply.BizType bizType, @RequestParam String bizId) {
+ return service.listByBizType(bizType, bizId);
+ }
+
+ /// 差分保存业务标签
+ ///
+ /// @param apply 标签请求
+ @AOPLog
+ @RequestRateLimit
+ @PostMapping("/apply")
+ public void apply(@RequestBody TagApply apply) {
+ service.apply(apply.getBizType(), apply.getBizId(), apply.getTagIdList());
+ }
+}
diff --git a/src/main/java/com/imyeyu/api/modules/common/entity/Tag.java b/src/main/java/com/imyeyu/api/modules/common/entity/Tag.java
index eb2bb7e..32b3af3 100644
--- a/src/main/java/com/imyeyu/api/modules/common/entity/Tag.java
+++ b/src/main/java/com/imyeyu/api/modules/common/entity/Tag.java
@@ -1,23 +1,28 @@
package com.imyeyu.api.modules.common.entity;
+import com.imyeyu.api.annotation.MultilingualField;
import com.imyeyu.spring.annotation.table.Transient;
import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
-/**
- * @author 夜雨
- * @since 2024-08-28 14:26
- */
+/// 标签
+///
+/// @author 夜雨
+/// @since 2024-08-28 14:26
@Data
@EqualsAndHashCode(callSuper = true)
public class Tag extends UUIDEntity {
- protected String langKey;
+ /// 名称多语言 ID
+ protected String nameLangId;
+ /// 当前语言名称
@Transient
- protected String value;
+ @MultilingualField("nameLangId")
+ protected String name;
+ /// 中文名称
@Transient
protected String zhCN;
}
diff --git a/src/main/java/com/imyeyu/api/modules/common/entity/TagApply.java b/src/main/java/com/imyeyu/api/modules/common/entity/TagApply.java
index b2d9059..8c934c9 100644
--- a/src/main/java/com/imyeyu/api/modules/common/entity/TagApply.java
+++ b/src/main/java/com/imyeyu/api/modules/common/entity/TagApply.java
@@ -1,9 +1,12 @@
package com.imyeyu.api.modules.common.entity;
+import com.imyeyu.spring.annotation.table.Transient;
import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import java.util.List;
+
/**
* 标签应用
*
@@ -14,12 +17,25 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
public class TagApply extends UUIDEntity {
+ ///
+ ///
+ /// @author 夜雨
+ /// @since 2026-08-12 14:27
+ public enum BizType {
+
+ GAO_CUSTOMER
+ }
+
/** 业务类型 */
- protected String bizType;
+ protected BizType bizType;
/** 业务 ID */
protected String bizId;
/** 标签 ID */
protected String tagId;
+
+ /// 标签 ID 列表
+ @Transient
+ private List tagIdList;
}
diff --git a/src/main/java/com/imyeyu/api/modules/common/mapper/TagApplyMapper.java b/src/main/java/com/imyeyu/api/modules/common/mapper/TagApplyMapper.java
new file mode 100644
index 0000000..5920367
--- /dev/null
+++ b/src/main/java/com/imyeyu/api/modules/common/mapper/TagApplyMapper.java
@@ -0,0 +1,11 @@
+package com.imyeyu.api.modules.common.mapper;
+
+import com.imyeyu.api.modules.common.entity.TagApply;
+import com.imyeyu.spring.mapper.BaseMapper;
+
+/// 标签应用 Mapper
+///
+/// @author 夜雨
+/// @since 2026-08-12 15:05
+public interface TagApplyMapper extends BaseMapper {
+}
diff --git a/src/main/java/com/imyeyu/api/modules/common/mapper/TagMapper.java b/src/main/java/com/imyeyu/api/modules/common/mapper/TagMapper.java
index fcca350..f8e79b5 100644
--- a/src/main/java/com/imyeyu/api/modules/common/mapper/TagMapper.java
+++ b/src/main/java/com/imyeyu/api/modules/common/mapper/TagMapper.java
@@ -3,9 +3,14 @@ package com.imyeyu.api.modules.common.mapper;
import com.imyeyu.api.modules.common.entity.Tag;
import com.imyeyu.spring.mapper.BaseMapper;
+import java.util.Collection;
+import java.util.List;
+
/**
* @author 夜雨
* @since 2025-05-30 22:48
*/
public interface TagMapper extends BaseMapper {
+
+ List selectByIdList(Collection idList);
}
diff --git a/src/main/java/com/imyeyu/api/modules/common/service/TagService.java b/src/main/java/com/imyeyu/api/modules/common/service/TagService.java
index 3514d3c..e76f170 100644
--- a/src/main/java/com/imyeyu/api/modules/common/service/TagService.java
+++ b/src/main/java/com/imyeyu/api/modules/common/service/TagService.java
@@ -1,11 +1,31 @@
package com.imyeyu.api.modules.common.service;
import com.imyeyu.api.modules.common.entity.Tag;
+import com.imyeyu.api.modules.common.entity.TagApply;
import com.imyeyu.spring.service.BaseService;
-/**
- * @author 夜雨
- * @since 2025-05-30 22:46
- */
+import java.util.Collection;
+import java.util.List;
+
+/// 标签服务
+///
+/// @author 夜雨
+/// @since 2025-05-30 22:46
public interface TagService extends BaseService {
+
+ List listByIdList(Collection idList);
+
+ /// 按业务查询标签列表
+ ///
+ /// @param bizType 业务类型
+ /// @param bizId 业务 ID
+ /// @return 标签列表
+ List listByBizType(TagApply.BizType bizType, String bizId);
+
+ /// 差分保存业务标签
+ ///
+ /// @param bizType 业务类型
+ /// @param bizId 业务 ID
+ /// @param tagIdList 标签 ID 列表
+ void apply(TagApply.BizType bizType, String bizId, List tagIdList);
}
diff --git a/src/main/java/com/imyeyu/api/modules/common/service/implement/TagServiceImplement.java b/src/main/java/com/imyeyu/api/modules/common/service/implement/TagServiceImplement.java
index afcc742..304d1b7 100644
--- a/src/main/java/com/imyeyu/api/modules/common/service/implement/TagServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/common/service/implement/TagServiceImplement.java
@@ -1,27 +1,100 @@
package com.imyeyu.api.modules.common.service.implement;
import com.imyeyu.api.modules.common.entity.Tag;
+import com.imyeyu.api.modules.common.entity.TagApply;
+import com.imyeyu.api.modules.common.mapper.TagApplyMapper;
import com.imyeyu.api.modules.common.mapper.TagMapper;
+import com.imyeyu.api.modules.common.service.MultilingualService;
import com.imyeyu.api.modules.common.service.TagService;
+import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
-/**
- * @author 夜雨
- * @since 2025-05-30 22:47
- */
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+/// 标签服务实现
+///
+/// @author 夜雨
+/// @since 2025-05-30 22:47
@Slf4j
@Service
@RequiredArgsConstructor
public class TagServiceImplement extends AbstractEntityService implements TagService {
private final TagMapper mapper;
+ private final TagApplyMapper applyMapper;
+ private final MultilingualService multilingualService;
@Override
protected BaseMapper mapper() {
return mapper;
}
+
+ @Override
+ public void create(Tag tag) {
+ TimiException.required(tag, "not found tag");
+ TimiException.required(tag.getZhCN(), "not found tag.zhCN");
+ tag.setNameLangId(multilingualService.create(tag.getZhCN()));
+ super.create(tag);
+ }
+
+ @Override
+ public void update(Tag tag) {
+ TimiException.required(tag, "not found tag");
+ TimiException.required(tag.getId(), "not found tag.id");
+ if (tag.getZhCN() != null) {
+ if (tag.getNameLangId() == null) {
+ Tag dbTag = get(tag.getId());
+ TimiException.required(dbTag, "not found tag");
+ tag.setNameLangId(dbTag.getNameLangId());
+ }
+ tag.setNameLangId(multilingualService.createIfDifferent(tag.getNameLangId(), tag.getZhCN()));
+ }
+ super.update(tag);
+ }
+
+ @Override
+ public List listByIdList(Collection idList) {
+ return mapper.selectByIdList(new HashSet<>(idList));
+ }
+
+ @Override
+ public List listByBizType(TagApply.BizType bizType, String bizId) {
+ return listByIdList(listApply(bizType, bizId).stream().map(TagApply::getTagId).toList());
+ }
+
+ @Override
+ public void apply(TagApply.BizType bizType, String bizId, List tagIdList) {
+ LinkedHashSet tagIdSet = new LinkedHashSet<>(tagIdList == null ? List.of() : tagIdList);
+ for (TagApply apply : listApply(bizType, bizId)) {
+ if (tagIdSet.remove(apply.getTagId())) {
+ continue;
+ }
+ applyMapper.delete(apply.getId());
+ }
+ List tagList = listByIdList(tagIdSet);
+ for (Tag tag : tagList) {
+ TagApply apply = new TagApply();
+ apply.setBizType(bizType);
+ apply.setBizId(bizId);
+ apply.setTagId(tag.getId());
+ applyMapper.insert(apply);
+ }
+ }
+
+ private List listApply(TagApply.BizType bizType, String bizId) {
+ TimiException.required(bizType, "not found bizType");
+ TimiException.required(bizId, "not found bizId");
+
+ TagApply example = new TagApply();
+ example.setBizType(bizType);
+ example.setBizId(bizId);
+ return applyMapper.selectAllByExample(example);
+ }
}
diff --git a/src/main/java/com/imyeyu/api/modules/common/vo/tag/TagRequest.java b/src/main/java/com/imyeyu/api/modules/common/vo/tag/TagRequest.java
deleted file mode 100644
index 151f163..0000000
--- a/src/main/java/com/imyeyu/api/modules/common/vo/tag/TagRequest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.imyeyu.api.modules.common.vo.tag;
-
-import lombok.Data;
-
-/**
- * @author 夜雨
- * @since 2025-05-30 22:58
- */
-@Data
-public class TagRequest {
-
- private String bizId;
-
- private String zhCN;
-}
\ No newline at end of file
diff --git a/src/main/java/com/imyeyu/api/modules/gao/annotation/RequireGaoRole.java b/src/main/java/com/imyeyu/api/modules/gao/annotation/RequireGaoRole.java
deleted file mode 100644
index 2f12945..0000000
--- a/src/main/java/com/imyeyu/api/modules/gao/annotation/RequireGaoRole.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.imyeyu.api.modules.gao.annotation;
-
-import com.imyeyu.api.bean.RoleMatchMode;
-import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-///
-/// 要求 GAO 模块角色
-///
-/// @author Codex
-/// @since 2026-07-26
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface RequireGaoRole {
-
- /// 所需角色
- ///
- /// @return 角色列表
- GaoRoleCode[] value();
-
- /// 匹配模式
- ///
- /// @return 匹配模式
- RoleMatchMode mode() default RoleMatchMode.ALL;
-}
diff --git a/src/main/java/com/imyeyu/api/modules/gao/annotation/RequireGaoRoleInterceptor.java b/src/main/java/com/imyeyu/api/modules/gao/annotation/RequireGaoRoleInterceptor.java
deleted file mode 100644
index 4d24acc..0000000
--- a/src/main/java/com/imyeyu/api/modules/gao/annotation/RequireGaoRoleInterceptor.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.imyeyu.api.modules.gao.annotation;
-
-import com.imyeyu.api.bean.ModuleCode;
-import com.imyeyu.api.bean.RoleMatchMode;
-import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
-import com.imyeyu.api.modules.user.service.RoleChecker;
-import com.imyeyu.java.TimiJava;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.lang.NonNull;
-import org.springframework.core.annotation.AnnotatedElementUtils;
-import org.springframework.stereotype.Component;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerInterceptor;
-
-///
-/// GAO 角色注解处理器
-///
-/// @author Codex
-/// @since 2026-07-27
-@Component
-public class RequireGaoRoleInterceptor implements HandlerInterceptor {
-
- private final RoleChecker roleChecker;
-
- public RequireGaoRoleInterceptor(RoleChecker roleChecker) {
- this.roleChecker = roleChecker;
- }
-
- @Override
- public boolean preHandle(@NonNull HttpServletRequest req, @NonNull HttpServletResponse resp, @NonNull Object handler) {
- if (!(handler instanceof HandlerMethod handlerMethod)) {
- return true;
- }
- RequireGaoRole annotation = handlerMethod.getMethodAnnotation(RequireGaoRole.class);
- if (annotation == null) {
- annotation = AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getBeanType(), RequireGaoRole.class);
- }
- if (annotation == null || TimiJava.isEmpty(annotation.value())) {
- return true;
- }
- String[] roleCodeList = java.util.Arrays.stream(annotation.value()).map(GaoRoleCode::name).toArray(String[]::new);
- if (annotation.mode() == RoleMatchMode.ANY) {
- roleChecker.checkAny(ModuleCode.GAO, roleCodeList);
- } else {
- roleChecker.checkAll(ModuleCode.GAO, roleCodeList);
- }
- return true;
- }
-}
diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRoleController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRoleController.java
index c9a1839..5cc71b6 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRoleController.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRoleController.java
@@ -1,8 +1,8 @@
package com.imyeyu.api.modules.gao.controller;
+import com.imyeyu.api.annotation.RequireCorePermission;
+import com.imyeyu.api.bean.CorePermissionCode;
import com.imyeyu.api.bean.ModuleCode;
-import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
-import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
import com.imyeyu.api.modules.user.entity.Role;
import com.imyeyu.api.modules.user.service.AuthorizationScopeService;
import com.imyeyu.api.modules.user.service.UserLoginService;
@@ -20,7 +20,6 @@ import java.util.List;
/// @author 夜雨
/// @since 2026-07-28 14:15
@RestController
-@RequireGaoRole(GaoRoleCode.STORE_MANAGER)
@RequiredArgsConstructor
@RequestMapping("/gao/role")
public class GaoRoleController {
@@ -30,6 +29,7 @@ public class GaoRoleController {
@AOPLog
@RequestRateLimit
+ @RequireCorePermission(CorePermissionCode.ROLE_READ)
@PostMapping("/available/list")
public List availableList() {
return authorizationScopeService.listGrantableRole(userLoginService.getRequireLoginUserId(), ModuleCode.GAO);
diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreBusinessDayController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreBusinessDayController.java
index 75d549d..68d29cf 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreBusinessDayController.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreBusinessDayController.java
@@ -1,9 +1,7 @@
package com.imyeyu.api.modules.gao.controller;
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
-import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
-import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
import com.imyeyu.api.modules.gao.entity.GaoStoreBusinessDay;
import com.imyeyu.api.modules.gao.service.GaoStoreBusinessDayService;
import com.imyeyu.spring.annotation.AOPLog;
diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreController.java
index 21b0d7e..c544d4e 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreController.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreController.java
@@ -1,12 +1,13 @@
package com.imyeyu.api.modules.gao.controller;
+import com.imyeyu.api.bean.ModuleCode;
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
-import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
-import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
import com.imyeyu.api.modules.gao.entity.GaoStore;
import com.imyeyu.api.modules.gao.service.GaoStoreService;
+import com.imyeyu.api.modules.user.service.PermissionChecker;
import com.imyeyu.api.modules.user.service.UserLoginService;
+import com.imyeyu.java.TimiJava;
import com.imyeyu.network.Network;
import com.imyeyu.spring.TimiSpring;
import com.imyeyu.spring.annotation.AOPLog;
@@ -37,9 +38,9 @@ public class GaoStoreController {
private final GaoStoreService service;
private final UserLoginService userLoginService;
+ private final PermissionChecker permissionChecker;
@AOPLog
- @RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
@RequestRateLimit
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
@PostMapping("/list")
@@ -48,7 +49,6 @@ public class GaoStoreController {
}
@AOPLog
- @RequireGaoRole(GaoRoleCode.STORE_MANAGER)
@RequestRateLimit
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
@PostMapping("/detail")
@@ -66,16 +66,26 @@ public class GaoStoreController {
}
@AOPLog
- @RequireGaoRole(GaoRoleCode.STORE_MANAGER)
@RequestRateLimit
@RequireGaoPermission(GaoPermissionCode.STORE_UPDATE)
@PostMapping("/update")
public void update(@RequestBody GaoStore store) {
- service.update(store);
+ if (permissionChecker.hasAny(ModuleCode.GAO, GaoPermissionCode.STORE_CREATE.getValue())) {
+ // 门店管理
+ service.update(store);
+ } else {
+ // 店长
+ GaoStore dbStore = service.get(store.getId());
+ dbStore.setName(store.getName());
+ dbStore.setTelephone(store.getTelephone());
+ dbStore.setAddress(store.getAddress());
+ dbStore.setRemark(store.getRemark());
+ dbStore.setAutoClosedDay(TimiJava.defaultIfNull(store.getAutoClosedDay(), false));
+ service.update(dbStore);
+ }
}
@AOPLog
- @RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
@RequestRateLimit
@RequireGaoPermission(GaoPermissionCode.STORE_DELETE)
@PostMapping("/delete")
@@ -84,7 +94,6 @@ public class GaoStoreController {
}
@AOPLog
- @RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
@RequestRateLimit
@RequireGaoPermission(GaoPermissionCode.STORE_UPDATE)
@PostMapping("/sort")
diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java
index 0452932..f045ea8 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java
@@ -5,7 +5,6 @@ import com.imyeyu.api.bean.ModuleCode;
import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.api.modules.common.service.AttachmentService;
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
-import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
import com.imyeyu.api.modules.gao.entity.GaoUser;
@@ -117,7 +116,6 @@ public class GaoUserController {
@AOPLog
@RequestRateLimit
- @RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
@RequireGaoPermission(GaoPermissionCode.USER_UPDATE)
@PostMapping("/transfer/store")
@JsonView(ResponseView.Public.class)
diff --git a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoPointLedger.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoPointLedger.java
index 550c558..1e63444 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoPointLedger.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoPointLedger.java
@@ -1,6 +1,7 @@
package com.imyeyu.api.modules.gao.entity;
import com.fasterxml.jackson.databind.JsonNode;
+import com.imyeyu.spring.annotation.table.Transient;
import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -83,4 +84,8 @@ public class GaoPointLedger extends UUIDEntity {
/// 发生时间
private Long occurredAt;
+
+ /// 客户信息
+ @Transient
+ private GaoCustomer customer;
}
diff --git a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStore.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStore.java
index f9042b0..07ea5f7 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStore.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStore.java
@@ -48,6 +48,9 @@ public class GaoStore extends UUIDEntity {
/// 备注
private String remark;
+ /// true 为启用自动计算营业日休息日
+ private Boolean autoClosedDay;
+
/// 排序值
private Integer sort;
diff --git a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStoreBusinessDay.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStoreBusinessDay.java
index 6192ef0..a83aa61 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStoreBusinessDay.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoStoreBusinessDay.java
@@ -18,7 +18,7 @@ public class GaoStoreBusinessDay extends UUIDEntity {
///
/// @author Codex
/// @since 2026-08-06
- public enum OpenStatus {
+ public enum Status {
/// 营业
OPEN,
@@ -34,7 +34,7 @@ public class GaoStoreBusinessDay extends UUIDEntity {
private Integer dateValue;
/// 营业状态
- private OpenStatus openStatus;
+ private Status status;
/// 营业日递增序号,仅营业日有值
private Long businessDayNo;
diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreBusinessDayMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreBusinessDayMapper.java
index 0ea3a57..9c3442e 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreBusinessDayMapper.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreBusinessDayMapper.java
@@ -4,6 +4,7 @@ import com.imyeyu.api.modules.gao.entity.GaoStoreBusinessDay;
import com.imyeyu.spring.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
import java.util.List;
@@ -27,7 +28,7 @@ public interface GaoStoreBusinessDayMapper extends BaseMapper= #{beginDateValue} AND `open_status` = 'OPEN' AND `deleted_at` IS NULL ORDER BY `date_value` ASC")
+ @Select("SELECT * FROM `gao_store_business_day` WHERE `store_id` = #{storeId} AND `date_value` >= #{beginDateValue} AND `status` = 'OPEN' AND `deleted_at` IS NULL ORDER BY `date_value` ASC")
List selectOpenListFromDate(@Param("storeId") String storeId, @Param("beginDateValue") Integer beginDateValue);
+ /// 清空指定日期及之后的营业日序号
+ ///
+ /// @param storeId 门店 ID
+ /// @param beginDateValue 开始日期值,格式为 yyyyMMdd
+ @Update("UPDATE `gao_store_business_day` SET `business_day_no` = NULL, `updated_at` = ROUND(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000) WHERE `store_id` = #{storeId} AND `date_value` >= #{beginDateValue} AND `status` = 'OPEN' AND `deleted_at` IS NULL")
+ void clearBusinessDayNoFromDate(@Param("storeId") String storeId, @Param("beginDateValue") Integer beginDateValue);
+
/// 查询日期范围内的营业日
///
/// @param storeId 门店 ID
diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreMapper.java
index 0dcb790..27ec207 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreMapper.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoStoreMapper.java
@@ -3,6 +3,7 @@ package com.imyeyu.api.modules.gao.mapper;
import com.imyeyu.api.modules.gao.entity.GaoStore;
import com.imyeyu.spring.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
import java.util.Collection;
import java.util.List;
@@ -16,6 +17,12 @@ public interface GaoStoreMapper extends BaseMapper {
List selectByIdList(@Param("idList") Collection idList);
+ /// 查询启用自动计算营业日休息日的可用门店
+ ///
+ /// @return 门店列表
+ @Select("SELECT * FROM `gao_store` WHERE `auto_closed_day` = TRUE AND `status` = 'ACTIVE' " + NOT_DELETE)
+ List selectAllByAutoClosedDay();
+
/// 查询用户所属的可用门店
///
/// @param userId 用户 ID
diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoStoreBusinessDayService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoStoreBusinessDayService.java
index fb6eb78..a64f449 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoStoreBusinessDayService.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoStoreBusinessDayService.java
@@ -23,6 +23,12 @@ public interface GaoStoreBusinessDayService extends BaseService {
String getBelongIdByRequiredLoginUserId();
+ List listByAutoClosedDay();
+
/// 导出门店列表
///
/// @param page 分页查询条件
diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventRecordServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventRecordServiceImplement.java
index 6202982..3c703d3 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventRecordServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventRecordServiceImplement.java
@@ -279,6 +279,7 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService pageRankByRange(GaoEventRecordRankPage page) {
TimiException.required(page.getStoreId(), "not found page.storeId");
+ page.setTodayDateValue(dateValue(Time.now()));
PageResult result = new PageResult<>();
result.setTotal(mapper.countRankByRange(page));
result.setList(mapper.selectRankByRange(page));
diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoPointLedgerServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoPointLedgerServiceImplement.java
index 8b55c00..76b8b7e 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoPointLedgerServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoPointLedgerServiceImplement.java
@@ -2,11 +2,15 @@ package com.imyeyu.api.modules.gao.service.implement;
import com.fasterxml.jackson.databind.JsonNode;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
+import com.imyeyu.api.modules.common.entity.Attachment;
+import com.imyeyu.api.modules.common.service.AttachmentService;
+import com.imyeyu.api.modules.gao.entity.GaoCustomer;
import com.imyeyu.api.modules.gao.entity.GaoPointAccount;
import com.imyeyu.api.modules.gao.entity.GaoPointLedger;
import com.imyeyu.api.modules.gao.entity.GaoPointRule;
import com.imyeyu.api.modules.gao.entity.GaoEventRecord;
import com.imyeyu.api.modules.gao.mapper.GaoPointLedgerMapper;
+import com.imyeyu.api.modules.gao.service.GaoCustomerService;
import com.imyeyu.api.modules.gao.service.GaoPointAccountService;
import com.imyeyu.api.modules.gao.service.GaoPointLedgerService;
import com.imyeyu.api.modules.gao.vo.GaoPointAdjustRequest;
@@ -23,6 +27,9 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+import java.util.Map;
+
/// GAO 客户积分流水服务实现
///
/// @author Codex
@@ -33,6 +40,8 @@ public class GaoPointLedgerServiceImplement extends AbstractEntityService result = new PageResult<>();
result.setTotal(mapper.countByQuery(page));
result.setList(mapper.selectByQuery(page));
+ fillCustomer(result.getList());
return result;
}
+ private void fillCustomer(List ledgerList) {
+ List customerIdList = ledgerList.stream().map(GaoPointLedger::getCustomerId).filter(TimiJava::isNotEmpty).distinct().toList();
+ if (customerIdList.isEmpty()) {
+ return;
+ }
+
+ Map customerMap = customerService.mapByIdList(customerIdList);
+ Map> attachmentMap = attachmentService.mapByBizIdList(Attachment.BizType.GAO_CUSTOMER, customerIdList);
+ for (GaoPointLedger ledger : ledgerList) {
+ GaoCustomer customer = customerMap.get(ledger.getCustomerId());
+ if (customer == null) {
+ continue;
+ }
+ customer.setAttachmentList(attachmentMap.get(customer.getId()));
+ ledger.setCustomer(customer);
+ }
+ }
+
private GaoPointLedger apply(String storeId, String customerId, GaoPointLedger.ChangeType changeType, long pointDelta, String ruleId, String eventId, String eventRecordId, JsonNode sourcePayload, String idempotencyKey, String remark, String operatorUserId, Long occurredAt) {
GaoPointLedger existing = mapper.selectByIdempotencyKey(idempotencyKey);
if (existing != null) {
diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoStoreBusinessDayServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoStoreBusinessDayServiceImplement.java
index a359323..6bc2f4b 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoStoreBusinessDayServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoStoreBusinessDayServiceImplement.java
@@ -37,7 +37,7 @@ public class GaoStoreBusinessDayServiceImplement extends AbstractEntityService listByDateRange(String storeId, Integer beginDateValue, Integer endDateValue) {
TimiException.required(storeId, "not found storeId");
@@ -120,8 +139,8 @@ public class GaoStoreBusinessDayServiceImplement extends AbstractEntityService listByAutoClosedDay() {
+ return mapper.selectAllByAutoClosedDay();
+ }
+
@Override
public byte[] export(Page page) throws IOException {
page.setIndex(0);
@@ -167,16 +165,31 @@ public class GaoStoreServiceImplement extends AbstractEntityService storeList = mapper.selectByIdList(new LinkedHashSet<>(idList));
- Map storeMap = storeList.stream().collect(Collectors.toMap(GaoStore::getId, Function.identity()));
- for (int i = 0; i < idList.size(); i++) {
- GaoStore store = storeMap.get(idList.get(i));
- if (store == null) {
- continue;
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_STORE_SORT");
+ try {
+ logger.setContent(jackson.writeValueAsString(idList));
+ List storeList = mapper.selectByIdList(new LinkedHashSet<>(idList));
+ Map storeMap = storeList.stream().collect(Collectors.toMap(GaoStore::getId, Function.identity()));
+ for (int i = 0; i < idList.size(); i++) {
+ GaoStore store = storeMap.get(idList.get(i));
+ if (store == null) {
+ continue;
+ }
+ store.setSort(i);
+ mapper.update(store);
}
- store.setSort(i);
- mapper.update(store);
+ logger.setLevel(Logger.Level.INFO);
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("删除 GAO 门店失败", e);
+ throw new TimiException(TimiCode.ERROR, "删除 GAO 门店失败", e);
+ } finally {
+ loggerService.create(logger);
}
}
diff --git a/src/main/java/com/imyeyu/api/modules/gao/task/GaoStoreAutoCloseDayTask.java b/src/main/java/com/imyeyu/api/modules/gao/task/GaoStoreAutoCloseDayTask.java
new file mode 100644
index 0000000..583cf75
--- /dev/null
+++ b/src/main/java/com/imyeyu/api/modules/gao/task/GaoStoreAutoCloseDayTask.java
@@ -0,0 +1,43 @@
+package com.imyeyu.api.modules.gao.task;
+
+import com.imyeyu.api.modules.gao.entity.GaoStore;
+import com.imyeyu.api.modules.gao.service.GaoStoreBusinessDayService;
+import com.imyeyu.api.modules.gao.service.GaoStoreService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+///
+/// GAO 门店营业日自动休息任务
+///
+/// @author Codex
+/// @since 2026-08-12
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GaoStoreAutoCloseDayTask {
+
+ private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
+
+ private final GaoStoreService storeService;
+ private final GaoStoreBusinessDayService businessDayService;
+
+ /// 每天零点后自动补记前一天无登记门店的休息日
+ @Scheduled(cron = "0 1 0 * * ?")
+ public void run() {
+ int dateValue = Integer.parseInt(DAY_FORMATTER.format(LocalDate.now().minusDays(1)));
+ List storeList = storeService.listByAutoClosedDay();
+ for (GaoStore store : storeList) {
+ try {
+ businessDayService.autoCloseBusinessDay(store.getId(), dateValue);
+ } catch (Exception e) {
+ log.error("自动补记 GAO 门店休息日失败: storeId[{}], dateValue[{}]", store.getId(), dateValue, e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/imyeyu/api/modules/gao/util/StoreXSSFBuilder.java b/src/main/java/com/imyeyu/api/modules/gao/util/StoreXSSFBuilder.java
index 000f7eb..a002b41 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/util/StoreXSSFBuilder.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/util/StoreXSSFBuilder.java
@@ -35,7 +35,7 @@ public class StoreXSSFBuilder extends BaseXSSFBuilder {
appendRow(sheet, 0, titleStyle, "门店列表导出");
appendRow(sheet, 1, null, "生成时间", Time.nowString());
appendRow(sheet, 2, null, "记录总数", String.valueOf(list.size()));
- appendRow(sheet, 3, headerStyle, "门店编码", "门店名称", "状态", "电话", "地址", "备注", "排序", "创建时间");
+ appendRow(sheet, 3, headerStyle, "门店编码", "门店名称", "状态", "电话", "地址", "备注", "自动计算休息日", "排序", "创建时间");
int rowIndex = 4;
for (GaoStore store : list) {
appendRow(sheet, rowIndex, null,
@@ -45,12 +45,13 @@ public class StoreXSSFBuilder extends BaseXSSFBuilder {
text(store.getTelephone()),
text(store.getAddress()),
text(store.getRemark()),
+ Boolean.TRUE.equals(store.getAutoClosedDay()) ? "是" : "否",
store.getSort() == null ? "" : String.valueOf(store.getSort()),
Time.toDateTime(store.getCreatedAt())
);
rowIndex++;
}
- for (int index = 0; index < 8; index++) {
+ for (int index = 0; index < 9; index++) {
sheet.autoSizeColumn(index);
sheet.setColumnWidth(index, Math.clamp(sheet.getColumnWidth(index), 10 * 256, 36 * 256));
}
diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordRankPage.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordRankPage.java
index 537b853..cffd255 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordRankPage.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordRankPage.java
@@ -23,9 +23,24 @@ public class GaoEventRecordRankPage extends BasePage {
/// 登记事件 ID 列表,为空查询全部登记事件
private List eventIdList;
+ /// 排行类型
+ private RankType rankType;
+
/// 开始登记时间
private Long beginAt;
/// 结束登记时间
private Long endAt;
+
+ /// 查询当天日期值,服务端内部填充,格式为 yyyyMMdd
+ private Integer todayDateValue;
+
+ public enum RankType {
+ /// 按累计登记天数
+ TOTAL_DAYS,
+ /// 按累计登记次数
+ TOTAL_COUNT,
+ /// 按最近连续登记天数
+ CONTINUOUS_DAYS
+ }
}
diff --git a/src/main/resources/db/migration/timiserver/V30__add_gao_store_auto_closed_day.sql b/src/main/resources/db/migration/timiserver/V30__add_gao_store_auto_closed_day.sql
new file mode 100644
index 0000000..400cf39
--- /dev/null
+++ b/src/main/resources/db/migration/timiserver/V30__add_gao_store_auto_closed_day.sql
@@ -0,0 +1,14 @@
+ALTER TABLE `gao_store`
+ ADD COLUMN `auto_closed_day` BOOLEAN NOT NULL DEFAULT FALSE COMMENT 'true 为启用自动计算休息日' AFTER `remark`;
+ALTER TABLE `gao_store_business_day`
+ DROP KEY `uk_gao_store_business_day_active_no`,
+ DROP KEY `idx_gao_store_business_day_open_no`,
+ DROP COLUMN `active_business_day_no`;
+ALTER TABLE `gao_store_business_day`
+ CHANGE COLUMN `open_status` `status` VARCHAR(32) NOT NULL COMMENT '营业状态';
+ALTER TABLE `gao_store_business_day`
+ ADD COLUMN `active_business_day_no` BIGINT GENERATED ALWAYS AS (
+ CASE WHEN `deleted_at` IS NULL AND `status` = 'OPEN' THEN `business_day_no` ELSE NULL END
+ ) STORED COMMENT '未删除营业日序号' INVISIBLE AFTER `business_day_no`,
+ ADD UNIQUE KEY `uk_gao_store_business_day_active_no` (`store_id`, `active_business_day_no`),
+ ADD KEY `idx_gao_store_business_day_status_no` (`store_id`, `status`, `business_day_no`);
diff --git a/src/main/resources/mapper/timi-server/AttachmentMapper.xml b/src/main/resources/mapper/timi-server/common/AttachmentMapper.xml
similarity index 100%
rename from src/main/resources/mapper/timi-server/AttachmentMapper.xml
rename to src/main/resources/mapper/timi-server/common/AttachmentMapper.xml
diff --git a/src/main/resources/mapper/timi-server/MultilingualMapper.xml b/src/main/resources/mapper/timi-server/common/MultilingualMapper.xml
similarity index 100%
rename from src/main/resources/mapper/timi-server/MultilingualMapper.xml
rename to src/main/resources/mapper/timi-server/common/MultilingualMapper.xml
diff --git a/src/main/resources/mapper/timi-server/common/TagMapper.xml b/src/main/resources/mapper/timi-server/common/TagMapper.xml
new file mode 100644
index 0000000..0b8518a
--- /dev/null
+++ b/src/main/resources/mapper/timi-server/common/TagMapper.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml b/src/main/resources/mapper/timi-server/gao/GaoCustomerMapper.xml
similarity index 100%
rename from src/main/resources/mapper/timi-server/GaoCustomerMapper.xml
rename to src/main/resources/mapper/timi-server/gao/GaoCustomerMapper.xml
diff --git a/src/main/resources/mapper/timi-server/GaoEventMapper.xml b/src/main/resources/mapper/timi-server/gao/GaoEventMapper.xml
similarity index 100%
rename from src/main/resources/mapper/timi-server/GaoEventMapper.xml
rename to src/main/resources/mapper/timi-server/gao/GaoEventMapper.xml
diff --git a/src/main/resources/mapper/timi-server/GaoEventRecordMapper.xml b/src/main/resources/mapper/timi-server/gao/GaoEventRecordMapper.xml
similarity index 77%
rename from src/main/resources/mapper/timi-server/GaoEventRecordMapper.xml
rename to src/main/resources/mapper/timi-server/gao/GaoEventRecordMapper.xml
index 796b272..194d81b 100644
--- a/src/main/resources/mapper/timi-server/GaoEventRecordMapper.xml
+++ b/src/main/resources/mapper/timi-server/gao/GaoEventRecordMapper.xml
@@ -129,10 +129,10 @@