From 633772f8b1f4632a4643576da2682af8cef02567 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 18 Dec 2025 14:46:12 +0800 Subject: [PATCH 01/48] =?UTF-8?q?1.=20=E4=BF=AE=E6=AD=A3=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=20sql=20=E7=AE=80=E5=8C=96=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index e159dc37..42b3bd3d 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -3560,7 +3560,7 @@ COMMENT ON TABLE system_users IS '用户信息表'; -- ---------------------------- -- @formatter:off -- SET IDENTITY_INSERT system_users ON; -INSERT INTO system_users (id, username, password, nickname, workcode, remark, post_ids, email, mobile, sex, user_source, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$04$KljJDa/LK7QfDm0lF5OhuePhlPfjRH3tB2Wu351Uidz.oQGJXevPi', '后台管理', NULL, '管理员', '[1,2]', '11aoteman@126.com', '18818260277', 2, 1, 'http://test.zt.iocoder.cn/test/20250502/avatar_1746154660449.png', 0, '0:0:0:0:0:0:0:1', '2025-05-10 18:03:15', 'admin', '2021-01-05 17:03:47', NULL, '2025-05-10 18:03:15', '0', 1); +INSERT INTO system_users (id, username, password, nickname, workcode, remark, post_ids, email, mobile, sex, user_source, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$04$KljJDa/LK7QfDm0lF5OhuePhlPfjRH3tB2Wu351Uidz.oQGJXevPi', '后台管理', NULL, '管理员', '[1,2]', '11aoteman@126.com', '18818260277', 2, 1, NULL, 0, '0:0:0:0:0:0:0:1', '2025-05-10 18:03:15', 'admin', '2021-01-05 17:03:47', NULL, '2025-05-10 18:03:15', '0', 1); INSERT INTO system_users (id, username, password, nickname, workcode, remark, post_ids, email, mobile, sex, user_source, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'zt', '$2a$04$h.aaPKgO.odHepnk5PCsWeEwKdojFWdTItxGKfx1r0e1CSeBzsTJ6', 'ZT', NULL, '不要吓我', '[1]', 'zt@iocoder.cn', '15601691300', 1, 1, NULL, 0, '0:0:0:0:0:0:0:1', '2025-04-08 09:36:40', '', '2021-01-07 09:07:17', NULL, '2025-04-21 14:23:08', '0', 1); INSERT INTO system_users (id, username, password, nickname, workcode, remark, post_ids, email, mobile, sex, user_source, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'yuanma', '$2a$04$fUBSmjKCPYAUmnMzOb6qE.eZCGPhHi1JmAKclODbfS/O7fHOl2bH6', '源码', NULL, NULL, NULL, 'yuanma@iocoder.cn', '15601701300', 0, 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-08-11 17:48:12', '', '2021-01-13 23:50:35', NULL, '2025-04-21 14:23:08', '0', 1); INSERT INTO system_users (id, username, password, nickname, workcode, remark, post_ids, email, mobile, sex, user_source, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'test', '$2a$04$BrwaYn303hjA/6TnXqdGoOLhyHOAA0bVrAFu6.1dJKycqKUnIoRz2', '测试号', NULL, NULL, '[1,2]', '111@qq.com', '15601691200', 1, 1, NULL, 0, '0:0:0:0:0:0:0:1', '2025-03-28 20:01:16', '', '2021-01-21 02:13:53', NULL, '2025-04-21 14:23:08', '0', 1); From a86b98b0f57a0e43f9b0d64c275be77a8b871121 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 18 Dec 2025 20:26:27 +0800 Subject: [PATCH 02/48] =?UTF-8?q?1.=20=E6=96=B0=E5=A2=9E=20permissionApi?= =?UTF-8?q?=20=E6=9F=A5=E8=AF=A2=E5=BD=93=E5=89=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=BA=A7=E5=88=AB=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/api/permission/PermissionApi.java | 6 +++ .../enums/permission/DataScopeEnum.java | 22 ++++++++ .../api/permission/PermissionApiImpl.java | 6 +++ .../service/permission/PermissionService.java | 9 ++++ .../permission/PermissionServiceImpl.java | 44 +++++++++++++++ .../permission/PermissionServiceTest.java | 53 +++++++++++++++++++ 6 files changed, 140 insertions(+) diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/permission/PermissionApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/permission/PermissionApi.java index 9e541926..b30f62f6 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/permission/PermissionApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/permission/PermissionApi.java @@ -4,6 +4,7 @@ import com.zt.plat.framework.common.biz.system.permission.PermissionCommonApi; import com.zt.plat.framework.common.pojo.CommonResult; import com.zt.plat.module.system.api.permission.dto.*; import com.zt.plat.module.system.enums.ApiConstants; +import com.zt.plat.module.system.enums.permission.DataScopeEnum; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Operation; @@ -50,4 +51,9 @@ public interface PermissionApi extends PermissionCommonApi { @Parameter(name = "userId", description = "用户编号", example = "1", required = true) CommonResult> getUserRoleIdListByUserId(@RequestParam("userId") Long userId); + @GetMapping(PREFIX + "/user-data-permission-level") + @Operation(summary = "获得用户的数据权限级别") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult getUserDataPermissionLevel(@RequestParam("userId") Long userId); + } \ No newline at end of file diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/permission/DataScopeEnum.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/permission/DataScopeEnum.java index b0edcfd0..4a1ab13f 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/permission/DataScopeEnum.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/permission/DataScopeEnum.java @@ -1,10 +1,12 @@ package com.zt.plat.module.system.enums.permission; +import com.fasterxml.jackson.annotation.JsonValue; import com.zt.plat.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Arrays; +import java.util.Objects; /** * 数据范围枚举类 @@ -33,6 +35,26 @@ public enum DataScopeEnum implements ArrayValuable { public static final Integer[] ARRAYS = Arrays.stream(values()).map(DataScopeEnum::getScope).toArray(Integer[]::new); + /** + * Jackson 序列化时输出整数 code,兼容旧客户端 + */ + @JsonValue + public Integer getScope() { + return scope; + } + + public static DataScopeEnum findByScope(Integer scope) { + if (scope == null) { + return null; + } + for (DataScopeEnum value : values()) { + if (Objects.equals(value.scope, scope)) { + return value; + } + } + return null; + } + @Override public Integer[] array() { return ARRAYS; diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/permission/PermissionApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/permission/PermissionApiImpl.java index 955fa69a..771f322b 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/permission/PermissionApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/permission/PermissionApiImpl.java @@ -6,6 +6,7 @@ import com.zt.plat.framework.common.util.object.BeanUtils; import com.zt.plat.module.system.api.permission.dto.*; import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleDataScopeReqVO; import com.zt.plat.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO; +import com.zt.plat.module.system.enums.permission.DataScopeEnum; import com.zt.plat.module.system.service.permission.PermissionService; import org.springframework.context.annotation.Primary; import org.springframework.validation.annotation.Validated; @@ -65,6 +66,11 @@ public class PermissionApiImpl implements PermissionApi { return success(permissionService.getUserRoleIdListByUserIdFromCache(userId)); } + @Override + public CommonResult getUserDataPermissionLevel(Long userId) { + return success(permissionService.getUserDataPermissionLevel(userId)); + } + @Override public CommonResult hasAnyPermissions(Long userId, String... permissions) { return success(permissionService.hasAnyPermissions(userId, permissions)); diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionService.java index 28a029fd..a1a88dd3 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionService.java @@ -1,6 +1,7 @@ package com.zt.plat.module.system.service.permission; import com.zt.plat.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO; +import com.zt.plat.module.system.enums.permission.DataScopeEnum; import java.util.Collection; import java.util.Set; @@ -143,4 +144,12 @@ public interface PermissionService { */ DeptDataPermissionRespDTO getDeptDataPermission(Long userId); + /** + * 获得用户的数据权限级别 + * + * @param userId 用户编号 + * @return 数据权限范围枚举 + */ + DataScopeEnum getUserDataPermissionLevel(Long userId); + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionServiceImpl.java index ac7a1553..6bb37d18 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/permission/PermissionServiceImpl.java @@ -27,6 +27,7 @@ import com.zt.plat.module.system.enums.permission.RoleTypeEnum; import com.zt.plat.module.system.service.dept.DeptService; import com.zt.plat.module.system.service.user.AdminUserService; import com.zt.plat.module.system.service.userdept.UserDeptService; +import com.zt.plat.framework.tenant.core.aop.TenantIgnore; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -57,6 +58,15 @@ import static com.zt.plat.module.system.enums.ErrorCodeConstants.ROLE_CAN_NOT_UP @Slf4j public class PermissionServiceImpl implements PermissionService { + private static final List DATA_SCOPE_PRIORITY = Arrays.asList( + DataScopeEnum.ALL, + DataScopeEnum.COMPANY_AND_DEPT, + DataScopeEnum.DEPT_AND_CHILD, + DataScopeEnum.DEPT_ONLY, + DataScopeEnum.DEPT_CUSTOM, + DataScopeEnum.SELF + ); + @Resource private RoleMenuMapper roleMenuMapper; @Resource @@ -404,6 +414,40 @@ public class PermissionServiceImpl implements PermissionService { return result; } + @Override + @DataPermission(enable = false) + @TenantIgnore + public DataScopeEnum getUserDataPermissionLevel(Long userId) { + List roles = getEnableUserRoleListByUserIdFromCache(userId); + if (CollUtil.isEmpty(roles)) { + return DataScopeEnum.SELF; + } + + DataScopeEnum best = null; + for (RoleDO role : roles) { + DataScopeEnum scopeEnum = DataScopeEnum.findByScope(role.getDataScope()); + if (scopeEnum == null) { + continue; + } + if (best == null || compareScope(scopeEnum, best) < 0) { + best = scopeEnum; + if (DataScopeEnum.ALL.equals(best)) { + break; + } + } + } + return best != null ? best : DataScopeEnum.SELF; + } + + private int compareScope(DataScopeEnum left, DataScopeEnum right) { + return getScopePriority(left) - getScopePriority(right); + } + + private int getScopePriority(DataScopeEnum scope) { + int idx = DATA_SCOPE_PRIORITY.indexOf(scope); + return idx >= 0 ? idx : Integer.MAX_VALUE; + } + /** * 获得自身的代理对象,解决 AOP 生效问题 * diff --git a/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/permission/PermissionServiceTest.java b/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/permission/PermissionServiceTest.java index 73095709..9bfefac6 100644 --- a/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/permission/PermissionServiceTest.java +++ b/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/permission/PermissionServiceTest.java @@ -1,7 +1,9 @@ package com.zt.plat.module.system.service.permission; import com.zt.plat.framework.common.exception.ServiceException; +import com.zt.plat.framework.common.enums.CommonStatusEnum; import com.zt.plat.framework.test.core.ut.BaseDbUnitTest; +import com.zt.plat.framework.common.util.json.JsonUtils; import com.zt.plat.module.system.controller.admin.permission.vo.role.RoleSaveReqVO; import com.zt.plat.module.system.dal.dataobject.permission.RoleDO; import com.zt.plat.module.system.dal.dataobject.permission.RoleMenuDO; @@ -11,6 +13,7 @@ import com.zt.plat.module.system.dal.mysql.permission.RoleMapper; import com.zt.plat.module.system.dal.mysql.permission.RoleMenuMapper; import com.zt.plat.module.system.dal.mysql.permission.UserRoleMapper; import com.zt.plat.module.system.dal.mysql.rolemenuexclusion.RoleMenuExclusionMapper; +import com.zt.plat.module.system.enums.permission.DataScopeEnum; import com.zt.plat.module.system.enums.permission.RoleTypeEnum; import com.zt.plat.module.system.service.dept.DeptService; import com.zt.plat.module.system.service.user.AdminUserService; @@ -408,4 +411,54 @@ public class PermissionServiceTest extends BaseDbUnitTest { assertEquals(1, exclusionDOS.size()); assertEquals(101L, exclusionDOS.get(0).getMenuId()); } + + @Test + public void testGetUserDataPermissionLevel_noRolesReturnSelf() { + Long userId = 1000L; + + DataScopeEnum result = permissionService.getUserDataPermissionLevel(userId); + + assertEquals(DataScopeEnum.SELF, result); + } + + @Test + public void testGetUserDataPermissionLevel_pickHighestPriority() { + Long userId = 2000L; + RoleDO roleCustom = randomPojo(RoleDO.class, o -> o + .setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) + .setId(110L) + .setTenantId(0L)); + roleMapper.insert(roleCustom); + RoleDO roleCompany = randomPojo(RoleDO.class, o -> o + .setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setDataScope(DataScopeEnum.COMPANY_AND_DEPT.getScope()) + .setId(120L) + .setTenantId(0L)); + roleMapper.insert(roleCompany); + + userRoleMapper.insert(randomPojo(UserRoleDO.class, o -> o.setUserId(userId).setRoleId(roleCustom.getId()))); + userRoleMapper.insert(randomPojo(UserRoleDO.class, o -> o.setUserId(userId).setRoleId(roleCompany.getId()))); + + DataScopeEnum result = permissionService.getUserDataPermissionLevel(userId); + + assertEquals(DataScopeEnum.COMPANY_AND_DEPT, result); + } + + @Test + public void testGetUserDataPermissionLevel_serializeAsNumber() { + Long userId = 3000L; + RoleDO roleAll = randomPojo(RoleDO.class, o -> o + .setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setDataScope(DataScopeEnum.ALL.getScope()) + .setId(210L) + .setTenantId(0L)); + roleMapper.insert(roleAll); + userRoleMapper.insert(randomPojo(UserRoleDO.class, o -> o.setUserId(userId).setRoleId(roleAll.getId()))); + + DataScopeEnum result = permissionService.getUserDataPermissionLevel(userId); + + assertEquals(DataScopeEnum.ALL, result); + assertEquals("1", JsonUtils.toJsonString(result)); + } } From 494de02d65d948ed1ccba972276ed034855a5ea0 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 18 Dec 2025 21:39:49 +0800 Subject: [PATCH 03/48] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8D=E7=88=B6=E5=AD=90?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E8=B7=A8=E9=A1=B5=E5=9C=BA=E6=99=AF=E4=B8=8B?= =?UTF-8?q?=EF=BC=8C=E6=97=A0=E6=B3=95=E6=AD=A3=E7=A1=AE=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=B1=82=E7=BA=A7=E4=BB=A3=E7=A0=81=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/service/dept/DeptService.java | 7 ++ .../system/service/dept/DeptServiceImpl.java | 23 ++++++ .../integration/iwork/IWorkSyncProcessor.java | 51 +++++++++++- .../iwork/impl/IWorkSyncProcessorImpl.java | 81 +++++++++++++++++-- .../iwork/impl/IWorkSyncServiceImpl.java | 26 ++++-- 5 files changed, 173 insertions(+), 15 deletions(-) diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java index c97510df..80834565 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java @@ -174,4 +174,11 @@ public interface DeptService { * @return 部门列表 */ List searchDeptTree(String keyword); + + /** + * 回填缺失的部门编码(不触发事件)。 + * + * @param deptIds 需要回填的部门 ID 列表 + */ + void backfillMissingCodesWithoutEvent(Collection deptIds); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java index 03cadf43..24104dc1 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java @@ -900,4 +900,27 @@ public class DeptServiceImpl implements DeptService { } } + @Override + @Transactional(rollbackFor = Exception.class) + @DataPermission(enable = false) + public void backfillMissingCodesWithoutEvent(Collection deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return; + } + List targets = deptMapper.selectBatchIds(deptIds); + for (DeptDO dept : targets) { + if (dept == null || StrUtil.isNotBlank(dept.getCode())) { + continue; + } + Integer source = ObjectUtil.defaultIfNull(dept.getDeptSource(), DeptSourceEnum.EXTERNAL.getSource()); + try { + String code = generateDeptCode(dept.getParentId(), source); + validateDeptCodeUnique(dept.getId(), code); + updateDeptCode(dept.getId(), code); + } catch (Exception ex) { + log.warn("[iWork] 回填部门编码失败 id={} name={} msg={}", dept.getId(), dept.getName(), ex.getMessage()); + } + } + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java index c19d3975..17ec9b6a 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java @@ -5,23 +5,42 @@ import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrJo import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSubcompanyPageRespVO; import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrUserPageRespVO; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Abstraction for applying iWork entities into local persistence. */ public interface IWorkSyncProcessor { - BatchResult syncSubcompanies(List data, SyncOptions options); + BatchResult syncSubcompanies(List data, + SyncOptions options); + + BatchResult syncSubcompanies(List data, + SyncOptions options, + DeptSyncContext context); BatchResult syncDepartments(List data, SyncOptions options); + BatchResult syncDepartments(List data, + SyncOptions options, + DeptSyncContext context); + BatchResult syncJobTitles(List data, SyncOptions options); BatchResult syncUsers(List data, SyncOptions options); + /** + * 对当次同步累计的待处理/占位部门做最终补偿(跨页父子依赖)。 + */ + default BatchResult flushDeptPending(DeptSyncContext context, SyncOptions options) { + return BatchResult.empty(); + } + /** * Execution options shared by batch and single sync flows. */ @@ -53,6 +72,32 @@ public interface IWorkSyncProcessor { } } + /** + * 部门/分部跨页同步上下文,用于累计待处理记录与已就绪父级。 + */ + final class DeptSyncContext { + private final Set readyParentIds = new HashSet<>(); + private final List pendingSubcompanies = new ArrayList<>(); + private final List pendingDepartments = new ArrayList<>(); + private final Set placeholderDeptIds = new HashSet<>(); + + public Set getReadyParentIds() { + return readyParentIds; + } + + public List getPendingSubcompanies() { + return pendingSubcompanies; + } + + public List getPendingDepartments() { + return pendingDepartments; + } + + public Set getPlaceholderDeptIds() { + return placeholderDeptIds; + } + } + /** * Aggregated result for a sync batch. */ @@ -170,11 +215,11 @@ public interface IWorkSyncProcessor { } default BatchResult syncSubcompany(IWorkHrSubcompanyPageRespVO.Subcompany data, SyncOptions options) { - return syncSubcompanies(Collections.singletonList(data), options); + return syncSubcompanies(Collections.singletonList(data), options, null); } default BatchResult syncDepartment(IWorkHrDepartmentPageRespVO.Department data, SyncOptions options) { - return syncDepartments(Collections.singletonList(data), options); + return syncDepartments(Collections.singletonList(data), options, null); } default BatchResult syncJobTitle(IWorkHrJobTitlePageRespVO.JobTitle data, SyncOptions options) { diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java index 3c004a2b..bbabb064 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java @@ -50,14 +50,34 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { @Override public BatchResult syncSubcompanies(List data, SyncOptions options) { + return syncSubcompanies(data, options, null); + } + + @Override + public BatchResult syncSubcompanies(List data, + SyncOptions options, + DeptSyncContext context) { + return syncSubcompaniesInternal(data, options, context, false); + } + + private BatchResult syncSubcompaniesInternal(List data, + SyncOptions options, + DeptSyncContext context, + boolean allowPlaceholderOnRemaining) { List records = CollUtil.emptyIfNull(data); BatchResult result = BatchResult.empty(); - if (records.isEmpty()) { + if (records.isEmpty() + && (context == null || CollUtil.isEmpty(context.getPendingSubcompanies()))) { return result; } result.increasePulled(records.size()); - List queue = new ArrayList<>(records); - Set readyParentIds = new HashSet<>(); + List queue = new ArrayList<>(); + if (context != null && CollUtil.isNotEmpty(context.getPendingSubcompanies())) { + queue.addAll(context.getPendingSubcompanies()); + context.getPendingSubcompanies().clear(); + } + queue.addAll(records); + Set readyParentIds = context != null ? context.getReadyParentIds() : new HashSet<>(); int guard = 0; int maxPasses = Math.max(1, queue.size() * 2); while (!queue.isEmpty() && guard++ < maxPasses) { @@ -106,6 +126,12 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { break; } } + if (!queue.isEmpty()) { + if (context != null && !allowPlaceholderOnRemaining) { + context.getPendingSubcompanies().addAll(queue); + queue.clear(); + } + } if (!queue.isEmpty()) { for (IWorkHrSubcompanyPageRespVO.Subcompany remaining : queue) { log.warn("[iWork] 分部父级缺失,延迟生成编码插入占位: id={} name={}", remaining.getId(), remaining.getSubcompanyname()); @@ -117,6 +143,9 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { try { DeptSyncOutcome outcome = upsertDept(saveReq.getId(), saveReq, isCanceledFlag(remaining.getCanceled()), options); applyDeptOutcome(result, outcome, "分部", remaining.getSubcompanyname()); + if (context != null && outcome.deptId() != null) { + context.getPlaceholderDeptIds().add(outcome.deptId()); + } } catch (Exception ex) { log.error("[iWork] 分部占位插入失败: id={} name={}", remaining.getId(), remaining.getSubcompanyname(), ex); result.increaseFailed(); @@ -128,14 +157,34 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { @Override public BatchResult syncDepartments(List data, SyncOptions options) { + return syncDepartments(data, options, null); + } + + @Override + public BatchResult syncDepartments(List data, + SyncOptions options, + DeptSyncContext context) { + return syncDepartmentsInternal(data, options, context, false); + } + + private BatchResult syncDepartmentsInternal(List data, + SyncOptions options, + DeptSyncContext context, + boolean allowPlaceholderOnRemaining) { List records = CollUtil.emptyIfNull(data); BatchResult result = BatchResult.empty(); - if (records.isEmpty()) { + if (records.isEmpty() + && (context == null || CollUtil.isEmpty(context.getPendingDepartments()))) { return result; } result.increasePulled(records.size()); - List queue = new ArrayList<>(records); - Set readyParentIds = new HashSet<>(); + List queue = new ArrayList<>(); + if (context != null && CollUtil.isNotEmpty(context.getPendingDepartments())) { + queue.addAll(context.getPendingDepartments()); + context.getPendingDepartments().clear(); + } + queue.addAll(records); + Set readyParentIds = context != null ? context.getReadyParentIds() : new HashSet<>(); int guard = 0; int maxPasses = Math.max(1, queue.size() * 2); while (!queue.isEmpty() && guard++ < maxPasses) { @@ -184,6 +233,12 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { break; } } + if (!queue.isEmpty()) { + if (context != null && !allowPlaceholderOnRemaining) { + context.getPendingDepartments().addAll(queue); + queue.clear(); + } + } if (!queue.isEmpty()) { for (IWorkHrDepartmentPageRespVO.Department remaining : queue) { log.warn("[iWork] 部门父级缺失,延迟生成编码插入占位: id={} name={}", remaining.getId(), remaining.getDepartmentname()); @@ -195,6 +250,9 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { try { DeptSyncOutcome outcome = upsertDept(saveReq.getId(), saveReq, isCanceledFlag(remaining.getCanceled()), options); applyDeptOutcome(result, outcome, "部门", remaining.getDepartmentname()); + if (context != null && outcome.deptId() != null) { + context.getPlaceholderDeptIds().add(outcome.deptId()); + } } catch (Exception ex) { log.error("[iWork] 部门占位插入失败: id={} name={}", remaining.getId(), remaining.getDepartmentname(), ex); result.increaseFailed(); @@ -204,6 +262,17 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { return result; } + @Override + public BatchResult flushDeptPending(DeptSyncContext context, SyncOptions options) { + BatchResult result = BatchResult.empty(); + if (context == null) { + return result; + } + result.merge(syncSubcompaniesInternal(Collections.emptyList(), options, context, true)); + result.merge(syncDepartmentsInternal(Collections.emptyList(), options, context, true)); + return result; + } + @Override public BatchResult syncJobTitles(List data, SyncOptions options) { List records = CollUtil.emptyIfNull(data); diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java index 8954ea8f..b06959d6 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil; import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil; import com.zt.plat.module.system.controller.admin.integration.iwork.vo.*; import com.zt.plat.module.system.enums.integration.IWorkSyncEntityTypeEnum; +import com.zt.plat.module.system.service.dept.DeptService; import com.zt.plat.module.system.service.integration.iwork.IWorkOrgRestService; import com.zt.plat.module.system.service.integration.iwork.IWorkSyncProcessor; import com.zt.plat.module.system.service.integration.iwork.IWorkSyncService; @@ -31,6 +32,7 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { private final IWorkOrgRestService orgRestService; private final IWorkSyncProcessor syncProcessor; + private final DeptService deptService; @Override public IWorkFullSyncRespVO fullSyncDepartments(IWorkFullSyncReqVO reqVO) { @@ -64,11 +66,14 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { boolean syncJobTitle = scopes.contains(IWorkSyncEntityTypeEnum.JOB_TITLE); int processedPages = 0; IWorkSyncProcessor.SyncOptions options = buildFullSyncOptions(reqVO); + IWorkSyncProcessor.DeptSyncContext deptSyncContext = (syncDepartments || syncSubcompanies) + ? new IWorkSyncProcessor.DeptSyncContext() + : null; if (syncSubcompanies) { - processedPages += executeSubcompanyFullSync(reqVO, options, respVO.getSubcompanyStat(), batchStats); + processedPages += executeSubcompanyFullSync(reqVO, options, respVO.getSubcompanyStat(), batchStats, deptSyncContext); } if (syncDepartments) { - processedPages += executeDepartmentFullSync(reqVO, options, respVO.getDepartmentStat(), batchStats); + processedPages += executeDepartmentFullSync(reqVO, options, respVO.getDepartmentStat(), batchStats, deptSyncContext); } if (syncJobTitle) { processedPages += executeJobTitleFullSync(reqVO, options, respVO.getJobTitleStat(), batchStats); @@ -76,6 +81,13 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { if (syncUsers) { processedPages += executeUserFullSync(reqVO, options, respVO.getUserStat(), batchStats); } + if (deptSyncContext != null) { + IWorkSyncProcessor.BatchResult flushResult = syncProcessor.flushDeptPending(deptSyncContext, options); + updateStat(respVO.getDepartmentStat(), flushResult, 0); + if (CollUtil.isNotEmpty(deptSyncContext.getPlaceholderDeptIds())) { + deptService.backfillMissingCodesWithoutEvent(deptSyncContext.getPlaceholderDeptIds()); + } + } respVO.setProcessedPages(processedPages); return respVO; } @@ -83,7 +95,8 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { private int executeSubcompanyFullSync(IWorkFullSyncReqVO reqVO, IWorkSyncProcessor.SyncOptions options, IWorkSyncEntityStatVO stat, - List batches) { + List batches, + IWorkSyncProcessor.DeptSyncContext context) { return executePaged(reqVO, IWorkSyncEntityTypeEnum.SUBCOMPANY, batches, (page, pageSize) -> { IWorkSubcompanyQueryReqVO query = new IWorkSubcompanyQueryReqVO(); query.setCurpage(page); @@ -92,7 +105,7 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { IWorkHrSubcompanyPageRespVO pageResp = orgRestService.listSubcompanies(query); ensureIWorkSuccess("拉取分部", pageResp.isSuccess(), pageResp.getMessage()); List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); - IWorkSyncProcessor.BatchResult result = syncProcessor.syncSubcompanies(dataList, options); + IWorkSyncProcessor.BatchResult result = syncProcessor.syncSubcompanies(dataList, options, context); updateStat(stat, result, dataList.size()); return new BatchExecution(result, dataList.size()); }); @@ -101,7 +114,8 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { private int executeDepartmentFullSync(IWorkFullSyncReqVO reqVO, IWorkSyncProcessor.SyncOptions options, IWorkSyncEntityStatVO stat, - List batches) { + List batches, + IWorkSyncProcessor.DeptSyncContext context) { return executePaged(reqVO, IWorkSyncEntityTypeEnum.DEPARTMENT, batches, (page, pageSize) -> { IWorkDepartmentQueryReqVO query = new IWorkDepartmentQueryReqVO(); query.setCurpage(page); @@ -110,7 +124,7 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { IWorkHrDepartmentPageRespVO pageResp = orgRestService.listDepartments(query); ensureIWorkSuccess("拉取部门", pageResp.isSuccess(), pageResp.getMessage()); List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); - IWorkSyncProcessor.BatchResult result = syncProcessor.syncDepartments(dataList, options); + IWorkSyncProcessor.BatchResult result = syncProcessor.syncDepartments(dataList, options, context); updateStat(stat, result, dataList.size()); return new BatchExecution(result, dataList.size()); }); From bdd22ed132e0481202dfe7bc415908ac5cd3f0a0 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 18 Dec 2025 22:26:05 +0800 Subject: [PATCH 04/48] =?UTF-8?q?1.=20=E5=8E=BB=E9=99=A4=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E4=B8=BA=E7=A9=BA=E6=97=B6=EF=BC=8C=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=BD=BF=E7=94=A8=20id=20=E4=BD=9C=E4=B8=BA=20code=20?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E6=98=A0=E5=B0=84=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iwork/impl/IWorkSyncProcessorImpl.java | 4 +- .../impl/IWorkSyncProcessorImplTest.java | 141 ++++++++++++++++++ .../iwork/impl/IWorkSyncServiceImplTest.java | 62 ++++++++ 3 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImplTest.java create mode 100644 zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImplTest.java diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java index bbabb064..abf94ac4 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java @@ -513,7 +513,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { req.setIsGroup(Boolean.FALSE); req.setDeptSource(DeptSourceEnum.IWORK.getSource()); req.setExternalSystemCode(ExternalPlatformEnum.IWORK.getCode()); - req.setExternalDeptCode(StrUtil.blankToDefault(trimToNull(data.getSubcompanycode()), String.valueOf(data.getId()))); + req.setExternalDeptCode(trimToNull(data.getSubcompanycode())); req.setExternalDeptName(data.getSubcompanyname()); return req; } @@ -533,7 +533,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { req.setIsGroup(Boolean.FALSE); req.setDeptSource(DeptSourceEnum.IWORK.getSource()); req.setExternalSystemCode(ExternalPlatformEnum.IWORK.getCode()); - req.setExternalDeptCode(StrUtil.blankToDefault(trimToNull(data.getDepartmentcode()), String.valueOf(data.getId()))); + req.setExternalDeptCode(trimToNull(data.getDepartmentcode())); req.setExternalDeptName(data.getDepartmentname()); return req; } diff --git a/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImplTest.java b/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImplTest.java new file mode 100644 index 00000000..a16f5f84 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImplTest.java @@ -0,0 +1,141 @@ +package com.zt.plat.module.system.service.integration.iwork.impl; + +import com.zt.plat.framework.test.core.ut.BaseMockitoUnitTest; +import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO; +import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrDepartmentPageRespVO; +import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSubcompanyPageRespVO; +import com.zt.plat.module.system.dal.mysql.dept.PostMapper; +import com.zt.plat.module.system.dal.mysql.user.AdminUserMapper; +import com.zt.plat.module.system.service.dept.DeptService; +import com.zt.plat.module.system.service.dept.PostService; +import com.zt.plat.module.system.service.integration.iwork.IWorkSyncProcessor; +import com.zt.plat.module.system.service.user.AdminUserService; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * Tests for cross-page pending handling and placeholder backfill in IWorkSyncProcessorImpl. + */ +class IWorkSyncProcessorImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private IWorkSyncProcessorImpl processor; + + @Mock + private DeptService deptService; + @Mock + private PostService postService; + @Mock + private PostMapper postMapper; + @Mock + private AdminUserService adminUserService; + @Mock + private AdminUserMapper adminUserMapper; + + @Test + void shouldProcessPendingChildWhenParentArrivesInLaterPage() { + IWorkSyncProcessor.DeptSyncContext context = new IWorkSyncProcessor.DeptSyncContext(); + IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true); + + IWorkHrDepartmentPageRespVO.Department child = new IWorkHrDepartmentPageRespVO.Department(); + child.setId(200); + child.setDepartmentname("child"); + child.setSupdepid(100); // parent comes later + + IWorkHrDepartmentPageRespVO.Department parent = new IWorkHrDepartmentPageRespVO.Department(); + parent.setId(100); + parent.setDepartmentname("parent"); + parent.setSupdepid(0); // root + + when(deptService.getDept(anyLong())).thenReturn(null); + when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(100L, 200L); + + processor.syncDepartments(List.of(child), options, context); + + verify(deptService, never()).createDept(any()); + assertEquals(1, context.getPendingDepartments().size()); + + processor.syncDepartments(List.of(parent), options, context); + + verify(deptService, times(2)).createDept(any()); + assertTrue(context.getPendingDepartments().isEmpty(), "pending should be cleared after parent processed"); + } + + @Test + void shouldInsertPlaceholderWhenParentMissingAfterFlush() { + IWorkSyncProcessor.DeptSyncContext context = new IWorkSyncProcessor.DeptSyncContext(); + IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true); + + IWorkHrDepartmentPageRespVO.Department child = new IWorkHrDepartmentPageRespVO.Department(); + child.setId(300); + child.setDepartmentname("orphan"); + child.setSupdepid(9999); // never provided + + when(deptService.getDept(anyLong())).thenReturn(null); + when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(300L); + + processor.syncDepartments(List.of(child), options, context); + assertEquals(1, context.getPendingDepartments().size()); + + IWorkSyncProcessor.BatchResult flushResult = processor.flushDeptPending(context, options); + assertNotNull(flushResult); + + ArgumentCaptor captor = ArgumentCaptor.forClass(DeptSaveReqVO.class); + verify(deptService, times(1)).createDept(captor.capture()); + DeptSaveReqVO placeholderReq = captor.getValue(); + assertTrue(Boolean.TRUE.equals(placeholderReq.getDelayCodeGeneration())); + assertNull(placeholderReq.getCode()); + + assertTrue(context.getPendingDepartments().isEmpty(), "pending should be cleared after placeholder insert"); + assertTrue(context.getPlaceholderDeptIds().contains(300L)); + } + + @Test + void shouldKeepExternalCodeNullWhenDepartmentCodeBlank() { + IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true); + + IWorkHrDepartmentPageRespVO.Department dept = new IWorkHrDepartmentPageRespVO.Department(); + dept.setId(500); + dept.setDepartmentname("blank-code-dept"); + dept.setDepartmentcode(" "); + dept.setSupdepid(0); + + when(deptService.getDept(anyLong())).thenReturn(null); + when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(500L); + + processor.syncDepartments(List.of(dept), options, null); + + ArgumentCaptor captor = ArgumentCaptor.forClass(DeptSaveReqVO.class); + verify(deptService, times(1)).createDept(captor.capture()); + DeptSaveReqVO req = captor.getValue(); + assertNull(req.getExternalDeptCode(), "externalDeptCode should remain null when source code is blank"); + } + + @Test + void shouldKeepExternalCodeNullWhenSubcompanyCodeBlank() { + IWorkSyncProcessor.SyncOptions options = IWorkSyncProcessor.SyncOptions.custom(true, true, true); + + IWorkHrSubcompanyPageRespVO.Subcompany subcompany = new IWorkHrSubcompanyPageRespVO.Subcompany(); + subcompany.setId(600); + subcompany.setSubcompanyname("blank-code-sub"); + subcompany.setSubcompanycode(null); + subcompany.setSupsubcomid(0); + + when(deptService.getDept(anyLong())).thenReturn(null); + when(deptService.createDept(any(DeptSaveReqVO.class))).thenReturn(600L); + + processor.syncSubcompanies(List.of(subcompany), options, null); + + ArgumentCaptor captor = ArgumentCaptor.forClass(DeptSaveReqVO.class); + verify(deptService, times(1)).createDept(captor.capture()); + DeptSaveReqVO req = captor.getValue(); + assertNull(req.getExternalDeptCode(), "externalDeptCode should remain null when source code is null or blank"); + } +} diff --git a/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImplTest.java b/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImplTest.java new file mode 100644 index 00000000..b8b1eb32 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/test/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImplTest.java @@ -0,0 +1,62 @@ +package com.zt.plat.module.system.service.integration.iwork.impl; + +import com.zt.plat.framework.test.core.ut.BaseMockitoUnitTest; +import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncReqVO; +import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrDepartmentPageRespVO; +import com.zt.plat.module.system.enums.integration.IWorkSyncEntityTypeEnum; +import com.zt.plat.module.system.service.dept.DeptService; +import com.zt.plat.module.system.service.integration.iwork.IWorkOrgRestService; +import com.zt.plat.module.system.service.integration.iwork.IWorkSyncProcessor; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.stubbing.Answer; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +class IWorkSyncServiceImplTest extends BaseMockitoUnitTest { + + @InjectMocks + private IWorkSyncServiceImpl syncService; + + @Mock + private IWorkOrgRestService orgRestService; + @Mock + private IWorkSyncProcessor syncProcessor; + @Mock + private DeptService deptService; + + @Test + void shouldBackfillCodesWhenPlaceholdersExistAfterFullSync() { + IWorkFullSyncReqVO reqVO = new IWorkFullSyncReqVO(); + reqVO.setPageSize(1); + reqVO.setMaxPages(1); + + IWorkHrDepartmentPageRespVO pageResp = new IWorkHrDepartmentPageRespVO(); + pageResp.setSuccess(true); + IWorkHrDepartmentPageRespVO.Department dept = new IWorkHrDepartmentPageRespVO.Department(); + dept.setId(1); + pageResp.setDataList(List.of(dept)); + when(orgRestService.listDepartments(any())).thenReturn(pageResp); + + // 在部门同步时标记占位 ID + doAnswer((Answer) invocation -> { + IWorkSyncProcessor.DeptSyncContext context = invocation.getArgument(2); + if (context != null) { + context.getPlaceholderDeptIds().add(500L); + } + return IWorkSyncProcessor.BatchResult.empty(); + }).when(syncProcessor).syncDepartments(any(), any(), any(IWorkSyncProcessor.DeptSyncContext.class)); + + when(syncProcessor.flushDeptPending(any(), any())).thenReturn(IWorkSyncProcessor.BatchResult.empty()); + + syncService.fullSyncDepartments(reqVO); + + verify(deptService, times(1)).backfillMissingCodesWithoutEvent(argThat(set -> set.contains(500L))); + } +} From cea886c9b26e1777723798fdee6985825b2910fa Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 22 Dec 2025 09:51:05 +0800 Subject: [PATCH 05/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../provider/UserDeptDataFeignProvider.java | 81 ++++++++++ .../provider/UserPostDataFeignProvider.java | 81 ++++++++++ .../provider/DatabusUserDeptProviderApi.java | 71 ++++++++ .../provider/DatabusUserPostProviderApi.java | 71 ++++++++ .../rpc/config/RpcConfiguration.java | 9 +- .../DatabusUserDeptProviderApiImpl.java | 151 ++++++++++++++++++ .../DatabusUserPostProviderApiImpl.java | 139 ++++++++++++++++ .../module/system/api/dept/PostApiImpl.java | 4 + 8 files changed, 604 insertions(+), 3 deletions(-) create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java new file mode 100644 index 00000000..81f3bcf2 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java @@ -0,0 +1,81 @@ +package com.zt.plat.framework.databus.server.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.databus.server.core.provider.DataProvider; +import com.zt.plat.framework.databus.server.core.provider.DataProviderRegistry; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * 用户-部门关系数据提供者 + */ +@Slf4j +@Component +public class UserDeptDataFeignProvider implements DataProvider { + + public static final String PROVIDER_TYPE = "USER_DEPT"; + + @Resource + private DatabusUserDeptProviderApi userDeptProviderApi; + + @Resource + private DataProviderRegistry dataProviderRegistry; + + @PostConstruct + public void init() { + dataProviderRegistry.register(this); + } + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public CursorPageData getPageByCursor(LocalDateTime cursorTime, Long cursorId, + int batchSize, Long tenantId) { + CursorPageReqDTO reqDTO = CursorPageReqDTO.builder() + .cursorTime(cursorTime) + .cursorId(cursorId) + .batchSize(batchSize) + .tenantId(tenantId) + .build(); + + CommonResult> result = userDeptProviderApi.getPageByCursor(reqDTO); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-部门关系数据失败: " + result.getMsg()); + } + + CursorPageResult pageResult = result.getData(); + return CursorPageData.of( + pageResult.getList(), + pageResult.getNextCursorTime(), + pageResult.getNextCursorId(), + pageResult.getCount(), + Boolean.TRUE.equals(pageResult.getHasMore()), + (pageResult.getTotal() != null ? pageResult.getTotal() : 0L) + ); + } + + @Override + public long count(Long tenantId) { + CommonResult result = userDeptProviderApi.count(tenantId); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-部门关系总数失败: " + result.getMsg()); + } + return result.getData(); + } + + @Override + public Long extractUid(DatabusUserDeptData data) { + return data.getId(); + } +} diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java new file mode 100644 index 00000000..b7df241a --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java @@ -0,0 +1,81 @@ +package com.zt.plat.framework.databus.server.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.databus.server.core.provider.DataProvider; +import com.zt.plat.framework.databus.server.core.provider.DataProviderRegistry; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * 用户-岗位关系数据提供者 + */ +@Slf4j +@Component +public class UserPostDataFeignProvider implements DataProvider { + + public static final String PROVIDER_TYPE = "USER_POST"; + + @Resource + private DatabusUserPostProviderApi userPostProviderApi; + + @Resource + private DataProviderRegistry dataProviderRegistry; + + @PostConstruct + public void init() { + dataProviderRegistry.register(this); + } + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public CursorPageData getPageByCursor(LocalDateTime cursorTime, Long cursorId, + int batchSize, Long tenantId) { + CursorPageReqDTO reqDTO = CursorPageReqDTO.builder() + .cursorTime(cursorTime) + .cursorId(cursorId) + .batchSize(batchSize) + .tenantId(tenantId) + .build(); + + CommonResult> result = userPostProviderApi.getPageByCursor(reqDTO); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-岗位关系数据失败: " + result.getMsg()); + } + + CursorPageResult pageResult = result.getData(); + return CursorPageData.of( + pageResult.getList(), + pageResult.getNextCursorTime(), + pageResult.getNextCursorId(), + pageResult.getCount(), + Boolean.TRUE.equals(pageResult.getHasMore()), + (pageResult.getTotal() != null ? pageResult.getTotal() : 0L) + ); + } + + @Override + public long count(Long tenantId) { + CommonResult result = userPostProviderApi.count(tenantId); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-岗位关系总数失败: " + result.getMsg()); + } + return result.getData(); + } + + @Override + public Long extractUid(DatabusUserPostData data) { + return data.getId(); + } +} diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java new file mode 100644 index 00000000..5e393626 --- /dev/null +++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java @@ -0,0 +1,71 @@ +package com.zt.plat.module.databus.api.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Databus 用户-部门关系数据提供者 API + *

+ * 供 Databus 调用,获取用户-部门关联数据用于全量/增量同步 + * + * @author ZT + */ +@FeignClient(name = "${databus.provider.user-dept.service:system-server}") +@Tag(name = "RPC 服务 - Databus 用户-部门关系数据提供者") +public interface DatabusUserDeptProviderApi { + + String PREFIX = "/rpc/databus/user-dept"; + + /** + * 游标分页查询用户-部门关系数据(用于全量同步) + * + * @param reqDTO 游标分页请求 + * @return 用户-部门关系数据分页结果 + */ + @PostMapping(PREFIX + "/page-by-cursor") + @Operation(summary = "游标分页查询用户-部门关系数据") + CommonResult> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO); + + /** + * 根据ID查询用户-部门关系详情(用于增量同步) + * + * @param id 关系ID + * @return 用户-部门关系数据 + */ + @GetMapping(PREFIX + "/get") + @Operation(summary = "查询用户-部门关系详情") + @Parameter(name = "id", description = "关系ID", required = true, example = "1001") + CommonResult getById(@RequestParam("id") Long id); + + /** + * 批量查询用户-部门关系详情(用于增量同步批量获取) + * + * @param ids 关系ID列表 + * @return 用户-部门关系数据列表 + */ + @GetMapping(PREFIX + "/list") + @Operation(summary = "批量查询用户-部门关系详情") + @Parameter(name = "ids", description = "关系ID列表", required = true, example = "1001,1002,1003") + CommonResult> getListByIds(@RequestParam("ids") List ids); + + /** + * 统计用户-部门关系总数(用于全量同步进度计算) + * + * @param tenantId 租户ID(可选) + * @return 用户-部门关系总数 + */ + @GetMapping(PREFIX + "/count") + @Operation(summary = "统计用户-部门关系总数") + @Parameter(name = "tenantId", description = "租户ID", example = "1") + CommonResult count(@RequestParam(value = "tenantId", required = false) Long tenantId); + +} diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java new file mode 100644 index 00000000..6e00365d --- /dev/null +++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java @@ -0,0 +1,71 @@ +package com.zt.plat.module.databus.api.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Databus 用户-岗位关系数据提供者 API + *

+ * 供 Databus 调用,获取用户-岗位关联数据用于全量/增量同步 + * + * @author ZT + */ +@FeignClient(name = "${databus.provider.user-post.service:system-server}") +@Tag(name = "RPC 服务 - Databus 用户-岗位关系数据提供者") +public interface DatabusUserPostProviderApi { + + String PREFIX = "/rpc/databus/user-post"; + + /** + * 游标分页查询用户-岗位关系数据(用于全量同步) + * + * @param reqDTO 游标分页请求 + * @return 用户-岗位关系数据分页结果 + */ + @PostMapping(PREFIX + "/page-by-cursor") + @Operation(summary = "游标分页查询用户-岗位关系数据") + CommonResult> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO); + + /** + * 根据ID查询用户-岗位关系详情(用于增量同步) + * + * @param id 关系ID + * @return 用户-岗位关系数据 + */ + @GetMapping(PREFIX + "/get") + @Operation(summary = "查询用户-岗位关系详情") + @Parameter(name = "id", description = "关系ID", required = true, example = "1001") + CommonResult getById(@RequestParam("id") Long id); + + /** + * 批量查询用户-岗位关系详情(用于增量同步批量获取) + * + * @param ids 关系ID列表 + * @return 用户-岗位关系数据列表 + */ + @GetMapping(PREFIX + "/list") + @Operation(summary = "批量查询用户-岗位关系详情") + @Parameter(name = "ids", description = "关系ID列表", required = true, example = "1001,1002,1003") + CommonResult> getListByIds(@RequestParam("ids") List ids); + + /** + * 统计用户-岗位关系总数(用于全量同步进度计算) + * + * @param tenantId 租户ID(可选) + * @return 用户-岗位关系总数 + */ + @GetMapping(PREFIX + "/count") + @Operation(summary = "统计用户-岗位关系总数") + @Parameter(name = "tenantId", description = "租户ID", example = "1") + CommonResult count(@RequestParam(value = "tenantId", required = false) Long tenantId); + +} diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java index 32e911e1..c62e2b2d 100644 --- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java +++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java @@ -4,6 +4,8 @@ import com.zt.plat.framework.common.biz.system.oauth2.OAuth2TokenCommonApi; import com.zt.plat.module.databus.api.provider.DatabusDeptProviderApi; import com.zt.plat.module.databus.api.provider.DatabusPostProviderApi; import com.zt.plat.module.databus.api.provider.DatabusUserProviderApi; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.system.api.dept.PostApi; import com.zt.plat.module.system.api.user.AdminUserApi; @@ -21,9 +23,10 @@ import org.springframework.context.annotation.Configuration; DatabusDeptProviderApi.class, DatabusUserProviderApi.class, DatabusPostProviderApi.class, - PostApi.class, - DeptApi.class, - AdminUserApi.class, + DatabusUserDeptProviderApi.class, + DatabusUserPostProviderApi.class, + PostApi.class, + DeptApi.class, }) public class RpcConfiguration { } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java new file mode 100644 index 00000000..15b375eb --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -0,0 +1,151 @@ +package com.zt.plat.module.system.api.databus; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; +import com.zt.plat.module.system.dal.mysql.userdept.UserDeptMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * Databus 用户-部门关系数据提供者 API 实现 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderApi { + + @Resource + private UserDeptMapper userDeptMapper; + + @Override + public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { + // 构建游标查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) + if (!reqDTO.isFirstPage()) { + queryWrapper.and(w -> w + .gt(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) + .or(o -> o + .eq(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) + .gt(UserDeptDO::getId, reqDTO.getCursorId()) + ) + ); + } + + // 租户过滤(如果指定) + if (reqDTO.getTenantId() != null) { + queryWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); + } + + // 按 create_time, id 升序排列,确保顺序稳定 + queryWrapper.orderByAsc(UserDeptDO::getCreateTime) + .orderByAsc(UserDeptDO::getId); + + // 多查一条判断是否有更多数据 + int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; + queryWrapper.last("LIMIT " + (limit + 1)); + + List list = userDeptMapper.selectList(queryWrapper); + + // 判断是否有更多 + boolean hasMore = list.size() > limit; + if (hasMore) { + list = list.subList(0, limit); + } + + if (CollUtil.isEmpty(list)) { + return success(CursorPageResult.empty()); + } + + // 转换为同步数据 + List dataList = list.stream() + .map(this::convertToData) + .collect(Collectors.toList()); + + // 获取最后一条数据的游标 + UserDeptDO last = list.get(list.size() - 1); + + // 首次查询时返回总数 + Long total = null; + if (reqDTO.isFirstPage()) { + LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); + if (reqDTO.getTenantId() != null) { + countWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); + } + total = userDeptMapper.selectCount(countWrapper); + } + + return success(CursorPageResult.of( + dataList, + last.getCreateTime(), + last.getId(), + hasMore, + total + )); + } + + @Override + public CommonResult getById(Long id) { + UserDeptDO userDept = userDeptMapper.selectById(id); + if (userDept == null) { + return success(null); + } + return success(convertToData(userDept)); + } + + @Override + public CommonResult> getListByIds(List ids) { + if (CollUtil.isEmpty(ids)) { + return success(Collections.emptyList()); + } + + List list = userDeptMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + return success(list.stream() + .map(this::convertToData) + .collect(Collectors.toList())); + } + + @Override + public CommonResult count(Long tenantId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (tenantId != null) { + queryWrapper.eq(UserDeptDO::getTenantId, tenantId); + } + return success(userDeptMapper.selectCount(queryWrapper)); + } + + /** + * 将 UserDeptDO 转换为 DatabusUserDeptData + */ + private DatabusUserDeptData convertToData(UserDeptDO userDept) { + return DatabusUserDeptData.builder() + .id(userDept.getId()) + .userId(userDept.getUserId()) + .deptId(userDept.getDeptId()) + .tenantId(userDept.getTenantId()) + .remark(userDept.getRemark()) + .build(); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java new file mode 100644 index 00000000..96db8704 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java @@ -0,0 +1,139 @@ +package com.zt.plat.module.system.api.databus; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; +import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; +import com.zt.plat.module.system.dal.mysql.dept.UserPostMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * Databus 用户-岗位关系数据提供者 API 实现 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderApi { + + @Resource + private UserPostMapper userPostMapper; + + @Override + public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { + // 构建游标查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) + if (!reqDTO.isFirstPage()) { + queryWrapper.and(w -> w + .gt(UserPostDO::getCreateTime, reqDTO.getCursorTime()) + .or(o -> o + .eq(UserPostDO::getCreateTime, reqDTO.getCursorTime()) + .gt(UserPostDO::getId, reqDTO.getCursorId()) + ) + ); + } + + // 注意:UserPostDO 没有租户字段,忽略 tenantId 过滤 + + // 按 create_time, id 升序排列,确保顺序稳定 + queryWrapper.orderByAsc(UserPostDO::getCreateTime) + .orderByAsc(UserPostDO::getId); + + // 多查一条判断是否有更多数据 + int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; + queryWrapper.last("LIMIT " + (limit + 1)); + + List list = userPostMapper.selectList(queryWrapper); + + // 判断是否有更多 + boolean hasMore = list.size() > limit; + if (hasMore) { + list = list.subList(0, limit); + } + + if (CollUtil.isEmpty(list)) { + return success(CursorPageResult.empty()); + } + + // 转换为同步数据 + List dataList = list.stream() + .map(this::convertToData) + .collect(Collectors.toList()); + + // 获取最后一条数据的游标 + UserPostDO last = list.get(list.size() - 1); + + // 首次查询时返回总数 + Long total = null; + if (reqDTO.isFirstPage()) { + total = userPostMapper.selectCount(new LambdaQueryWrapper<>()); + } + + return success(CursorPageResult.of( + dataList, + last.getCreateTime(), + last.getId(), + hasMore, + total + )); + } + + @Override + public CommonResult getById(Long id) { + UserPostDO userPost = userPostMapper.selectById(id); + if (userPost == null) { + return success(null); + } + return success(convertToData(userPost)); + } + + @Override + public CommonResult> getListByIds(List ids) { + if (CollUtil.isEmpty(ids)) { + return success(Collections.emptyList()); + } + + List list = userPostMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + return success(list.stream() + .map(this::convertToData) + .collect(Collectors.toList())); + } + + @Override + public CommonResult count(Long tenantId) { + // 注意:UserPostDO 没有租户字段,返回全量总数 + return success(userPostMapper.selectCount(new LambdaQueryWrapper<>())); + } + + /** + * 将 UserPostDO 转换为 DatabusUserPostData + */ + private DatabusUserPostData convertToData(UserPostDO userPost) { + return DatabusUserPostData.builder() + .id(userPost.getId()) + .userId(userPost.getUserId()) + .postId(userPost.getPostId()) + .build(); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java index 40c7e22b..97cf029e 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java @@ -10,6 +10,7 @@ import com.zt.plat.module.system.controller.admin.dept.vo.post.PostSaveReqVO; import com.zt.plat.module.system.dal.dataobject.dept.PostDO; import com.zt.plat.module.system.service.dept.PostService; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -20,6 +21,7 @@ import java.util.List; import static com.zt.plat.framework.common.pojo.CommonResult.success; +@Slf4j @RestController // 提供 RESTful API 接口,给 Feign 调用 @Validated public class PostApiImpl implements PostApi { @@ -36,6 +38,7 @@ public class PostApiImpl implements PostApi { @Override public CommonResult updatePost(PostSaveReqDTO updateReqVO) { + log.error("ssssssssss"); PostSaveReqVO reqVO = BeanUtils.toBean(updateReqVO, PostSaveReqVO.class); postService.updatePost(reqVO); return success(true); @@ -49,6 +52,7 @@ public class PostApiImpl implements PostApi { @Override public CommonResult getPost(Long id) { + log.error("cccccccc"+id); PostDO post = postService.getPost(id); return success(BeanUtils.toBean(post, PostRespDTO.class)); } From 0bdded447a97926ac90a8be7ad1a5ed7934fbac3 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 22 Dec 2025 11:03:15 +0800 Subject: [PATCH 06/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../userdept/UserDeptSyncServiceImpl.java | 85 ++++++++++++++----- .../userpost/UserPostSyncServiceImpl.java | 84 +++++++++++++----- .../consumer/DatabusUserChangeConsumer.java | 10 ++- .../rpc/config/RpcConfiguration.java | 4 + .../system/api/userdept/UserDeptApi.java | 64 ++++++++++++++ .../api/userdept/dto/UserDeptRespDTO.java | 31 +++++++ .../api/userdept/dto/UserDeptSaveReqDTO.java | 26 ++++++ .../system/api/userpost/UserPostApi.java | 64 ++++++++++++++ .../api/userpost/dto/UserPostRespDTO.java | 28 ++++++ .../api/userpost/dto/UserPostSaveReqDTO.java | 23 +++++ .../DatabusUserDeptProviderApiImpl.java | 48 +++-------- .../DatabusUserPostProviderApiImpl.java | 36 +++----- .../databus/DatabusUserProviderApiImpl.java | 7 ++ .../system/dal/mysql/dept/UserPostMapper.java | 43 ++++++++++ .../dal/mysql/userdept/UserDeptMapper.java | 43 ++++++++++ 15 files changed, 494 insertions(+), 102 deletions(-) create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java index 9027e379..04f16ae4 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java @@ -1,56 +1,101 @@ package com.zt.plat.framework.databus.client.handler.userdept; import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.system.api.userdept.UserDeptApi; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; /** - * 用户-部门关系同步服务实现 + * 用户-部门关系同步服务实现(通过 Feign API 调用远程服务) *

* 使用条件: * 1. zt.databus.sync.client.enabled=true + * 2. 系统中存在 UserDeptApi 接口(Feign 客户端) *

- * 注意:由于用户-部门关系通常集成在用户管理中,此实现为占位符。 - * 分公司可以根据实际情况: - * 1. 自定义实现此接口,直接操作本地数据库 - * 2. 或者通过用户管理 API 间接处理关联关系 + * 如果分公司需要自定义实现,可以创建自己的 UserDeptSyncService Bean, + * 此默认实现会自动失效(@ConditionalOnMissingBean) * * @author ZT */ @Slf4j @Service @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") +@ConditionalOnClass(name = "com.zt.plat.module.system.api.userdept.UserDeptApi") public class UserDeptSyncServiceImpl implements UserDeptSyncService { + @Autowired(required = false) + private UserDeptApi userDeptApi; // Feign 远程调用接口 + @Override public void create(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到创建用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,通过本地 API 或直接数据库操作完成同步 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过创建用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系创建成功, userId={}, deptId={}", data.getUserId(), data.getDeptId()); } @Override public void update(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到更新用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过更新用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + userDeptApi.updateUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系更新成功, userId={}, deptId={}", data.getUserId(), data.getDeptId()); } @Override public void delete(Long id) { - log.info("[UserDeptSync] 收到删除用户-部门关系请求, id={}", id); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过删除用户-部门关系, id={}", id); + return; + } + userDeptApi.deleteUserDept(id).checkError(); + log.info("[UserDeptSync] 用户-部门关系删除成功, id={}", id); } @Override public void fullSync(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到全量同步用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,逻辑:存在则更新,不存在则插入 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过全量同步用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + try { + // 尝试获取,存在则更新,不存在则创建 + var existing = userDeptApi.getUserDept(dto.getId()); + if (existing.isSuccess() && existing.getData() != null) { + userDeptApi.updateUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-更新成功, id={}", dto.getId()); + } else { + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + } + } catch (Exception e) { + // 获取失败,尝试创建 + log.warn("[UserDeptSync] 用户-部门关系获取失败,尝试创建, id={}", dto.getId()); + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + } + } + + /** + * 构建用户部门关系 DTO(用于 Feign 调用) + */ + private UserDeptSaveReqDTO buildUserDeptDTO(DatabusUserDeptData data) { + UserDeptSaveReqDTO dto = new UserDeptSaveReqDTO(); + dto.setId(data.getId()); + dto.setUserId(data.getUserId()); + dto.setDeptId(data.getDeptId()); + dto.setRemark(data.getRemark()); + return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java index b41d6ac8..01eb2b4b 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java @@ -1,56 +1,100 @@ package com.zt.plat.framework.databus.client.handler.userpost; import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.system.api.userpost.UserPostApi; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; /** - * 用户-岗位关系同步服务实现 + * 用户-岗位关系同步服务实现(通过 Feign API 调用远程服务) *

* 使用条件: * 1. zt.databus.sync.client.enabled=true + * 2. 系统中存在 UserPostApi 接口(Feign 客户端) *

- * 注意:由于用户-岗位关系通常集成在用户管理中,此实现为占位符。 - * 分公司可以根据实际情况: - * 1. 自定义实现此接口,直接操作本地数据库 - * 2. 或者通过用户管理 API 间接处理关联关系 + * 如果分公司需要自定义实现,可以创建自己的 UserPostSyncService Bean, + * 此默认实现会自动失效(@ConditionalOnMissingBean) * * @author ZT */ @Slf4j @Service @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") +@ConditionalOnClass(name = "com.zt.plat.module.system.api.userpost.UserPostApi") public class UserPostSyncServiceImpl implements UserPostSyncService { + @Autowired(required = false) + private UserPostApi userPostApi; // Feign 远程调用接口 + @Override public void create(DatabusUserPostData data) { - log.info("[UserPostSync] 收到创建用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,通过本地 API 或直接数据库操作完成同步 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过创建用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系创建成功, userId={}, postId={}", data.getUserId(), data.getPostId()); } @Override public void update(DatabusUserPostData data) { - log.info("[UserPostSync] 收到更新用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过更新用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + userPostApi.updateUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系更新成功, userId={}, postId={}", data.getUserId(), data.getPostId()); } @Override public void delete(Long id) { - log.info("[UserPostSync] 收到删除用户-岗位关系请求, id={}", id); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过删除用户-岗位关系, id={}", id); + return; + } + userPostApi.deleteUserPost(id).checkError(); + log.info("[UserPostSync] 用户-岗位关系删除成功, id={}", id); } @Override public void fullSync(DatabusUserPostData data) { - log.info("[UserPostSync] 收到全量同步用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,逻辑:存在则更新,不存在则插入 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过全量同步用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + try { + // 尝试获取,存在则更新,不存在则创建 + var existing = userPostApi.getUserPost(dto.getId()); + if (existing.isSuccess() && existing.getData() != null) { + userPostApi.updateUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-更新成功, id={}", dto.getId()); + } else { + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + } + } catch (Exception e) { + // 获取失败,尝试创建 + log.warn("[UserPostSync] 用户-岗位关系获取失败,尝试创建, id={}", dto.getId()); + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + } + } + + /** + * 构建用户岗位关系 DTO(用于 Feign 调用) + */ + private UserPostSaveReqDTO buildUserPostDTO(DatabusUserPostData data) { + UserPostSaveReqDTO dto = new UserPostSaveReqDTO(); + dto.setId(data.getId()); + dto.setUserId(data.getUserId()); + dto.setPostId(data.getPostId()); + return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java index dd3a52e0..43fd8e97 100644 --- a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java @@ -34,7 +34,15 @@ public class DatabusUserChangeConsumer implements RocketMQListener dataMap = new HashMap<>(); diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java index c62e2b2d..d79beb52 100644 --- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java +++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java @@ -9,6 +9,8 @@ import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.system.api.dept.PostApi; import com.zt.plat.module.system.api.user.AdminUserApi; +import com.zt.plat.module.system.api.userdept.UserDeptApi; +import com.zt.plat.module.system.api.userpost.UserPostApi; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Configuration; @@ -27,6 +29,8 @@ import org.springframework.context.annotation.Configuration; DatabusUserPostProviderApi.class, PostApi.class, DeptApi.class, + UserDeptApi.class, + UserPostApi.class, }) public class RpcConfiguration { } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java new file mode 100644 index 00000000..d48c6b69 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java @@ -0,0 +1,64 @@ +package com.zt.plat.module.system.api.userdept; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.system.api.userdept.dto.UserDeptRespDTO; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; +import com.zt.plat.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.List; + +/** + * 用户-部门关系 Feign API + * + * @author ZT + */ +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 用户部门关系") +public interface UserDeptApi { + + String PREFIX = ApiConstants.PREFIX + "/user-dept"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增用户部门关系") + CommonResult createUserDept(@RequestBody UserDeptSaveReqDTO reqVO); + + @PutMapping(PREFIX + "/update") + @Operation(summary = "修改用户部门关系") + CommonResult updateUserDept(@RequestBody UserDeptSaveReqDTO reqVO); + + @DeleteMapping(PREFIX + "/delete") + @Operation(summary = "删除用户部门关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult deleteUserDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "通过ID查询用户部门关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult getUserDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list-by-user-id") + @Operation(summary = "通过用户ID查询用户部门关系列表") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult> getUserDeptListByUserId(@RequestParam("userId") Long userId); + + @GetMapping(PREFIX + "/list-by-dept-id") + @Operation(summary = "通过部门ID查询用户部门关系列表") + @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) + CommonResult> getUserDeptListByDeptId(@RequestParam("deptId") Long deptId); + + @DeleteMapping(PREFIX + "/delete-by-user-id") + @Operation(summary = "通过用户ID删除用户部门关系") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult deleteUserDeptByUserId(@RequestParam("userId") Long userId); + + @DeleteMapping(PREFIX + "/delete-by-dept-id") + @Operation(summary = "通过部门ID删除用户部门关系") + @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) + CommonResult deleteUserDeptByDeptId(@RequestParam("deptId") Long deptId); +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java new file mode 100644 index 00000000..5a558b90 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java @@ -0,0 +1,31 @@ +package com.zt.plat.module.system.api.userdept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户部门关系 Response DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户部门关系 Response DTO") +@Data +public class UserDeptRespDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "部门编号", example = "100") + private Long deptId; + + @Schema(description = "备注", example = "主部门") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java new file mode 100644 index 00000000..b18f2a56 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java @@ -0,0 +1,26 @@ +package com.zt.plat.module.system.api.userdept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户部门关系创建/修改 Request DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户部门关系创建/修改 Request DTO") +@Data +public class UserDeptSaveReqDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1", required = true) + private Long userId; + + @Schema(description = "部门编号", example = "100", required = true) + private Long deptId; + + @Schema(description = "备注", example = "主部门") + private String remark; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java new file mode 100644 index 00000000..a58e09cb --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java @@ -0,0 +1,64 @@ +package com.zt.plat.module.system.api.userpost; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.system.api.userpost.dto.UserPostRespDTO; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; +import com.zt.plat.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.List; + +/** + * 用户-岗位关系 Feign API + * + * @author ZT + */ +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 用户岗位关系") +public interface UserPostApi { + + String PREFIX = ApiConstants.PREFIX + "/user-post"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增用户岗位关系") + CommonResult createUserPost(@RequestBody UserPostSaveReqDTO reqVO); + + @PutMapping(PREFIX + "/update") + @Operation(summary = "修改用户岗位关系") + CommonResult updateUserPost(@RequestBody UserPostSaveReqDTO reqVO); + + @DeleteMapping(PREFIX + "/delete") + @Operation(summary = "删除用户岗位关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult deleteUserPost(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "通过ID查询用户岗位关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult getUserPost(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list-by-user-id") + @Operation(summary = "通过用户ID查询用户岗位关系列表") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult> getUserPostListByUserId(@RequestParam("userId") Long userId); + + @GetMapping(PREFIX + "/list-by-post-id") + @Operation(summary = "通过岗位ID查询用户岗位关系列表") + @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) + CommonResult> getUserPostListByPostId(@RequestParam("postId") Long postId); + + @DeleteMapping(PREFIX + "/delete-by-user-id") + @Operation(summary = "通过用户ID删除用户岗位关系") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult deleteUserPostByUserId(@RequestParam("userId") Long userId); + + @DeleteMapping(PREFIX + "/delete-by-post-id") + @Operation(summary = "通过岗位ID删除用户岗位关系") + @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) + CommonResult deleteUserPostByPostId(@RequestParam("postId") Long postId); +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java new file mode 100644 index 00000000..e7251a61 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java @@ -0,0 +1,28 @@ +package com.zt.plat.module.system.api.userpost.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户岗位关系 Response DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户岗位关系 Response DTO") +@Data +public class UserPostRespDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "岗位编号", example = "100") + private Long postId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java new file mode 100644 index 00000000..4ad5af68 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java @@ -0,0 +1,23 @@ +package com.zt.plat.module.system.api.userpost.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户岗位关系创建/修改 Request DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户岗位关系创建/修改 Request DTO") +@Data +public class UserPostSaveReqDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1", required = true) + private Long userId; + + @Schema(description = "岗位编号", example = "100", required = true) + private Long postId; +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java index 15b375eb..3a461df9 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -35,34 +35,16 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { - // 构建游标查询条件 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) - if (!reqDTO.isFirstPage()) { - queryWrapper.and(w -> w - .gt(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) - .or(o -> o - .eq(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) - .gt(UserDeptDO::getId, reqDTO.getCursorId()) - ) - ); - } - - // 租户过滤(如果指定) - if (reqDTO.getTenantId() != null) { - queryWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); - } - - // 按 create_time, id 升序排列,确保顺序稳定 - queryWrapper.orderByAsc(UserDeptDO::getCreateTime) - .orderByAsc(UserDeptDO::getId); - // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - queryWrapper.last("LIMIT " + (limit + 1)); - List list = userDeptMapper.selectList(queryWrapper); + // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的部门关系 + List list = userDeptMapper.selectPageByCursorWithUserSource( + reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), + reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), + reqDTO.getTenantId(), + limit + 1 + ); // 判断是否有更多 boolean hasMore = list.size() > limit; @@ -82,14 +64,11 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp // 获取最后一条数据的游标 UserDeptDO last = list.get(list.size() - 1); - // 首次查询时返回总数 + // 首次查询时返���总数 Long total = null; if (reqDTO.isFirstPage()) { - LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); - if (reqDTO.getTenantId() != null) { - countWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); - } - total = userDeptMapper.selectCount(countWrapper); + // ⚠️ 只统计 userSource = 2 的用户的部门关系 + total = userDeptMapper.countWithUserSource(reqDTO.getTenantId()); } return success(CursorPageResult.of( @@ -128,11 +107,8 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult count(Long tenantId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - if (tenantId != null) { - queryWrapper.eq(UserDeptDO::getTenantId, tenantId); - } - return success(userDeptMapper.selectCount(queryWrapper)); + // ⚠️ 只统计 userSource = 2 的用户的部门关系 + return success(userDeptMapper.countWithUserSource(tenantId)); } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java index 96db8704..faabe471 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java @@ -35,31 +35,16 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp @Override public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { - // 构建游标查询条件 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) - if (!reqDTO.isFirstPage()) { - queryWrapper.and(w -> w - .gt(UserPostDO::getCreateTime, reqDTO.getCursorTime()) - .or(o -> o - .eq(UserPostDO::getCreateTime, reqDTO.getCursorTime()) - .gt(UserPostDO::getId, reqDTO.getCursorId()) - ) - ); - } - - // 注意:UserPostDO 没有租户字段,忽略 tenantId 过滤 - - // 按 create_time, id 升序排列,确保顺序稳定 - queryWrapper.orderByAsc(UserPostDO::getCreateTime) - .orderByAsc(UserPostDO::getId); - // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - queryWrapper.last("LIMIT " + (limit + 1)); - List list = userPostMapper.selectList(queryWrapper); + // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的岗位关系 + List list = userPostMapper.selectPageByCursorWithUserSource( + reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), + reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), + reqDTO.getTenantId(), + limit + 1 + ); // 判断是否有更多 boolean hasMore = list.size() > limit; @@ -82,7 +67,8 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp // 首次查询时返回总数 Long total = null; if (reqDTO.isFirstPage()) { - total = userPostMapper.selectCount(new LambdaQueryWrapper<>()); + // ⚠️ 只统计 userSource = 2 的用户的岗位关系 + total = userPostMapper.countWithUserSource(reqDTO.getTenantId()); } return success(CursorPageResult.of( @@ -121,8 +107,8 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp @Override public CommonResult count(Long tenantId) { - // 注意:UserPostDO 没有租户字段,返回全量总数 - return success(userPostMapper.selectCount(new LambdaQueryWrapper<>())); + // ⚠️ 只统计 userSource = 2 的用户的岗位关系 + return success(userPostMapper.countWithUserSource(tenantId)); } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java index 286b9984..f6b9050a 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java @@ -54,6 +54,9 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { // 构建游标查询条件 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只同步 userSource = 2 的用户 + queryWrapper.eq(AdminUserDO::getUserSource, 2); + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) if (!reqDTO.isFirstPage()) { queryWrapper.and(w -> w @@ -100,6 +103,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { Long total = null; if (reqDTO.isFirstPage()) { LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只统计 userSource = 2 的用户 + countWrapper.eq(AdminUserDO::getUserSource, 2); if (reqDTO.getTenantId() != null) { countWrapper.eq(AdminUserDO::getTenantId, reqDTO.getTenantId()); } @@ -143,6 +148,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { @Override public CommonResult count(Long tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只统计 userSource = 2 的用户 + queryWrapper.eq(AdminUserDO::getUserSource, 2); if (tenantId != null) { queryWrapper.eq(AdminUserDO::getTenantId, tenantId); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java index fa9bd6aa..2df5c891 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java @@ -5,7 +5,10 @@ import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX; import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -29,4 +32,44 @@ public interface UserPostMapper extends BaseMapperX { default void deleteByUserId(Long userId) { delete(Wrappers.lambdaUpdate(UserPostDO.class).eq(UserPostDO::getUserId, userId)); } + + /** + * 游标分页查询用户-岗位关系(只查询 userSource = 2 的用户) + * @param cursorTime 游标时间 + * @param cursorId 游标ID + * @param tenantId 租户ID(可选) + * @param limit 限制数量 + * @return 用户岗位关系列表 + */ + @Select("") + List selectPageByCursorWithUserSource(@Param("cursorTime") LocalDateTime cursorTime, + @Param("cursorId") Long cursorId, + @Param("tenantId") Long tenantId, + @Param("limit") Integer limit); + + /** + * 统计用户-岗位关系数量(只统计 userSource = 2 的用户) + * @param tenantId 租户ID(可选) + * @return 数量 + */ + @Select("") + Long countWithUserSource(@Param("tenantId") Long tenantId); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java index b9aad69a..bf21f41d 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java @@ -4,7 +4,10 @@ import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX; import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX; import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.time.LocalDateTime; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -45,4 +48,44 @@ public interface UserDeptMapper extends BaseMapperX { ); } + /** + * 游标分页查询用户-部门关系(只查询 userSource = 2 的用户) + * @param cursorTime 游标时间 + * @param cursorId 游标ID + * @param tenantId 租户ID(可选) + * @param limit 限制数量 + * @return 用户部门关系列表 + */ + @Select("") + List selectPageByCursorWithUserSource(@Param("cursorTime") LocalDateTime cursorTime, + @Param("cursorId") Long cursorId, + @Param("tenantId") Long tenantId, + @Param("limit") Integer limit); + + /** + * 统计用户-部门关系数量(只统计 userSource = 2 的用户) + * @param tenantId 租户ID(可选) + * @return 数量 + */ + @Select("") + Long countWithUserSource(@Param("tenantId") Long tenantId); + } \ No newline at end of file From d688932f6dbbcd4a0720cc8f2dc2a563eb137003 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Mon, 22 Dec 2025 13:43:56 +0800 Subject: [PATCH 07/48] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8D=E6=8B=86=E5=87=BA?= =?UTF-8?q?=E7=9A=84=E4=B8=9A=E5=8A=A1=E6=A8=A1=E5=9D=97=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8A=A0=E8=BD=BD=E6=95=B0=E6=8D=AE=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BusinessDataPermissionConfiguration.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionConfiguration.java b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionConfiguration.java index 174049ad..5f9a19c8 100644 --- a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionConfiguration.java +++ b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionConfiguration.java @@ -7,6 +7,8 @@ import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; import java.util.LinkedHashSet; import java.util.Set; @@ -18,14 +20,12 @@ import java.util.Set; public class BusinessDataPermissionConfiguration { @Bean - public BusinessDataPermissionEntityScanner businessDataPermissionEntityScanner(BeanFactory beanFactory, ApplicationContext applicationContext) { + public BusinessDataPermissionEntityScanner businessDataPermissionEntityScanner(BeanFactory beanFactory, ApplicationContext applicationContext, Environment environment) { Set basePackages = new LinkedHashSet<>(); + addConfiguredBasePackages(environment, basePackages); if (AutoConfigurationPackages.has(beanFactory)) { basePackages.addAll(AutoConfigurationPackages.get(beanFactory)); } - if (basePackages.isEmpty()) { - basePackages.add("com.zt"); - } ClassLoader classLoader = applicationContext != null ? applicationContext.getClassLoader() : Thread.currentThread().getContextClassLoader(); @@ -35,6 +35,21 @@ public class BusinessDataPermissionConfiguration { return new BusinessDataPermissionEntityScanner(basePackages, classLoader); } + private void addConfiguredBasePackages(Environment environment, Set basePackages) { + if (environment == null) { + return; + } + String configured = environment.getProperty("zt.info.base-package"); + if (!StringUtils.hasText(configured)) { + return; + } + for (String pkg : configured.split("[,;\\s]+")) { + if (StringUtils.hasText(pkg)) { + basePackages.add(pkg.trim()); + } + } + } + @Bean public CompanyDataPermissionRuleCustomizer autoCompanyDataPermissionRuleCustomizer(BusinessDataPermissionEntityScanner scanner) { return rule -> scanner.getEntityMetadata().forEach(metadata -> { From 02208869f0b6ce907a7cf1e9d879a6fd14ce4e50 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Mon, 22 Dec 2025 14:15:22 +0800 Subject: [PATCH 08/48] =?UTF-8?q?1.=20=E7=A7=BB=E9=99=A4=E4=BA=8C=E7=BB=B4?= =?UTF-8?q?=E7=A0=81=E9=BB=98=E8=AE=A4=E7=A4=BA=E4=BE=8B=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/file/FileConfigServiceImpl.java | 6 +++--- .../src/main/resources/file/bg1.png | Bin 0 -> 6600 bytes .../src/main/resources/file/erweima.jpg | Bin 18385 -> 0 bytes .../file/core/ftp/FtpFileClientTest.java | 2 +- .../file/core/local/LocalFileClientTest.java | 2 +- .../file/core/s3/S3FileClientTest.java | 2 +- .../file/core/sftp/SftpFileClientTest.java | 2 +- .../infra/service/file/FileServiceImplTest.java | 6 +++--- 8 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 zt-module-infra/zt-module-infra-server/src/main/resources/file/bg1.png delete mode 100644 zt-module-infra/zt-module-infra-server/src/main/resources/file/erweima.jpg diff --git a/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/service/file/FileConfigServiceImpl.java b/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/service/file/FileConfigServiceImpl.java index f0e41360..f625e2db 100644 --- a/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/service/file/FileConfigServiceImpl.java +++ b/zt-module-infra/zt-module-infra-server/src/main/java/com/zt/plat/module/infra/service/file/FileConfigServiceImpl.java @@ -2,6 +2,8 @@ package com.zt.plat.module.infra.service.file; import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.util.IdUtil; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.zt.plat.framework.common.pojo.PageResult; import com.zt.plat.framework.common.util.json.JsonUtils; import com.zt.plat.framework.common.util.validation.ValidationUtils; @@ -14,8 +16,6 @@ import com.zt.plat.module.infra.framework.file.core.client.FileClient; import com.zt.plat.module.infra.framework.file.core.client.FileClientConfig; import com.zt.plat.module.infra.framework.file.core.client.FileClientFactory; import com.zt.plat.module.infra.framework.file.core.enums.FileStorageEnum; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import jakarta.annotation.Resource; import jakarta.validation.Validator; import lombok.Getter; @@ -172,7 +172,7 @@ public class FileConfigServiceImpl implements FileConfigService { // 校验存在 validateFileConfigExists(id); // 上传文件 - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); + byte[] content = ResourceUtil.readBytes("file/bg1.png"); return getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg", "image/jpeg"); } diff --git a/zt-module-infra/zt-module-infra-server/src/main/resources/file/bg1.png b/zt-module-infra/zt-module-infra-server/src/main/resources/file/bg1.png new file mode 100644 index 0000000000000000000000000000000000000000..fa136983a286c78243629337b4a4f585d094fa44 GIT binary patch literal 6600 zcmZu$cR1VOw~wNTRik$8RV`v~YLB9-szyc7nz2VEsMc0nYpYqSN^Gs!m{qGv?NL;M z7$t~V_v?56x%avEkBlepdCvHp_nh-N`Nor#W+z#tHaT3=7g6a*rY1-|EyUkBdT z^_xY34+<|mOJ5L(lHuw_1j^230fAVN`daE{fw|iYh(NQocCx>_pJp6W2XxHq$Q$nZ zqpfOwH7y=}3He?X;%YN{hqwAwLBXUoYTMo2ZM)c};ie_yjfZ9;+*VbSv##3DD8A9B z-_RrH;hE#Fe|~iFFNHo+0c+?exvL=MiyQl^Ed>H)aZ9e5ogE>5eS!d1i9q&xpXXys-q@!<8r2 zG^=uRi62^S^HT~tbF$M}3v=kKg;lX|aBfsJss-H=e7yc>UWC_a!hx?S=s1nIxbQj% zpB|dsHJJ>*ht|>hHS5s*XtzPDt*OkNT-|XYd3d=GAH?GBEu5+*UVpQ?+hSe-A)jtwxS8aeO}?%Bx9Q)KeJKK1vT z*OQ0v&EYD6PM4PY)z2FcUZb;u=j*dBe@Qi9G77gjXo}k)%#V8!aByma27X$vON0rY z(kp>HQE-L7{Ofi+vL;jE0k(_x(AL*@+2-AOSA!b#bP-e?vd?#paB}*Xqrpf>ka`TCD(dM6)cX=Jr1nq=|Twy?oWQBcMTa1Pqh@K`*cpda<`-#N1d|nO(Ub%2<|2MEcD0SKi$^>de_KoBO?-B3 z@LuRrLDEXP#~cOQjfT;b}d? z)(13wA&~pLlVUCOu4!Qi8y@@fXeFe8}vDHq6-c|l6I(7CIUip z*)4zfBz6QdE18FM^2`MQb$-CzF6dv94;$AZ!?&>ST!8V}8rRSeroZvDP>Bl0=9k;N z1GDNMw9z_&hnY6VC%EX$sf!tE=HkMq{QxRtvRkVQ|JHv!e{z5FI?w(HJJxaILg zI%aiBtt}ofD(d8JF;H)}rn&S!arE&`gGrkIi0wsv%`~f%T@-Q`cM%(nSlRD-dcHg< zZZP|wV|p|fl^xo*HEXK&KsB4YD;z`nvll;AA)nK*E*_d+Xf9t|^rkk2e_$eIM<*}DmEdN$hJ3K0hJDYe z1%Q+z_N$7Wcbk2oO9voPpHW#r&5P>U$Q!E{I{sf=KeYuhjc3;$Sk500xREKKmVzG> zSLd1vS}N%w3t)pjT+)O$K9Ipp()yIj6pve&ZDptA^bOydqdai{`&3oo>AHFMJ2PAc z%5FZan2^UU{+YX6o4sVi?YUE2?R)f$e|`v#&BTO>#$EW0s~=b|ICM&=n^t#IMZcbV z;?vB3P3KzDGa+!(-Cq*FzcP4oK8F&PcZa|JF;Ky`XmBF7LDxx)hmpH5+R4jGo4Tgt z19fzIi3ia{cPz5Hu$`!Ud7|unFKM7%?l#*@ROa?I^Fv$%%ZM37O~)IYo6d~V>JvwZ=|HON`oD49sT`w zb?e0)o{hLL(ZRdWITELdJ>R?VWUpJLQ(QeNZuCkrZi_zu$f&gP01WgV&E0^`zI=mN z5W_^&!$*k$l#s(B{qNZwkj-}Rqr={n0W<6<(HFtJd;l=fl?xD z>I9$oULk5sFSMf<&$?kJ-GaZcok zlwczhYJu36yXOOw{sTt1Bq1YY;TW5uit&FkuRs}zV8i%F-hEn6hQ5(=OAjvADf|ek zcUk~@tI*LM_Ex68mgGgKuOtv)Q!^FJ`VsSZws`PFqUL+YQW^a#vDy+G!QLw~^wx99 z532CMe_-$H=bp&y3-fh;6_c6)vq4LC^R`iyyYiNU7{lI%Y+k^ea?>HCB`UXQ!eh62 zmEhSAbu*BB%gf=|<}ad8$*gujgO{Q*I8x>R?2g;#*ALH;^ zoir&lhttoTOZ3RNSU+120w!SeIJQNEBOc#<(tkVcL>7L9Q;4KbAN7Q73*gnN*?C+3>=9L}0ohdQc? zvq{ZI{!*wjJiC~B2!iP9rUtuk-8IgCHbtzH$Q=wL&Y}3qf4IKGe_>2Nwmm?s%?t(V4@dTOpgRnG$2kbvOpu@_s=EwFSRqL^;tmI7CWI2PbE~lm`JUo<{Ii5T8*hBQD+n9cTAoZJO}ix zG#dRq4o|faX97w@31OTrlocK(8jd(uziZ&Ndl_h0dAqAl;ZfGq%{qY6ptjbNw~%{* zZnkm&9Qm7$$=*e|*lJJ1 zzM($)tE8VyKFnpSxgXH3#p2F+?l+DGNLW1au*0B90-IAh zS*07PPMNnv?U`+;%i~ZC8{`gM2sM8P9qC@mc|DN!Gl55Cf0Kx6dfL-cOt4uzCX&~% zif5%Dnv9i~k*4@yWVl8$kIvTRo90qBd)8!pN&8ab?ZL&=E##+d zg3%AGOXlQF`?{cqwXithexlO1nw_0Y8I#OqEv$d8O*q`w?3|t-Ql0?8dTr|YDP=$w zpB;@*X&|F?02W@^(qMsR_!ZCpaWAAg(F-Ua)S-OjHB;a}L8 z3B^=$Hi!Fss1T&pJ73WZfLyJ;2#!VAC`isK15L^ODcN8!cAxG1FvT5k>jQ`rE8rLQE^MgSo;U4Xx%8%~P+Rv^4>q+%D@~;i@eI z1%PIUZ}I7|PwRhQDdq44_N5qhpV-J)~sh)0712j&8Sy+RKBVPWn?4 zv&w<%YZp{jTB*ROyxueW-KjgZQmf*QE}^|9W9IengUd$JTf|$VAGr4bWwlG4Ayh(V zQCU+V2YvTVY@tA+IktBp5^CT7l7*f}xTvJEfSVZE>Vo$E-r1sc%(Ae0Wqa}46!705 zo)iC%hGFvZK9urOih|S{94paC43ZTqvHlTQ6?jQvHS(rD-G88^onkba4{lOZ@~xE& zsily)7B%C4e0p$&!MDwW<-&}&p)l?q9PP>uHXzPCpB!+DP9iaXy!@R-&}c^1R9a;( zE?a9Uz!|?IHSIkwyeUJ@3|Lb>{^`V07X*0j`j7eHf4W%WQ4{U*sFISvmvoE4KQR!n zZ0xPw+T{nkoKDaeSM+M+ie5d{XO*?lG(NZYt$#Mf#|TetJ$bOQl_q}3OE5ed3aWC( z)!#=B_cw9sV7Z6g--1bVBCggG={PUQ;4a1{F)IP!Ro_zrlT!)-@a(KngkfLCgpS>K3{D5r?>s+v5ojJ zqifBm4^{AQ2%IXM`T3``TwSzaovnvUX_;NbYF}AXSqnv-4qC9t<1ItyY}Y>+Q|ig= z+4ga_l4ylT6#QXL?E0+GW!k1-vh>kv!kP9=-5ZmdSjX=EveZS#>~Bl$xSp(Q@3x&= zqV=qT;N+3&Nr$loCh}Bea<2wmd}Mt8dw1R;;n4~J_CTIGO|%Yq%B}x@!%h&Su)E6$ zM&l0EE6lisgoJ(#4;V1QZ~yjFT=tT;Yn-_OPTWFPj^j*{ZC~+f(wTk7-`c3&@sNK% zGNx8(CL%2>eXn@TYctzWkcEtl587H@n}Q#dk(ZA!5#FEvQdFez2ZKrcr@%qejm4^M z$?38q=*=N4THGvOf>2f^VFo2D7r|OV3E{a@X$Asu$39Jiik|Xj$-Bg!z71 zsF~wy)&rA-e}+tUEklf71o)_0+uAbk4dU=8KZ1|Rcc&yaigezkrzigVg6iaIZx2a1 z+}t#ID8X}DOov3C0Zs&7jy#jq4dyC3Iqw+ToryG1hH|5y;x>1p#^k?I1c4ydcfSn` zpi45I4xP>1<9;ZVTN7LhzFRp$2(nA5L^gefVSle2X05i1ZscoGxLe-l0Pr z8JVL~NmLYORPl$4?Q!L2HRBQuG{UHOEdEG%BzDK9*UHIBnns6&ed%Lct@$QGnG|WjYjUq^!U+M2${2t2d;p7Iwiw*| ztdX$m=H03y|FTVH$3#hp1zdR8Lm@B50_EN+>Gw>Drv?bo!Z4RB0)Y?~7G}AiWjTo) zBoVB?T``(7oMNr`__28xET%15IxDp`D%nIh!a=lOq1_zz0gGH7)vEl}wM+0t7PxP3 zhqaqlna2Srogffl?#^y**!DvK_>Zdcn5&%m`*}g1h@?3?m+Q`uHv4}4rWtACyfthd zasAh0dXJQ6Y?6hgEy$rfR<8U}=Dm9)ppPF#?3yfKjk6=R-Ou`ZW@kUlu~l`3zLJ~x zSozV!(voiPf;zgpW(KG;jpAn9#RYMgN_$@v@?Bb5!b{sBM@mKGd`v{<(ys0UPn57N zS0RicZ3d3HAkCIN#22eHQ0}$&^=}7g7MfjSK4M`62MTO$BSKUy++`WrsVG8aPY0?@ zD5p2O)aZbhnysA9k+{ZgFb#7J3GrZf&)ihiz-LeHlvd8s-R3| z1iitVI6ml|+qa{1iu?8^8FC2(0&PK4spHd2`Q&NgX)S3uuvS)9SHDsE8qv_0Z?K8~ zlsSy?CY^(s)x1A@`Df3t0+MBD7(Tq=!^ z>FVoKUB&hdP0#knT=HBJ}E#*h% zR|Hv$o+f(v5Q(rIHB)RCTbaBKG^f?Qo?JclVfga(wCdl%Ndidv$|-F4_y(I(+?R8r zogbjM{1{%0@1NSsyc%t^Abpxa@0=2)pu7tA`_KPwLA05Nw$uVXk=oeI-vnul9PW>d zIZM+$&@Aq+2ay}UyhZyyF=(z|jz&bQa&7m0%Y1G3)W%BwB9B=Te{|op)`uw^gro6$ zL31;$fWW}5Mem0Wd|>cCA2JlkNO-vBIv0!H#{lJzl_GW*1my;pa0D!OoN0@O%t!PN3#Kmb(PELw1*Vfi} zL$zxUL+G-_F@q-Zqhbkj>Vi#n1Sy+@9EwfA{h{_(k z5IkV**puPzfHYft@>VfYog1et_J-Kc8y1=rc-U{R`=!P$jv-89kNuSbotBu^J-XRR`a9F1ESJmeBNRNernIQusIJv(QS%pwt5ne3gR z6o@T`F<3e{5YKatt|!uA1C=@b{9hDTwz7jG?GMc3QF1AX-v__{7$0XR7*Iraqm|N2 z%tRELCxX=>($W#x*|kC>fcnpfbo&`cSJ?i zZMk05-Qi*wb$3QsvI-i1S|hOr#-ST7Hin{KwUY~&alO4!-i8QH8YjzQ&8Lc+c zf*l)o1q1{#i_D6us#KPnCVm<9L{O|zgeLYR^-c2^n2AV)oJucBG&_&IRV&5@6Y&Yf z;FnuVR&$_TQ@(F@1olG2T3$ZaCiPSTaoBD2oWP)TZDeCha6C|Jv`Wa$ zt<-iNQWTzVei)6Tv*D&BMRC zq|SaQtqL{WLuw(0+BT_l~04$KxNGc6AnkSP;pQ4t;)9G&EiIja_R#_^(#Fv7$0Ev!kp?5wb^FWrg_P zpQHMH%lG#@|3|%E9nLwQao^YbdXMYm@crQ@7>SC4vH}bP0|vtYe_)5BFj*KJ6BGIi zzOcYwY&>jiEG%pSTwEMHLIOg<69gwt5D}A+5D}9SpEyBsiiDJ$f|8Pw@Z@Q#QxsHW z6qFRuK``LpJy_WI*x2|KL??(S{?A{B%`j3t3``76I0h*UlN19^igDNqI}3xsF@Ao* zj=u2laWQZRFtM=V;CVW5C*U2>{rvjEz{bSF!G+@;j=%`v;8_wl33v)+_Urjy|Kg$_ zEYOL&EWqgCnJzFG_?HFa?p@d+?8NuGcTew3GT`ns5n#fwFfbc17@A-w_F=eqSjKR; zC??8VnnQ-OJ&kBTmB9>~jf6qSOyt`gO6|87%2A|djZH9@yYjjWB&Ro!>ROqY1@<|Y zc|P4G(mthFSx+S#-!Mn8dyS3^ETUjdRAj&UIql~S&E5+R@66)&C29)F?Sy-m-fmrFjj`}75A z#U0`pyj^w}Jn#_4-||4(p0Hr(zTObg<@h{(A+|jGdrzzt^sksBg=A19CU2m;|q@V?(-Q-TUlUHCcE>k7!N!Q88=Kd@gvmHAV_*V?R zN)s3OQ!d<})?>Y&3!RfW5R+#OM#n&EN(jqjk3PEK0z7ZcUYu)B7S=2Vo-*QoNoCHn zw@GBdFntXheD%!tA`GJ$<5XH#(337KtVKju9-?hsD(4U;Fr8o=__^`&>jU+xHuPUx z)gHq2tu1#E?ICdG819;K7EXX(_bCpU`;0zj6^>9*kVL8@Z05s-n{0 z5%j%t)VuM_a-GwVRAceS^+OoF%pr_@=(cg-7kl#MVz(AuXj4h}TM+zD7v*5YWUw1@ zcugl%%y3{*?J(R2vfk|@2Y%eU_?uy-#btxv!)J9j8cAhuA=GGOPN}P*tT5q=3#n{* zS|l)0X{JLMwak(dp}5=#{o}@TlJ)l74~H__P1{z|61w{qU&{J% z?lfX7g*|Cfh8cW~y9<{3s{WQ)XGGX-5ek{~>uZz2sO?l>3nSq-^WKlL{%$~b=IpI+b3}vH?rA4U|84`l&A1d141Arr=m8v&nim7z^G_L#>Re*LqX;SlZY5E-z6<=Gjq!T(CYC3 z1z?bY*4?>XxivmIddt~qxxT9M5EgL=3knw(+^-$owB0!^5zRp&v3 zOMEV?+A*vsQ4cBh@!e8rzC_BHw%)w^RTLs^#lc*oKy8*iMJ$Z1y5Lz2j>(DE4c2(C z1sY;HZCRHO)CSxIDEFF@Axe##LN6W{_RQ@Y+*`khZ*3xu6YzjS>!Yv&@|8FBl$$ks zgo5-=I+Y?}bewNN$A);cz*AH4G+8(m0(6x}deZ z44=nrlCxEMavdMr+i2e>r%uztdFmgLCf*~yNE~k>P7S}infXyg0lA6GFx{7c{A3>0 zdQzUK#U?L9lTzVw-V(PZe#yx2S($hOV*!2F1vb%FO>aIK;j`Ll=Uys!$eJdPAJXii z?nRBMd`0gxL13K?+w1<CvsnKCQ)ZGB}`NLRl94D ztUvT$l%qFotTR|7%YHf-nc+8dHO2NjC|5E6a z6*#SyNur8-rPIKohUc4@C1U~YkOgYd9^N;PjBw^q<;BP$e2bi~jofm>l&1g)8U0|mE{Q4mqt~RertE&QOi!2o9(B~{F!a02`znU zM%Fhv-El$K6zpC`4-~CE;!Bdm``@Id1dtX&9(qL@UcYI$Ko-wcMMZ&+Z+3_5|!PQ8QI%Oh7#>n;oaizjrJ(G_ET9ua(s8Z2v-oc z{pewsq1IpP?n|vrTK9_7!eZ|E^>?|x>TX#LYFz2l4(+q)I~L(z)ZVOz`)7>z;=O;o zwUMIF+8E>oejL7iPS46{={XApISL{t%+GSzV#Zxh7) ztoBDKKfm5!gGKeZ2)Zf|%X(Fms&@90$8ub7l;#{++ zGl5-augrriUaXKX1!*5%H`?YDUuK;TX*mwwZq(HUb@*GVsNf0(7A@N}(bjj~Q8X#2 zmueeSKIAZ^q*g23Y+S}Vj{E^JZtAW}Rf&wLK@VSMSW1_Ylf$c%M6C(4@g~93TVUnuX#LAFYJR~59Ig~d7oXzcM6{x~h^X#KbW;?Gz#rnRFGqAO3g^ie6_UIzJ zDV!}p^*V9@RHO~eDK2@ z`>Qy08dCeZzgc<+?7tr)Y!nue<#`hpq&3WTx@z@m`)rK0%zZ_Eo6My4H?(fgITx!R z-=a8zMiqcYb4D_ApPJ>h@R}bMQr^b`~M6~TKSj}8@@ zs_BUqyR*rMJWMNv&YJI^KR$ui6+jSS)hojno+3PJfAuXA2eJPu+QMRu9sm&WfRh4^$3@mkm*J=oraIo z=Kt2&;nF39X`ht9ex4}CWisN(XYJ0<8;bAFUmu&lXnY-_j$&KNtk^Vs&>*vJ+?`Rq zFE~4}%(vD5!Z=Uz!#>`S+_k)saib8>eldNc%pb9f#dy(K@rJyUa}`^xde@xHa|)p; z=uRa75eZ>k=-NyEq7H_>+x%g4K}ua>pu25|HAVBfbh;W6%T?=Y$k}HL#NKe`mV3AC z5FmMsZ9ZE(DF~bS5dYnct;zwZy!Br&82TbhAoiNUY-h??36gyj;z{T3M$d3@k3(4Y zv5u;yko#6h>D|{EaFJf*Uu-FxEzE90_Zx>MgxMidzHPqXA*IWOG~iB45j>c_VViUE zvG9T=-o4}*tS{|Sovp2PXX6yuplTWD;KQ@~To(f|I zoR^kL>G8sbgR87N>P?$GO0&XPPde>Zr5eA^=yr2=0yk3)CI;$=1_yDq6T@MIcgZ_cvl=!*%6# z>7qWOEmQ7u4ZC3zRIgmZ=ae>xP74)zJ{MXtRil#PyQYd@?nXmU+i7I5EN=r8`oxCm zep@nEK_s_TB*2w?l>>i6QewHmoEmtqnDKS}JYP-E$N@C)pcfngkCJq@+wK$_UqKb+ zDTBA-vv~Q^h!{# zjb)X~Z@;tg`o(n?)%{R&HEX4%fQrh{;BA|BGD_iLQZwl89Z^lJD=`3av^M3bM=F@mdIJbt*}Jv?UJBIl_rUjQhAM22Gr zyKHppGf)baiCda)%1!EeFPY&J;ldRu%w|L$B4+Bs*2VZ^JD3@6Yk*5v>XMw)C?FjA zEp3T#d=*kZFh5eL)cC@ z`W$8Sps7z#mZgb|jgMOX++-)<$8CstucDcEhcv{aM+aF~P54pI1Z$6VNY0R%?3|zm zorS}NP9k-r*^}E`6h-^$AKqTa^1SaTJOVn2@g^bDw%qk8uE9E?w#X@Jj&|+$W;hhy zJ5EO z)FssO1~au>nB$aq0$!$@R?Mj=GCW*ta~Q2Pg7ac>mdMXw>!tiVz_dd!e;m z*mg7?5d3ZhjZs?C_~=W6@NSl_;IE)vky8y`^#Qse9dr=>8PGvKnASVfCftbGqS${$ zYMzbmAj5eGCXr+&E;XZfB};(z4`KZezMZnFVm4OxD;OQ+Ue#PLi}n0L<6&oc5r@=9 zbcv0R${(1hL;}0b<7hN$9JTM7?cG`0cvQwuD9}33uL%zeA{Fn9V81B5`)^QDn`KQA zi})`tkcG+sl25oeVT|!nGe8=2hO6erI6y*^7`k&f%V@cx_t%S^NJW6^pN-L&K`KS+`uiaTN|OhWd-%y!Gx_jp6_Jc(OG;( z`a#NfSp?~b?)SGujdK+xzWT3huf*F+NRFt39PGl&POFX4MH*lcnXh(73$@9A(yTlZ z=C6){VHmQfm7L)uuX?b8!eq)-n%r31;(eEbllGFjQ#Ex|ITNL3RJna#9HYL=9KHnK zBz`Qu%v20sV6k&#P@s64T|54EWAOuaAT7CGhqs^4U8!($(g*XW=kqNOXy)YQ9&tH6 z$`R0EpbKtvV)Sp$p{4hwl=f`8SjS_1^1XyZZTO_6Xq{*SQ3`P+?Q~Rl!h@t#!nn)l zu+}j>L+cwI>e|!hKUPYYZ{WQlw#Spz96Bd4p11t4Ygr~gYoO=>Gh|(9LzKE2D*s_h z!qI;9Nj~VAj=)i&du9L+79C`gJos@jJ_C~!R`l6itw5FH0~9z^Ip~4FLBY#x4mlki zCCLsXT#hyU9V8^SA;AoZ?emKn`m(Btu_q?B)TiBEi2yW6{X|19Xb((4N&jjOjj4v* zq;-|i=8xx|yJ}ynR|em`I_nREh-7{&Stf3o27^WpamZSZvicH{C3m;3HwBn1*)+QWUg;QnFR(^aWhTodzth2yBp6z6AGVw zwm}Xw6L`atAL5vkMdQa2Ik0Y#%HPN>E4*x9DB0%o?IJ!J6Li`E5GG=dB{lcOvjpN2 zfc66^!oUo*7Y{iISEe&tXSmbcld{}udQzmVYghYRTdj)9BDOurAD2C=DMGwC&FZ zJ!V2(O8pSFk8x6D3?p2zKZj%0ysV^hcyQ47L?~l66trQamw5|94wo_Y;$dicnvtY=Z7!!XT**3G)920ZUw%&)#9;0thF<^ z&SeLG$)mLF$Y$=OVB1>FW6Hg3IcIDpMmDJ~#%+92_)96sek011m%gzMzA)sPIw$Cw zW}e#ANv4jp1j-fi>eOo&kfc_r1vO!;RSrhpILA7HOpupZGV+saR5Lrs4cPN040yJg zD{9;ixz%3D?!thh0)k}^{&i8D>Bi=ex zjx0F|ufBNkVnpcKlKq#>8>tjhzBr~~KyyZ3GBogqG$(}!5zw3y*&D0JbA~eD{CmWM z0{mM-J0n0_bi06Lw1CzM^a!w4M@{mjSG0|a))}}=OK4vND>GuYCdzG{>6KL`4o;XN zg*KhAk6rg{+vy4I)M;uSi?Y|r3pCvPFFuy2`y2%`tY7p2v|8kQ42(Ps%XC!(ok5qe z1^W7VVVUl(SGr$REkav9yR}rc4S5Y!2j}!Bv{yAsU-lZ< z6)*2rr`qI7LESJZ4(f(aITs6WQQooYmF{x)0z--sur?Y3KB<909r#%6Gr`i|rEpo~=7ti-wA#DA9*+b1G@ ztutaR+qh35R30Wxra~41O|gyzI*V3eN?CmE8aR&M7=$=g!p|b2dUOPhpb*XELcp;A zOdZO!ggeD>Nx}ZX34<7X!2Vqn+^r*V1ridYuagcJNXQEQvc@7+hK*ASXO!iL1*q;h zU@C!7ZAxFO9kWfc1skK5{zZ2=-H^`7P?RxOtO>B^_WoB;nw3;hxTj~tuR2wZp4r{q zWE&)ueJ;4#x0-#+;&C2fPIvt732oLY@WP`wxp{iR&}L?o@`fBpamxT}*Mg@ijDecz zVG2;BZl|sz^k*5;7y2U}>>xMt0P!I80`Ehy4sE{R)|0>>RO@OM{T=PCP%H)Z=on@v zO##oP8U^w=O;G<4P#y>BALMc0MOOOrH8M7iVc?eqB5c_5()7=?g#?M31%IeE5F`|D zmuCA1V}PFfeySVjx#M2{eKG5_n6h<{QP6e7c^%(lVmtL8*=V~SBDlh^RVyit9c$P> ziX}c*Mr(L$q`oHXK)i0o_B=YTIGz>ecK>+g2=%#Wu9~H9G}talNoQI?8?>fUBm!-a z1}E4m2~)0}`CKlY82Eu?G%C1UN2ngV6UvxverC+p$Mf{uuC(RU<9?};5FPdl%t65x z%dePjJgI;WnD~d}r>TL7&-GO%;?_`I_4@#{Hq)59AAZ$^bY-c0PIm4x&9A0;gi=XQ zS%JSm$Iu0poAw58MXLIbTywh~mG0N~@*yDpt6r#RND4}1XWef2g#0Noeo5|}`ukGn z^D}J${30F-EGEtR#(r~5d{O|efe2772omb~KuX;S;<~x#&ftpBI>XrsN~vQUfx`jw zig+AOx_{((pKP|PntukkuUr6^ZxErmTxc;J;&NtRpm4g;dcS13QDOOfC{IJSNc-*X zmtKzoE6ULQ@7#4-X2eVY!P?8$MNOaj1Np%qp;x`eqBOCaVicrX)aZ0erc)GhZB$mk z@B-Jim_KwWQI*9)9zTNLMZhK*qwtEJ9g&~g)zPHhnXCK?_r|#2(mQ^@1vI{h{A6a^ z>UxE!H9s${+yG?cj$QlJwIn+`f*>JM~z1rnx$ zQ1_ZJFi)|18l2e=<|)o_24yf$LCX~jA?{Ngl~sutsh-c9GL8~%fyr#m#oYyqdhbVp zO=L90I1%Swb~>LzcB3aN!Qilr(d1WUGlxrEpiZX@G#YBxU;Nx3epo62T!^2M<`kD zIgQt~9m39xy9u%#6Az0X`4ZRO>*h|2315q_#BmxK;+8o+{_>`ra!+QDkjdP!wo)XI zj&ob|%$Kk|W;hi5AA=AlnlHGE0}63;HFNAAbLoXU%b@R>daI3g!Z3B3>R1{=dH>So zLarxhCxp`6-$9RM{+T<2P`!Y+;2$bg1U;v#0;*m_q@a74&#`g6w8k%RwA6W$P4&H= z+j}1zG(Ml2r2bqT^r*;}+KsW){Yy!UgXG8~t7?U>Bl1DO2DHhiY;xB$g14Ja3V%-B zQU14Rq2KDm)?lo~!`0%R^{_uu@|>WkVK$Mf)!)b+=PQ@nItM0VvbGLsd!t?>J(W4B zfHNn44wt}8A>>uuBWR}JVNS;nW(p{#G%$&Q>I@Vl7(5*fHYD+HXj2!7ZV<*kph{We zhJ-FRV$rKyy~Y&GMWEz;=l^$>Wc;7OE&4P^rgvbO-?Kk4+JuS?=`}-hG6)EE03VhY z1z|&JJ~+xPVd`F|p;D&^Q_T(i+q9!o`V#ci6%1C@+#{x-!D6O2O8P;~S{F|~aK$k7?tj~-yGhM`tvrA zMzH@F^@AY?n2a--O-4-tLUYMWL(c^z#RU&CN`pATljt1Bb_z@qK#mhSEe8_C$p8{Z zoujDQ=P^gm9RD#XCwPn}0fD4HI})>hPp4)SS)1EL^ub16e^*WZrS5bHa9Qhpf^?$5 zWmWK({*0i{a(Gne=oz&`Y43#q(5-pZQ0Q(Ark*kU5l1j3xN*sb<3j&ybC3+>cJd#y z-IPF1vf*m=2aBGBh8z`T)kP?BF=6XFM))ONLpr|bl{tj1_<;|QNRq%XFtIUk;J9!s z7#8%wK1?_{3 zxfJ;DNVH%I_Nbdbwr08>-cEA6f5i_$TUwsC3cnve5R=W1O z7DM4Tls`SWs5$GXTRm1}v^GO}Q;(4XFNdAst@Az2GPjE${;B;^FXF4{j|M6gaJAObxyr^<2Gs=yH#l0p;^=?mp zrjsUk)!;_|TwL__dXW~xv zQfpor6aOP2dsDV#LM<&*{1v@BLC}vDld}2AxYR>6eMVfj{V&TG^qsySH z4l_e)%}fum>Q%L)lvyryW)^-+bJ*hq=uT^u%_&;b2~!Hf{4>(o0;nNH1P~Q74%8B`iqt#nsee1vbuJB%;yb z_Oi`QpZv3i29ufA{BICSH{I@S+yCGTiR%_p<{6ndF;+5OFyP`^{(iS>bye!DjR6e~ zXRi+G!Oe5aHqLLS|I6zp(fctQ*Ff)g)>^YLW;z2ETUXNq z!Cf*dXBtlkGWi3h`PO$sVI@0 zwiEYXi$@)kSVa0oR!=_g{n6<*Lt3I6$L8dtydGOw7nChUq~OW5>t@gZ_GR+I<#=wsZEAq zM%hj5<7?I?iyIryitDC*H!p45X{5F+a*u`(Wc5UoXnZo4#FkKm)~-F;r1m-+!2@xn zqo1C&QzkF_eHImuae8IXk4i{lk6?6daEyR^=0%_$*_gE01T{+p}GF9B*-aFaMH1*HMv?N~1w6DXBPY;OD*5$De#H zo<*WY=GOB&N#DdT@BRG~r6Eu)UnTF=?)A2t939ey$Fu5%HO+x8*APpi0|k#~$q>CC z%|Flg$8$85#KMw_ebCvuyR1|6qE=S0SKe)_WxrmuT%DFa`q3=*%FwPQIY)whjOp`+ z)3y3basRmBpV!~`or(gWIC#RB`FXmiISbwOhAf5|B{^0zSRzIc8NgPb(sxQS0P5LR zOU#7$#EOq!SWef#eGZYrH-@5e~QBwe3XW z(&~Zj57y8Z1lw;A?q~0lG`y8xxYm@5@=l~(&GCGi|CW#?Abfa`g)Rgyuoy=6Ns@X~ zued&8-dwAG1kV?F)P8lC(_i=8RuK%vqI1%Mpsk_L3!wc!9p>o1hSB%cCv2J*&gPFx zn`sPM6ow=YslTe;H_`Cz0SUvm(4{)xQUZO199uS>1&`f@Hv@C+kJ|KQ9d%^{r)5Gn zw|q1v{>MtESH`6+lhK{m3uHBeXOID)Eo@B4+e~@$S7sgnT`PF z8Ggmz^JAtl1Q|&-SAV45xATCVmThEFea!`;W0?5#Opih52Q3%fUwzN(zMidpueWS- z>F=)j7xq9|{o4wCQP^9$ztaCV7H^Fks!}DZJyk*dC|Ro?snW~dx+tN!muS>`2vZfJ z_6E@eC^WoKMr!Grl)&ZfAtU zITGx2WNYJ2*BUH_)fqfOfwN4md>C6vZZAoXjq2!Eb-xh|p|?=)Cwhm!0w^Q*E@$0( ze!XDmiR=3NT>{YKY4i&pg#5sL-S9AVr_^)SX-|Re2)MT);DS~Fz=>`JU%O1{xzJ=o z1@)Z)NqITYcf?$&M}&^WyPr_{hcPpokf@my)&UN7b{R|P&jV|(NCi)vPg+Up4W4DlRAiIn@2 ztP%>b(x9DjgTlL;0Y6E^1{DgZP$VWO6u?D@UBHmt?oSF#ma+bRt7806$9sinpcbG5 z7LfML*+{YyveaHT$OPSyg}j=&JGdP!g=*1KNXTb{&WRW5^Oy8t_%8JHM}+&Ypm2vk z@gV5G$(C^l9(B{kpy%7}I#W?1-+!P~8Dd^9)IpNJ;LN%Gfby27f1K3Ek;^>;hcLLP zihtl@MEU_)dHTw}u44x|j$N!Q%CmkXoQ_!$uOK(Y{@kWYQO`8T75$XTdrGq$s{1|t z87cwJ7D6`hC&sb?r~#wp+DGpU79v8%C2qVb1B+Z}yRU zH=mgy4J@sYoO+S%xypJP3#HLt>Fk6SM8|vxz(V19VC>ileXgAKS%MhJgG#~oyr-}{ z;#t8y4H9{IrD746L2=p3+tKp&XKv@IveEh~#*IX$*85uXO2OzhlwQBemHWF^M|xI0 zdW0OmgoQ+P3p!pco{H-5f4NiE;b zZ$OJYS&5YcKVPCZY=zyf_x?O*m;QZrbBwq$u^#sW)^o+meIC4j4w6-*guf#?9p{GZvQ=yMF28O5M%(C z4IzGV=RdA{Y$?8szI<`S@8gTPo4bYu1JBhiXf8-v&lpX#xmOBLRMi&^XHMJQlj)3^ zB6|W;y$kB>?{e>0Nlps0y#4LXignrO^Xv*wNtiD&YJagofWTv*ihaFPw|;)NJFrCJ%UH$ZG6vQUaOJ5m*0cJ^0lEk7~JG5Th`P? zKY%no{qxD$#@Mf1VvV5>+_pZ3-8XP*QwP)%JnycR-wKhDX&yui6R*CXqMK-wt+{nw z;Sz8GdBAVTxz`lvPU%+F=NOcZhTH>E4~x8-O4DDKpma2j67m;7A_i6yLW=quphEzG z#X6ux|3!4$((1ld5HAoN$vaX+c{)@4XkB;&h)3pVKvd31#w=Gyq39M#(e$QUbVJy_jF32h^zgECx7T?77EvL$0 zOo6)CM}<|2P@T9Oed->>9UEINl$8RCQXn zLH8zK29N_{*F7mE4Eq3u0-XTr1?ehwxupdYRXFDcG!L*v|Dzt9EHZ;|KnW2Ir(R3z zLBO1e{F{9P3Cq9e0TNyo7Im9CMO#(9o;{-|SKtr?QDsL?qEI0=ATly~b7*4x&V`D^ zCaKUIf=A`_2LYild{P#>d|_oFtk#wU-EtN8xScMS>bqQevDA5SEy;ou_1iP}gt?5| z4)H7L7HXLSOk+w3BtGU&A6}oSqK;I<@*9IJhow_!MAgj5+yIoh2 zAhZu;B=XL?b0*7IQIgF<`#|r3Z#hN);`ktkhTOY43CX%2ks5CgW`_kD2i_>eqs*uL zWWMn*%^h&2*Id0b4jC;8dKu#%^V1`Z&7r3IvWR%vLl}PiIi>jnky%=Wm@FZkL)cX{ z92ye@sjlnAX%gBIzgHw()K@tAbj$X^a zv+0OwYooG?PF(IEj0!ou0n|?yI5`^^oe8=HqTr@m#5>O)d^z)0R(yXWsdh+oOZS`Q zPX#bO^tsRV*-J=H;$McbHd%HpO-q9CCG{qx?r@PmaaL4bfr!by`e_J(V)ro66KnpD zChfanA{Yw1x-OJB0NEq9&U5m~pDJ~z2rT#p)JYi@1b{*XoVz(dESCT{ml-qV{=N?q z1w_=VyaGcjGHzV*vO<)1nnG>Ync~Hcz{I1=ITF}ZO~CYjLF?;2 zAbkImzDfOU^dbdwA{*B_0ATcfYdq=^DTkJBOWOHlcR$KIW6L%FqB|!uK=*kczC8pe z^KTcnwzmWHLK7C?&^cT$M(KVu(AuIu-U^WJXGD9~zs`|JXxK+n>i=01W}iVG zr6@<>wy{meMso6qPWXalkxYfsBWxs)NIFQ>+x9sza$KPV8Dj1APcNz+*Q)f9@dLL; z{+F1cABq{a%GR=xL%i!!rQfesmDQWcjCv^S@GNyl4tqusw&{caR5|5LkTjh^z zX+R%Ht(Dm`;4>VSUznlvA{TsnEWHS4$EBxd{#?{px9@GucSuuBjIMY2M^rLXeQaKYy$kR|hq3IuZRO7x-jYE?3+5MwjMUAz| z+UsAFkxr-xha_((Mcfo3xUJ&3){Dxuo*Vmu0C~%hS5q#?26B(esp!l*V^B_iCCP$B ziHq5is0Zw4!LS+xuZ2vffCIpak${NF z2qZd@oJEmOA_a>c49K*9?gPDt5%jP5*6eMy*NR{7$Zu`)N3C4hTaN(I6BHf?gXk%) zIxO4t!<{^VMbJG!iVkE0=^r7t>>^0g7ZA6XqCmO?ZnW%6qwdL^+UqQc2jX%v68<2& zTBcem9SsFdCMvpT&YT-AA-8}iH1uxYTf|=J-x$A88pAhaTt$fm90iD>nvHNgL;C)c zK>q-ri_8VaOBgadP#1>k8OWiddS2ZZEa4I0*`-hRzP8Puwj2iq6+h+CAS&xf9(BA| zOdi^?6Z=3-=<87>ayd-xh^)S^d>Fl<0m&~2et>}fa)L%*(vF-UDZtyWoSEqJ^Xr8Q z@d4q#RU}Bd69kK)*A@fUND30my>SEOzy15K(E~b1-7(YYo0%RcLi<|Qd)*)frL!4A zLOpvEY}>wI3KrdU{~I7K!`h)zJeCdoF_!56L&;M+Q=JE)k8p!lp0#AlI2aLRd940xO8)2c;q%_wa_-fq4KiT0YSH z;4?Y@h~dHwAgk0kn+&Xy{$5Pwk7?zX9UYzMNy;Ch2pW+5E(Y|2Xb@+iprjwas~tlU zo8E85?$4g4)vQ`MrSLnT0;4d;UUd*IgE5xMK=zs)5*lN%(D|Q4fm}@QD9Sb?|D^q^ zT>1W1=HzAnOaumOPdjyCLE{kSDVwtf22gBWH=2GQ1Xbc?Cs98o2Qc8kx%|)b9Q#d> z2wwviTJy`-K-u)o-`Vu{3^3C~kisy)e}~7$!i4|)Pxa7mI>Evw#bG2P=abeZpBmvzi;Fz^^9|;={p08WvC3Y?8h*Mmb)Au)n#!f~?Z7 zm^h8Nwu#)$eeMx4t02Rv=Km$2x?*~9XIs%GUoWBOQuaOZk;mUfItJ>m6ii5*owGdg zUWZ1T9tJ1)p#K@!zXnertNBD2*YO}?A*|@jJy^$%qAs$3n53oR(HiID*A<@%g>Lsn zNQ<4-tFkqrW%lFY{3ux-7U-9&cH%OVl<_;4Q~5R<#EvS*7~D|DNuH%==|zgTdiZ2veKD@y07V|$L+%OoSyy2p^|K;kOJ?HXLNf&l|! zXF9be{VTevm)=RB+Fi#^MzooQH-G1%=X~%b(95*qLnG|Pov}k0SWs55pjgnKU+W2e z{|#7BQZONw<|kp2xl3`$9KDv{*U3o1_B`L^i{NL8Rj+(SNq;wC+0n6^h`M1pMLiUxm6zVxu^+(Dx0;X-q zTq>8_S*A7W8(3U)c~eXqzGG$a`R-OiC#P=WSEfxkG&=-_PhOeqmGvKK*CVHjxOBZ@ pEwzL`>i*8R__Kv1*C}gmHZq>QI%40h(qzO Date: Mon, 22 Dec 2025 17:30:25 +0800 Subject: [PATCH 09/48] =?UTF-8?q?1.=20=E4=B8=B4=E6=97=B6=E6=8E=92=E9=99=A4?= =?UTF-8?q?=E7=89=A9=E6=B5=81=E6=A8=A1=E5=9D=97=E7=9A=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BusinessDataPermissionEntityScanner.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java index 93c306f5..b8cd3de9 100644 --- a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java +++ b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java @@ -28,6 +28,13 @@ import java.util.*; @Slf4j public class BusinessDataPermissionEntityScanner { + /** + * 临时排除的包前缀(物流模块 DO,不参与数据权限扫描) + */ + private static final Set EXCLUDED_PACKAGE_PREFIXES = Collections.unmodifiableSet( + new LinkedHashSet<>(Collections.singletonList("com.zt.plat.module.backendlogistics.dal.dataobject")) + ); + private final Set basePackages; private final ClassLoader classLoader; @@ -70,6 +77,9 @@ public class BusinessDataPermissionEntityScanner { if (!StringUtils.hasText(className)) { continue; } + if (isExcludedPackage(className)) { + continue; + } try { Class clazz = ClassUtils.forName(className, classLoader); if (clazz == BusinessBaseDO.class || !BusinessBaseDO.class.isAssignableFrom(clazz)) { @@ -92,6 +102,15 @@ public class BusinessDataPermissionEntityScanner { return new ArrayList<>(metadataMap.values()); } + private boolean isExcludedPackage(String className) { + for (String prefix : EXCLUDED_PACKAGE_PREFIXES) { + if (className.startsWith(prefix)) { + return true; + } + } + return false; + } + private EntityMetadata buildMetadata(Class entityClass) { String tableName = resolveTableName(entityClass); if (!StringUtils.hasText(tableName)) { From 5a2ff28c6f56982017f54fa061ed06044c47667f Mon Sep 17 00:00:00 2001 From: chenbowen Date: Mon, 22 Dec 2025 19:32:04 +0800 Subject: [PATCH 10/48] =?UTF-8?q?1.=20=E6=96=B0=E5=A2=9E=20dept=20?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=9A=84=E5=85=A8=E5=B1=80=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/dept/DeptDataPermissionRule.java | 22 ++++- .../rule/dept/DeptDataPermissionRuleTest.java | 96 ++++++++++++++++++- .../core/context/DeptContextHolder.java | 61 ++++++++++++ .../web/CompanyVisitContextInterceptor.java | 11 +++ .../CompanyVisitContextInterceptorTest.java | 88 +++++++++++++++++ 5 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/DeptContextHolder.java create mode 100644 zt-framework/zt-spring-boot-starter-biz-tenant/src/test/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptorTest.java diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java index 7ff3fe02..e54a7f54 100644 --- a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java @@ -3,6 +3,7 @@ package com.zt.plat.framework.datapermission.core.rule.dept; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.zt.plat.framework.common.biz.system.permission.PermissionCommonApi; import com.zt.plat.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO; import com.zt.plat.framework.common.enums.UserTypeEnum; @@ -14,7 +15,7 @@ import com.zt.plat.framework.mybatis.core.util.MyBatisUtils; import com.zt.plat.framework.security.core.LoginUser; import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils; import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; -import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.zt.plat.framework.tenant.core.context.DeptContextHolder; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.Alias; @@ -108,6 +109,11 @@ public class DeptDataPermissionRule implements DataPermissionRule { return null; } + // 显式忽略部门数据权限时直接放行 + if (DeptContextHolder.shouldIgnore()) { + return null; + } + // 获得数据权限 DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); // 从上下文中拿不到,则调用逻辑进行获取 @@ -136,6 +142,20 @@ public class DeptDataPermissionRule implements DataPermissionRule { } } + // 若存在部门上下文,优先使用上下文中的单一部门,必要时校验公司一致性 + Long ctxDeptId = DeptContextHolder.getDeptId(); + if (ctxDeptId != null && ctxDeptId > 0L) { + Long currentCompanyId = CompanyContextHolder.getCompanyId(); + Long ctxCompanyId = DeptContextHolder.getCompanyId(); + Long compareCompanyId = ctxCompanyId != null ? ctxCompanyId : currentCompanyId; + if (currentCompanyId != null && currentCompanyId > 0L + && compareCompanyId != null && !currentCompanyId.equals(compareCompanyId)) { + log.warn("[getExpression][LoginUser({}) Table({}/{}) DeptContextHolder company mismatch: currentCompanyId={}, ctxCompanyId={}, ctxDeptId={}, source=DeptContextHolder]", + JsonUtils.toJsonString(loginUser), tableName, tableAlias == null ? null : tableAlias.getName(), + currentCompanyId, compareCompanyId, ctxDeptId); + } + } + // 情况一,如果是 ALL 可查看全部,则无需拼接条件 if (deptDataPermission.getAll()) { return null; diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java index 2177695b..77f194ce 100644 --- a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java @@ -7,10 +7,13 @@ import com.zt.plat.framework.common.enums.UserTypeEnum; import com.zt.plat.framework.common.util.collection.SetUtils; import com.zt.plat.framework.security.core.LoginUser; import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils; +import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; +import com.zt.plat.framework.tenant.core.context.DeptContextHolder; import com.zt.plat.framework.test.core.ut.BaseMockitoUnitTest; import com.zt.plat.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -27,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; /** @@ -48,7 +52,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { // 清空 rule rule.getTableNames().clear(); ((Map) ReflectUtil.getFieldValue(rule, "deptColumns")).clear(); - ((Map) ReflectUtil.getFieldValue(rule, "deptColumns")).clear(); + ((Map) ReflectUtil.getFieldValue(rule, "userColumns")).clear(); + } + + @AfterEach + void tearDown() { + DeptContextHolder.clear(); + CompanyContextHolder.clear(); } @Test // 无 LoginUser @@ -236,4 +246,88 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { } } + @Test // 忽略部门数据权限,直接放行 + void testGetExpression_ignoreDeptContext() { + try (MockedStatic secMock = mockStatic(SecurityFrameworkUtils.class); + MockedStatic deptCtxMock = mockStatic(DeptContextHolder.class)) { + String tableName = "t_order"; + Alias alias = new Alias("o"); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + secMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + deptCtxMock.when(DeptContextHolder::shouldIgnore).thenReturn(true); + + Expression expression = rule.getExpression(tableName, alias); + + assertNull(expression); + verifyNoInteractions(permissionApi); + } + } + + @Test // 上下文部门存在且公司一致时,清空原集合并覆盖为单一 deptId + void testGetExpression_deptContextOverride_companyMatch() { + try (MockedStatic secMock = mockStatic(SecurityFrameworkUtils.class); + MockedStatic deptCtxMock = mockStatic(DeptContextHolder.class); + MockedStatic companyCtxMock = mockStatic(CompanyContextHolder.class)) { + + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + secMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)) + .setCompanyId(1L); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(success(deptDataPermission)); + + deptCtxMock.when(DeptContextHolder::shouldIgnore).thenReturn(false); + deptCtxMock.when(DeptContextHolder::getDeptId).thenReturn(99L); + deptCtxMock.when(DeptContextHolder::getCompanyId).thenReturn(1L); + companyCtxMock.when(CompanyContextHolder::getCompanyId).thenReturn(1L); + companyCtxMock.when(CompanyContextHolder::isIgnore).thenReturn(false); + + rule.addDeptColumn(tableName, "dept_id"); + + Expression expression = rule.getExpression(tableName, tableAlias); + + assertEquals("u.dept_id IN (99)", expression.toString()); + assertEquals(CollUtil.newLinkedHashSet(99L), deptDataPermission.getDeptIds()); + assertEquals(1L, deptDataPermission.getCompanyId()); + } + } + + @Test // 上下文部门存在但公司不一致时,记录告警并保持原逻辑(不覆盖) + void testGetExpression_deptContextOverride_companyMismatch() { + try (MockedStatic secMock = mockStatic(SecurityFrameworkUtils.class); + MockedStatic deptCtxMock = mockStatic(DeptContextHolder.class); + MockedStatic companyCtxMock = mockStatic(CompanyContextHolder.class)) { + + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + secMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setDeptIds(CollUtil.newLinkedHashSet(10L)) + .setCompanyId(1L); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(success(deptDataPermission)); + + deptCtxMock.when(DeptContextHolder::shouldIgnore).thenReturn(false); + deptCtxMock.when(DeptContextHolder::getDeptId).thenReturn(99L); + deptCtxMock.when(DeptContextHolder::getCompanyId).thenReturn(2L); + companyCtxMock.when(CompanyContextHolder::getCompanyId).thenReturn(1L); + companyCtxMock.when(CompanyContextHolder::isIgnore).thenReturn(false); + + rule.addDeptColumn(tableName, "dept_id"); + + Expression expression = rule.getExpression(tableName, tableAlias); + + assertEquals("u.dept_id IN (10)", expression.toString()); + assertEquals(CollUtil.newLinkedHashSet(10L), deptDataPermission.getDeptIds()); + assertEquals(1L, deptDataPermission.getCompanyId()); + } + } + } diff --git a/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/DeptContextHolder.java b/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/DeptContextHolder.java new file mode 100644 index 00000000..e463ae50 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/DeptContextHolder.java @@ -0,0 +1,61 @@ +package com.zt.plat.framework.tenant.core.context; + +import com.alibaba.ttl.TransmittableThreadLocal; + +/** + * 部门上下文 Holder,使用 {@link TransmittableThreadLocal} 支持在线程池/异步场景下的上下文传递。 + * + * 包含当前部门编号、所属公司编号以及是否忽略部门数据权限的标识。 + */ +public class DeptContextHolder { + + /** 当前部门编号 */ + private static final ThreadLocal DEPT_ID = new TransmittableThreadLocal<>(); + /** 当前部门所属公司编号(用于一致性校验) */ + private static final ThreadLocal COMPANY_ID = new TransmittableThreadLocal<>(); + /** 是否忽略部门数据权限 */ + private static final ThreadLocal IGNORE = new TransmittableThreadLocal<>(); + + public static Long getDeptId() { + return DEPT_ID.get(); + } + + public static Long getCompanyId() { + return COMPANY_ID.get(); + } + + /** + * 设置部门与所属公司编号。 + */ + public static void setContext(Long deptId, Long companyId) { + DEPT_ID.set(deptId); + COMPANY_ID.set(companyId); + } + + public static void setDeptId(Long deptId) { + DEPT_ID.set(deptId); + } + + public static void setCompanyId(Long companyId) { + COMPANY_ID.set(companyId); + } + + public static boolean hasDeptId() { + Long deptId = DEPT_ID.get(); + return deptId != null && deptId > 0L; + } + + public static void setIgnore(Boolean ignore) { + IGNORE.set(ignore); + } + + public static boolean shouldIgnore() { + return Boolean.TRUE.equals(IGNORE.get()); + } + + public static void clear() { + DEPT_ID.remove(); + COMPANY_ID.remove(); + IGNORE.remove(); + } +} diff --git a/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptor.java b/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptor.java index 538f6d4f..f4688a21 100644 --- a/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptor.java +++ b/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptor.java @@ -3,6 +3,7 @@ package com.zt.plat.framework.tenant.core.web; import com.zt.plat.framework.security.core.LoginUser; import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils; import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; +import com.zt.plat.framework.tenant.core.context.DeptContextHolder; import com.zt.plat.framework.web.core.util.WebFrameworkUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -66,11 +67,19 @@ public class CompanyVisitContextInterceptor implements HandlerInterceptor { if (companyId == null || companyId <= 0L) { CompanyContextHolder.setIgnore(true); + DeptContextHolder.clear(); return true; } CompanyContextHolder.setIgnore(false); CompanyContextHolder.setCompanyId(companyId); + // 默认不忽略部门数据权限;如果有有效部门则写入上下文 + DeptContextHolder.setIgnore(false); + if (deptId != null && deptId > 0L) { + DeptContextHolder.setContext(deptId, companyId); + } else { + DeptContextHolder.clear(); + } if (loginUser == null) { return true; } @@ -91,7 +100,9 @@ public class CompanyVisitContextInterceptor implements HandlerInterceptor { LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); if (loginUser != null) { loginUser.setVisitCompanyId(0L); + loginUser.setVisitDeptId(0L); } + DeptContextHolder.clear(); } private Long resolveLong(Object value) { diff --git a/zt-framework/zt-spring-boot-starter-biz-tenant/src/test/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptorTest.java b/zt-framework/zt-spring-boot-starter-biz-tenant/src/test/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptorTest.java new file mode 100644 index 00000000..6fbe99ff --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-biz-tenant/src/test/java/com/zt/plat/framework/tenant/core/web/CompanyVisitContextInterceptorTest.java @@ -0,0 +1,88 @@ +package com.zt.plat.framework.tenant.core.web; + +import com.zt.plat.framework.security.core.LoginUser; +import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; +import com.zt.plat.framework.tenant.core.context.DeptContextHolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * CompanyVisitContextInterceptor 单测,覆盖公司/部门上下文写入及清理。 + */ +class CompanyVisitContextInterceptorTest { + + private final HandlerInterceptor interceptor = new CompanyVisitContextInterceptor(); + + @AfterEach + void tearDown() { + CompanyContextHolder.clear(); + DeptContextHolder.clear(); + SecurityContextHolder.clearContext(); + } + + @Test // 无公司 id:应 ignore,公司/部门上下文清空 + void testPreHandle_noCompanyId_ignore() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + boolean result = interceptor.preHandle(request, response, new Object()); + + assertTrue(result); + assertTrue(CompanyContextHolder.isIgnore()); + assertNull(CompanyContextHolder.getCompanyId()); + assertNull(DeptContextHolder.getDeptId()); + } + + @Test // 有公司无部门:写入公司,部门清空 + void testPreHandle_companyOnly() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + LoginUser loginUser = new LoginUser(); + SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(loginUser, null)); + request.addHeader("visit-company-id", "11"); + + boolean result = interceptor.preHandle(request, response, new Object()); + + assertTrue(result); + assertFalse(CompanyContextHolder.isIgnore()); + assertEquals(11L, CompanyContextHolder.getCompanyId()); + assertFalse(DeptContextHolder.shouldIgnore()); + assertNull(DeptContextHolder.getDeptId()); + assertEquals(11L, loginUser.getVisitCompanyId()); + assertNull(loginUser.getVisitDeptId()); + } + + @Test // 有公司+部门:写入公司、部门上下文,afterCompletion 清理 visitDeptId & holder + void testPreHandle_withCompanyAndDept_andAfterCompletionClear() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + LoginUser loginUser = new LoginUser(); + SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(loginUser, null)); + request.addHeader("visit-company-id", "22"); + request.addHeader("visit-dept-id", "33"); + + boolean result = interceptor.preHandle(request, response, new Object()); + + assertTrue(result); + assertFalse(CompanyContextHolder.isIgnore()); + assertEquals(22L, CompanyContextHolder.getCompanyId()); + assertEquals(33L, DeptContextHolder.getDeptId()); + assertEquals(22L, DeptContextHolder.getCompanyId()); + assertEquals(22L, loginUser.getVisitCompanyId()); + assertEquals(33L, loginUser.getVisitDeptId()); + + // afterCompletion: 清理 visitCompanyId/visitDeptId 与 holder + interceptor.afterCompletion(request, response, new Object(), null); + assertEquals(0L, loginUser.getVisitCompanyId()); + assertEquals(0L, loginUser.getVisitDeptId()); + assertNull(DeptContextHolder.getDeptId()); + assertNull(DeptContextHolder.getCompanyId()); + } +} From 9c0c4cca3391c9f6fa2de61430d2a6d339123073 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 23 Dec 2025 10:17:15 +0800 Subject: [PATCH 11/48] =?UTF-8?q?1.=20=E5=8D=87=E7=BA=A7=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 +++-- zt-dependencies/pom.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 8c4d3911..7e0b370a 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 3.0.45 + 3.0.46 17 ${java.version} @@ -271,7 +271,8 @@ chenbowen - local + + dev 172.16.46.63:30848 chenbowen diff --git a/zt-dependencies/pom.xml b/zt-dependencies/pom.xml index b0a132d9..f8e6acdc 100644 --- a/zt-dependencies/pom.xml +++ b/zt-dependencies/pom.xml @@ -26,7 +26,7 @@ https://github.com/YunaiV/ruoyi-vue-pro - 3.0.45 + 3.0.46 1.6.0 3.4.5 From 79452c02f6c538c106755c9390aa8d0d1a82326b Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 23 Dec 2025 11:44:37 +0800 Subject: [PATCH 12/48] =?UTF-8?q?1.=20=E4=BC=98=E5=8C=96=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BusinessDataPermissionEntityScanner.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java index 93c306f5..f44f4afe 100644 --- a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java +++ b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java @@ -28,6 +28,11 @@ import java.util.*; @Slf4j public class BusinessDataPermissionEntityScanner { + /** + * 临时排除的包前缀(物流模块 DO,不参与数据权限扫描) + */ + private static final Set EXCLUDED_PACKAGE_PREFIXES = Set.of("com.zt.plat.module.backendlogistics.dal.dataobject","com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO"); + private final Set basePackages; private final ClassLoader classLoader; @@ -70,6 +75,9 @@ public class BusinessDataPermissionEntityScanner { if (!StringUtils.hasText(className)) { continue; } + if (isExcludedPackage(className)) { + continue; + } try { Class clazz = ClassUtils.forName(className, classLoader); if (clazz == BusinessBaseDO.class || !BusinessBaseDO.class.isAssignableFrom(clazz)) { @@ -92,6 +100,15 @@ public class BusinessDataPermissionEntityScanner { return new ArrayList<>(metadataMap.values()); } + private boolean isExcludedPackage(String className) { + for (String prefix : EXCLUDED_PACKAGE_PREFIXES) { + if (className.startsWith(prefix)) { + return true; + } + } + return false; + } + private EntityMetadata buildMetadata(Class entityClass) { String tableName = resolveTableName(entityClass); if (!StringUtils.hasText(tableName)) { From ca87ed3c529fe2f5cde68abfa2454bcc011458ae Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 23 Dec 2025 11:59:32 +0800 Subject: [PATCH 13/48] =?UTF-8?q?1.=20=E6=9A=82=E6=97=B6=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E6=8E=89=E6=89=80=E6=9C=89=E7=9A=84=E7=89=A9=E6=B5=81=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E4=BB=A5=E5=8F=8A=20erp=20=E6=A8=A1=E5=9D=97=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/BusinessDataPermissionEntityScanner.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java index f44f4afe..2c195fed 100644 --- a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java +++ b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/framework/BusinessDataPermissionEntityScanner.java @@ -31,7 +31,10 @@ public class BusinessDataPermissionEntityScanner { /** * 临时排除的包前缀(物流模块 DO,不参与数据权限扫描) */ - private static final Set EXCLUDED_PACKAGE_PREFIXES = Set.of("com.zt.plat.module.backendlogistics.dal.dataobject","com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO"); + private static final Set EXCLUDED_PACKAGE_PREFIXES = Set.of( + "com.zt.plat.module.backendlogistics", + "com.zt.plat.module.erp", + "com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO"); private final Set basePackages; private final ClassLoader classLoader; From 7b1991cc1c592aaebb36032acfef864b390349d7 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 23 Dec 2025 16:36:06 +0800 Subject: [PATCH 14/48] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8D=20get=20=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E6=97=B6=EF=BC=8C=E8=BD=AC=E4=B9=89=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E8=A7=A3=E6=9E=90=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E4=BC=9A=E5=AD=98=E5=9C=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/GatewaySecurityFilter.java | 24 ++++++++--- .../sample/DatabusApiInvocationExample.java | 40 +++++++++++-------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java index 48c2a627..f9e5754d 100644 --- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java +++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/integration/gateway/security/GatewaySecurityFilter.java @@ -33,6 +33,7 @@ import org.springframework.web.util.ContentCachingResponseWrapper; import org.springframework.web.util.UriComponentsBuilder; import java.io.IOException; +import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -304,15 +305,28 @@ public class GatewaySecurityFilter extends OncePerRequestFilter { .build() .getQueryParams(); params.forEach((key, values) -> { - if (!StringUtils.hasText(key) || "signature".equalsIgnoreCase(key)) { + String decodedKey = URLDecoder.decode(key, StandardCharsets.UTF_8); + if (!StringUtils.hasText(decodedKey) || "signature".equalsIgnoreCase(decodedKey)) { return; } if (CollectionUtils.isEmpty(values)) { - target.put(key, ""); - } else if (values.size() == 1) { - target.put(key, values.get(0)); + target.put(decodedKey, ""); + return; + } + // 对每一个 value 做 URL 解码,确保与客户端原文签名一致 + List decodedValues = values.stream() + .map(val -> URLDecoder.decode(val, StandardCharsets.UTF_8)) + .toList(); + boolean allNullLiteral = decodedValues.stream() + .allMatch(v -> "null".equals(v)); + if (allNullLiteral) { + // 过滤掉仅包含字符串 "null" 的参数 + return; + } + if (decodedValues.size() == 1) { + target.put(decodedKey, decodedValues.get(0)); } else { - target.put(key, String.join(",", values)); + target.put(decodedKey, String.join(",", decodedValues)); } }); } catch (IllegalArgumentException ex) { diff --git a/zt-module-databus/zt-module-databus-server/src/test/java/com/zt/plat/module/databus/framework/integration/gateway/sample/DatabusApiInvocationExample.java b/zt-module-databus/zt-module-databus-server/src/test/java/com/zt/plat/module/databus/framework/integration/gateway/sample/DatabusApiInvocationExample.java index 5bd323d3..af84f587 100644 --- a/zt-module-databus/zt-module-databus-server/src/test/java/com/zt/plat/module/databus/framework/integration/gateway/sample/DatabusApiInvocationExample.java +++ b/zt-module-databus/zt-module-databus-server/src/test/java/com/zt/plat/module/databus/framework/integration/gateway/sample/DatabusApiInvocationExample.java @@ -5,6 +5,10 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.zt.plat.framework.common.util.security.CryptoSignatureUtils; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.io.PrintStream; import java.net.URI; @@ -23,10 +27,6 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeMap; import java.util.UUID; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; /** * 可直接运行的示例,演示如何使用 appId=test 与对应密钥调用本地 Databus API。 @@ -37,14 +37,14 @@ public final class DatabusApiInvocationExample { // private static final String APP_ID = "iwork"; // private static final String APP_SECRET = "lpGXiNe/GMLk0vsbYGLa8eYxXq8tGhTbuu3/D4MJzIk="; - private static final String APP_ID = "ztmy"; - private static final String APP_SECRET = "zFre/nTRGi7LpoFjN7oQkKeOT09x1fWTyIswrc702QQ="; + private static final String APP_ID = "jwyw"; + private static final String APP_SECRET = "MhfCcqB59rDTnB5yGOVXWtp/5a0JXir7pSjPl5cVMJ8="; private static final String ENCRYPTION_TYPE = CryptoSignatureUtils.ENCRYPT_TYPE_AES; // private static final String TARGET_API = "http://172.16.46.63:30081/admin-api/databus/api/portal/callback/v1"; // private static final String TARGET_API = "http://172.16.46.195:48080/admin-api/databus/api/portal/lgstOpenApi/v1"; // private static final String TARGET_API = "http://172.16.46.195:48080/admin-api/databus/api/portal/lgstOpenApi/v1"; - private static final String TARGET_API = "https://jygk.chncopper.com:30078/admin-api/databus/api/portal/lgstOpenApi/v1"; -// private static final String TARGET_API = "http://localhost:48080/admin-api/databus/api/portal/callback/v1"; +// private static final String TARGET_API = "https://jygk.chncopper.com:30078/admin-api/databus/api/portal/lgstOpenApi/v1"; + private static final String TARGET_API = "http://localhost:48080/admin-api/databus/api/portal/testcbw/456"; // private static final String TARGET_API = "http://localhost:48080/admin-api/databus/api/portal/lgstOpenApi/v1"; // private static final String TARGET_API = "http://localhost:48080/admin-api/databus/api/portal/testcbw/456"; // ⚠️ 仅用于联调:信任所有证书 + 关闭主机名校验,生产环境请改为受信 CA 或自定义 truststore。 @@ -102,10 +102,16 @@ public final class DatabusApiInvocationExample { public static void main(String[] args) throws Exception { OUT.println("=== GET 请求示例 ==="); -// executeGetExample(); + executeGetExample(); // OUT.println(); -// OUT.println("=== POST 请求示例 ==="); - executePostExample(); + OUT.println("=== POST 请求示例 ==="); + executePostExample(""" + {"operateFlag":"I","__interfaceType__":"R_MY_JY_03","data":{"endAddressName":"1","customerCompanyName":"中铜国贸","endAddressDetail":"测试地址","remark":" ","custSuppType":"1","shipperCompanyName":"中铜国贸","consigneeCorpCode":" ","consignerContactPhone":" 11","importFlag":"10","businessSupplierCode":" ","entrustMainCode":"WT3162251027027","endAddressCode":" ","specifyCarrierCorpCode":"10086689","materDetail":[{"detailStatus":"10","batchNo":"ZLTD2510ZTGM0017001","measureCodeMdm":"CU032110001","packType":" ","quantityPlanDetail":1,"deliveryOrderNo":"ZLTD2510ZTGM0017001","measureCode":"CU032110001","goodsSpecification":" ","measureUnitCode":"PAC","entrustDetailCode":"WT3162251027027001","brand":" ","soNumber":"68ecf0055502d565d22b378a"}],"operateFlag":1,"custSuppName":"上海锦生金属有限公司","startAddressCode":" ","planStartTime":1761556166000,"customerCompanyCode":0,"importMethod":"EXW","startAddressType":"10","shipperCompanyCode":"3162","deliverCondition":"20","businessSupplierName":" ","startAddressDetail":" 111","transType":"30","endAddressType":"20","planEndTime":1761556166000,"specifyCarrierCorpName":null,"custSuppFlag":"0101","businessType":"20","consigneeCorpName":" ","custSuppCode":"10086689","startAddressName":" 111","consignerContactName":" 11"},"datetime":"20251027170929","busiBillCode":"WT3162251027027","system":"BRMS","__requestId__":"f918841c-14fb-49eb-9640-c5d1b3d46bd1"} + """); + + executePostExample(""" + {"msgCode":"YWJYGK0003","data":"{\\"memberId\\":65352,\\"routes\\":[{\\"carrierCorpCode\\":\\"10193776\\",\\"carrierCorpName\\":\\"成都达海金属加工配送有限公司\\",\\"endAddressCode\\":\\"440000-440300\\",\\"endAddressDetail\\":\\"深圳港\\",\\"endAddressDetailDesc\\":\\"广东省深圳市盐田区深盐路\\",\\"endAddressLatitude\\":22.567426,\\"endAddressLongitude\\":114.283271,\\"endAddressName\\":\\"广东省-深圳市\\",\\"endAddressType\\":\\"port\\",\\"startAddressCode\\":\\"520000-0\\",\\"startAddressDetail\\":\\"安龙\\",\\"startAddressDetailDesc\\":\\"贵州省安龙县德卧镇坡告村\\",\\"startAddressLatitude\\":25.066532,\\"startAddressLongitude\\":105.244186,\\"startAddressName\\":\\"贵州省-null\\",\\"startAddressType\\":\\"railway-station\\",\\"taskEndTime\\":1766592000000,\\"taskStartTime\\":1766332800000,\\"transType\\":\\"10\\"},{\\"carrierCorpCode\\":\\"10193776\\",\\"carrierCorpName\\":\\"成都达海金属加工配送有限公司\\",\\"endAddressCode\\":\\"230000-230600\\",\\"endAddressDetail\\":\\"大庆东\\",\\"endAddressDetailDesc\\":\\"黑龙江省大庆市龙凤区凤一路28号\\",\\"endAddressLatitude\\":46.544097,\\"endAddressLongitude\\":125.118902,\\"endAddressName\\":\\"黑龙江省-大庆市\\",\\"endAddressType\\":\\"railway-station\\",\\"startAddressCode\\":\\"440000-440300\\",\\"startAddressDetail\\":\\"深圳港\\",\\"startAddressDetailDesc\\":\\"广东省深圳市盐田区深盐路\\",\\"startAddressLatitude\\":22.567426,\\"startAddressLongitude\\":114.283271,\\"startAddressName\\":\\"广东省-深圳市\\",\\"startAddressType\\":\\"port\\",\\"taskEndTime\\":1767110400000,\\"taskStartTime\\":1766592000000,\\"transType\\":\\"30\\"},{\\"carrierCorpCode\\":\\"10193776\\",\\"carrierCorpName\\":\\"成都达海金属加工配送有限公司\\",\\"endAddressCode\\":\\"520000-0\\",\\"endAddressDetail\\":\\"郑屯\\",\\"endAddressDetailDesc\\":\\"贵州省郑屯镇\\",\\"endAddressName\\":\\"贵州省-null\\",\\"endAddressType\\":\\"railway-station\\",\\"startAddressCode\\":\\"230000-230600\\",\\"startAddressDetail\\":\\"大庆东\\",\\"startAddressDetailDesc\\":\\"黑龙江省大庆市龙凤区凤一路28号\\",\\"startAddressLatitude\\":46.544097,\\"startAddressLongitude\\":125.118902,\\"startAddressName\\":\\"黑龙江省-大庆市\\",\\"startAddressType\\":\\"railway-station\\",\\"taskEndTime\\":1768320000000,\\"taskStartTime\\":1767110400000,\\"transType\\":\\"20\\"}],\\"taskLineNumber\\":\\"CT202512230001_001\\",\\"taskNumber\\":\\"CT202512230001\\"}"} + """); } private static void executeGetExample() throws Exception { @@ -113,9 +119,11 @@ public final class DatabusApiInvocationExample { queryParams.put("businessCode", "11"); queryParams.put("fileId", "11"); queryParams.put("null", null); + queryParams.put("empty", ""); + queryParams.put("taskTimeEnd", "2025-12-28 23:00:00"); String signature = generateSignature(queryParams, Map.of()); URI requestUri = buildUri(TARGET_API, queryParams); - String nonce = "171615676c7d4d96b9f55f3d90ad27e0"; + String nonce = randomNonce(); HttpRequest request = HttpRequest.newBuilder(requestUri) .timeout(Duration.ofSeconds(10)) @@ -131,16 +139,14 @@ public final class DatabusApiInvocationExample { printResponse(response); } - private static void executePostExample() throws Exception { + private static void executePostExample(String json) throws Exception { Map queryParams = new LinkedHashMap<>(); long extraTimestamp = 1761556157185L; -// String bodyJson = String.format(""" +// String bodyJson = String.json(""" // {"operateFlag":"I","__interfaceType__":"R_MY_JY_03","data":{"endAddressName":"1","customerCompanyName":"中铜国贸","endAddressDetail":"测试地址","remark":" ","custSuppType":"1","shipperCompanyName":"中铜国贸","consigneeCorpCode":" ","consignerContactPhone":" 11","importFlag":"10","businessSupplierCode":" ","entrustMainCode":"WT3162251027027","endAddressCode":" ","specifyCarrierCorpCode":"10086689","materDetail":[{"detailStatus":"10","batchNo":"ZLTD2510ZTGM0017001","measureCodeMdm":"CU032110001","packType":" ","quantityPlanDetail":1,"deliveryOrderNo":"ZLTD2510ZTGM0017001","measureCode":"CU032110001","goodsSpecification":" ","measureUnitCode":"PAC","entrustDetailCode":"WT3162251027027001","brand":" ","soNumber":"68ecf0055502d565d22b378a"}],"operateFlag":1,"custSuppName":"上海锦生金属有限公司","startAddressCode":" ","planStartTime":1761556166000,"customerCompanyCode":0,"importMethod":"EXW","startAddressType":"10","shipperCompanyCode":"3162","deliverCondition":"20","businessSupplierName":" ","startAddressDetail":" 111","transType":"30","endAddressType":"20","planEndTime":1761556166000,"specifyCarrierCorpName":null,"custSuppFlag":"0101","businessType":"20","consigneeCorpName":" ","custSuppCode":"10086689","startAddressName":" 111","consignerContactName":" 11"},"datetime":"20251027170929","busiBillCode":"WT3162251027027","system":"BRMS","__requestId__":"f918841c-14fb-49eb-9640-c5d1b3d46bd1"} // """, extraTimestamp); - String bodyJson = String.format(""" - {} - """, extraTimestamp); + String bodyJson = String.format(json, extraTimestamp); Map bodyParams = parseBodyJson(bodyJson); String signature = generateSignature(queryParams, bodyParams); From 82ea639cdd138b6aa4fff408968de4f2be92860d Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 23 Dec 2025 16:36:35 +0800 Subject: [PATCH 15/48] =?UTF-8?q?1.=20=E5=8E=BB=E6=8E=89=E5=87=AD=E8=AF=81?= =?UTF-8?q?=E5=94=AF=E4=B8=80=E7=BA=A6=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/数据总线API凭证绑定与访问日志补充_20251209.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/dm/数据总线API凭证绑定与访问日志补充_20251209.sql b/sql/dm/数据总线API凭证绑定与访问日志补充_20251209.sql index ab9dcc19..c9dc74f1 100644 --- a/sql/dm/数据总线API凭证绑定与访问日志补充_20251209.sql +++ b/sql/dm/数据总线API凭证绑定与访问日志补充_20251209.sql @@ -19,7 +19,8 @@ CREATE TABLE databus_api_definition_credential ( deleted BIT DEFAULT '0' NOT NULL ); -CREATE UNIQUE INDEX uk_databus_api_definition_credential ON databus_api_definition_credential (api_id, credential_id, deleted); +-- 去掉错误的唯一索引逻辑 +-- CREATE UNIQUE INDEX uk_databus_api_definition_credential ON databus_api_definition_credential (api_id, credential_id, deleted); CREATE INDEX idx_databus_api_definition_credential_api ON databus_api_definition_credential (api_id); CREATE INDEX idx_databus_api_definition_credential_cred ON databus_api_definition_credential (credential_id); From 76619824474d72a1fb9054bf4e610b6f63e72ff8 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Tue, 23 Dec 2025 18:20:42 +0800 Subject: [PATCH 16/48] =?UTF-8?q?update=EF=BC=9A=E5=8D=87=E7=BA=A7seata?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=88=B02.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-dependencies/pom.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/zt-dependencies/pom.xml b/zt-dependencies/pom.xml index b5c1f76c..8881c31e 100644 --- a/zt-dependencies/pom.xml +++ b/zt-dependencies/pom.xml @@ -32,6 +32,7 @@ 3.4.5 2024.0.1 2023.0.3.2 + 2.4.0 2.8.3 4.6.0 @@ -133,6 +134,18 @@ import + + + org.apache.seata + seata-all + ${seata.version} + + + org.apache.seata + seata-spring-boot-starter + ${seata.version} + + io.github.mouzt From 20524797289c05a1f3285c73e186dcd1fee0e0c8 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 23 Dec 2025 19:05:07 +0800 Subject: [PATCH 17/48] =?UTF-8?q?1.=20=E4=B8=B4=E6=97=B6=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E5=B9=B3=E5=8F=B0=E7=9A=84=E5=8D=95=E7=8B=AC?= =?UTF-8?q?=20topic=20=E6=B6=88=E8=B4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zt/plat/module/system/mq/message/sms/SmsSendMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/mq/message/sms/SmsSendMessage.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/mq/message/sms/SmsSendMessage.java index fa86b5a6..5ce00196 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/mq/message/sms/SmsSendMessage.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/mq/message/sms/SmsSendMessage.java @@ -14,7 +14,7 @@ import java.util.List; @Data public class SmsSendMessage { - public static final String TOPIC = "SMS_SEND_TOPIC"; // 重点:需要增加消息对应的 Topic + public static final String TOPIC = "SMS_SEND_TOPIC_TEST"; // 重点:需要增加消息对应的 Topic /** * 短信日志编号 */ From 7e87465ef9a90e10d516a149c7133a93ce9bcb61 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Wed, 24 Dec 2025 10:14:52 +0800 Subject: [PATCH 18/48] =?UTF-8?q?1.=20=E4=BF=AE=E6=AD=A3=E6=9C=89=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E7=9F=AD=E4=BF=A1=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/zt/plat/module/system/enums/ErrorCodeConstants.java | 4 ++-- .../plat/module/system/service/sms/SmsCodeServiceImpl.java | 6 +++--- .../src/main/resources/application.yaml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java index 8178c53e..fd2aee37 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/ErrorCodeConstants.java @@ -127,8 +127,8 @@ public interface ErrorCodeConstants { ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1_002_014_000, "验证码不存在"); ErrorCode SMS_CODE_EXPIRED = new ErrorCode(1_002_014_001, "验证码已过期"); ErrorCode SMS_CODE_USED = new ErrorCode(1_002_014_002, "验证码已使用"); - ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "超过每日短信发送数量"); - ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "短信发送过于频繁"); + ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "超过每日短信发送数量:{}次"); + ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "短信发送过于频繁,请于{}分钟后再试"); // ========== 租户信息 1-002-015-000 ========== ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1_002_015_000, "租户不存在"); diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/sms/SmsCodeServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/sms/SmsCodeServiceImpl.java index 9661a239..bc31fbad 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/sms/SmsCodeServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/sms/SmsCodeServiceImpl.java @@ -10,10 +10,10 @@ import com.zt.plat.module.system.dal.dataobject.sms.SmsCodeDO; import com.zt.plat.module.system.dal.mysql.sms.SmsCodeMapper; import com.zt.plat.module.system.enums.sms.SmsSceneEnum; import com.zt.plat.module.system.framework.sms.config.SmsCodeProperties; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; import java.time.LocalDateTime; import static cn.hutool.core.util.RandomUtil.randomInt; @@ -56,11 +56,11 @@ public class SmsCodeServiceImpl implements SmsCodeService { if (lastSmsCode != null) { if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() < smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁 - throw exception(SMS_CODE_SEND_TOO_FAST); + throw exception(SMS_CODE_SEND_TOO_FAST, smsCodeProperties.getSendFrequency().toMinutes()); } if (isToday(lastSmsCode.getCreateTime()) && // 必须是今天,才能计算超过当天的上限 lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。 - throw exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); + throw exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY, smsCodeProperties.getSendMaximumQuantityPerDay()); } // TODO ZT:提升,每个 IP 每天可发送数量 // TODO ZT:提升,每个 IP 每小时可发送数量 diff --git a/zt-module-system/zt-module-system-server/src/main/resources/application.yaml b/zt-module-system/zt-module-system-server/src/main/resources/application.yaml index 2b0a2558..853e32cd 100644 --- a/zt-module-system/zt-module-system-server/src/main/resources/application.yaml +++ b/zt-module-system/zt-module-system-server/src/main/resources/application.yaml @@ -241,8 +241,8 @@ zt: expire-times: 10m send-frequency: 1m send-maximum-quantity-per-day: 10 - begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 - end-code: 9999 # 这里配置 9999 的原因是,测试方便。 + begin-code: 100000 + end-code: 999999 # E办OAuth2配置文件 From 433e2fb4de49dc41b7b0dd06a0be7a38cecb92b4 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Wed, 24 Dec 2025 10:27:57 +0800 Subject: [PATCH 19/48] =?UTF-8?q?1.=20=E4=BF=AE=E6=94=B9=E6=AF=8F=E6=97=A5?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=8F=91=E9=80=81=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zt-module-system-server/src/main/resources/application.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zt-module-system/zt-module-system-server/src/main/resources/application.yaml b/zt-module-system/zt-module-system-server/src/main/resources/application.yaml index 853e32cd..1b3abadf 100644 --- a/zt-module-system/zt-module-system-server/src/main/resources/application.yaml +++ b/zt-module-system/zt-module-system-server/src/main/resources/application.yaml @@ -240,7 +240,7 @@ zt: sms-code: # 短信验证码相关的配置项 expire-times: 10m send-frequency: 1m - send-maximum-quantity-per-day: 10 + send-maximum-quantity-per-day: 20 begin-code: 100000 end-code: 999999 From 9485d94574b422afdf85d4c5216793b7e8d24e85 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Wed, 24 Dec 2025 10:36:00 +0800 Subject: [PATCH 20/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/consumer/DatabusClientConsumer.java | 7 +- .../handler/dept/DeptSyncServiceImpl.java | 25 ++--- .../handler/post/PostSyncServiceImpl.java | 23 +--- .../user/AdminUserSyncServiceImpl.java | 19 +--- .../userdept/UserDeptSyncServiceImpl.java | 19 +--- .../userpost/UserPostSyncServiceImpl.java | 19 +--- .../plat/module/system/api/dept/DeptApi.java | 6 + .../plat/module/system/api/dept/PostApi.java | 6 + .../system/api/dept/dto/DeptSaveReqDTO.java | 15 +++ .../module/system/api/user/AdminUserApi.java | 6 + .../api/user/dto/AdminUserSaveReqDTO.java | 6 + .../system/api/userdept/UserDeptApi.java | 6 + .../system/api/userpost/UserPostApi.java | 6 + .../DatabusUserDeptProviderApiImpl.java | 6 +- .../module/system/api/dept/DeptApiImpl.java | 9 ++ .../module/system/api/dept/PostApiImpl.java | 8 +- .../system/api/user/AdminUserApiImpl.java | 7 ++ .../system/api/userdept/UserDeptApiImpl.java | 88 +++++++++++++++ .../system/api/userpost/UserPostApiImpl.java | 106 ++++++++++++++++++ .../system/dal/mysql/dept/DeptMapper.java | 7 +- .../system/service/dept/DeptService.java | 4 + .../system/service/dept/DeptServiceImpl.java | 37 ++++++ .../system/service/dept/PostService.java | 4 + .../system/service/dept/PostServiceImpl.java | 21 ++++ .../system/service/user/AdminUserService.java | 4 + .../service/user/AdminUserServiceImpl.java | 44 ++++++++ .../service/userdept/UserDeptService.java | 3 + .../service/userdept/UserDeptServiceImpl.java | 20 +++- 28 files changed, 453 insertions(+), 78 deletions(-) create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java index 4a7c5cdb..0000776e 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java @@ -13,7 +13,7 @@ import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; - +import com.zt.plat.framework.tenant.core.context.TenantContextHolder; /** * DataBus 客户端统一消费者 *

@@ -33,8 +33,8 @@ import org.springframework.stereotype.Component; @Component @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") @RocketMQMessageListener( - topic = "${zt.databus.sync.client.mq.topic:databus-sync}-${zt.databus.sync.client.client-code}", - consumerGroup = "${zt.databus.sync.client.mq.consumer-group:databus-client-consumer}-${zt.databus.sync.client.client-code}" + topic = "${zt.databus.sync.client.mq.topic-base:databus-sync}-${zt.databus.sync.client.client-code}", + consumerGroup = "${zt.databus.sync.client.mq.consumer-group-prefix:databus-client-consumer}-${zt.databus.sync.client.client-code}" ) public class DatabusClientConsumer implements RocketMQListener { @@ -46,6 +46,7 @@ public class DatabusClientConsumer implements RocketMQListener { log.debug("[DatabusClient] 收到消息, body={}", body); try { + TenantContextHolder.setTenantId(1L); // 1. 解析消息获取 eventType DatabusEventType eventType = parseEventType(body); if (eventType == null) { diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java index ca760435..00d9913a 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java @@ -69,21 +69,15 @@ public class DeptSyncServiceImpl implements DeptSyncService { return; } DeptSaveReqDTO dto = buildDeptDTO(data); + + // 使用专用同步接口,跳过业务校验,直接 upsert try { - // 尝试获取,存在则更新,不存在则创建 - var existing = deptApi.getDept(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - deptApi.updateDept(dto).checkError(); - log.info("[DeptSync] 部门全量同步-更新成功, deptId={}", dto.getId()); - } else { - deptApi.createDept(dto).checkError(); - log.info("[DeptSync] 部门全量同步-创建成功, deptId={}", dto.getId()); - } + deptApi.syncDept(dto).checkError(); + log.info("[DeptSync] 部门全量同步成功, deptId={}, deptName={}", dto.getId(), dto.getName()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[DeptSync] 部门获取失败,尝试创建, deptId={}", dto.getId()); - deptApi.createDept(dto).checkError(); - log.info("[DeptSync] 部门全量同步-创建成功, deptId={}", dto.getId()); + log.error("[DeptSync] 部门全量同步失败, deptId={}, deptName={}, parentId={}, code={}, error={}", + dto.getId(), dto.getName(), dto.getParentId(), dto.getCode(), e.getMessage()); + throw e; } } @@ -93,13 +87,18 @@ public class DeptSyncServiceImpl implements DeptSyncService { private DeptSaveReqDTO buildDeptDTO(DatabusDeptData data) { DeptSaveReqDTO dto = new DeptSaveReqDTO(); dto.setId(data.getId()); + dto.setCode(data.getCode()); // ⚠️ 重要:传递编码,保持一致 dto.setName(data.getName()); + dto.setShortName(data.getShortName()); dto.setParentId(data.getParentId()); dto.setSort(data.getSort()); dto.setLeaderUserId(data.getLeaderUserId()); dto.setPhone(data.getPhone()); dto.setEmail(data.getEmail()); dto.setStatus(data.getStatus()); + dto.setIsGroup(data.getIsGroup()); + dto.setIsCompany(data.getIsCompany()); + dto.setDeptSource(data.getDeptSource()); return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java index 463fdc6e..6ad68f2e 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java @@ -68,25 +68,14 @@ public class PostSyncServiceImpl implements PostSyncService { return; } PostSaveReqDTO dto = buildPostDTO(data); + try { - // 尝试获取,存在则更新,不存在则创建 - var existing = postApi.getPost(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - postApi.updatePost(dto).checkError(); - log.info("[PostSync] 岗位全量同步-更新成功, postId={}, postName={}", dto.getId(), dto.getName()); - } else { - postApi.createPost(dto).checkError(); - log.info("[PostSync] 岗位全量同步-创建成功, postId={}, postName={}", dto.getId(), dto.getName()); - } + postApi.syncPost(dto).checkError(); + log.info("[PostSync] 岗位全量同步成功, postId={}, postName={}", dto.getId(), dto.getName()); } catch (Exception e) { - // 获取失败,尝试创建 - try { - postApi.createPost(dto).checkError(); - log.info("[PostSync] 岗位全量同步-创建成功, postId={}, postName={}", dto.getId(), dto.getName()); - } catch (Exception createEx) { - log.error("[PostSync] 岗位全量同步失败, postId={}, postName={}", dto.getId(), dto.getName(), createEx); - throw createEx; - } + log.error("[PostSync] 岗位全量同步失败, postId={}, postName={}, code={}, error={}", + dto.getId(), dto.getName(), dto.getCode(), e.getMessage()); + throw e; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java index d40cfd51..a0b239df 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java @@ -72,21 +72,14 @@ public class AdminUserSyncServiceImpl implements AdminUserSyncService { return; } AdminUserSaveReqDTO dto = buildUserDTO(data); + try { - // 尝试获取,存在则更新,不存在则创建 - var existing = adminUserApi.getUser(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - adminUserApi.updateUser(dto).checkError(); - log.info("[UserSync] 用户全量同步-更新成功, userId={}", dto.getId()); - } else { - adminUserApi.createUser(dto).checkError(); - log.info("[UserSync] 用户全量同步-创建成功, userId={}", dto.getId()); - } + adminUserApi.syncUser(dto).checkError(); + log.info("[UserSync] 用户全量同步成功, userId={}, username={}", dto.getId(), dto.getUsername()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[UserSync] 用户获取失败,尝试创建, userId={}", dto.getId()); - adminUserApi.createUser(dto).checkError(); - log.info("[UserSync] 用户全量同步-创建成功, userId={}", dto.getId()); + log.error("[UserSync] 用户全量同步失败, userId={}, username={}, error={}", + dto.getId(), dto.getUsername(), e.getMessage()); + throw e; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java index 04f16ae4..36914af0 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java @@ -70,20 +70,13 @@ public class UserDeptSyncServiceImpl implements UserDeptSyncService { } UserDeptSaveReqDTO dto = buildUserDeptDTO(data); try { - // 尝试获取,存在则更新,不存在则创建 - var existing = userDeptApi.getUserDept(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - userDeptApi.updateUserDept(dto).checkError(); - log.info("[UserDeptSync] 用户-部门关系全量同步-更新成功, id={}", dto.getId()); - } else { - userDeptApi.createUserDept(dto).checkError(); - log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); - } + userDeptApi.syncUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步成功, id={}, userId={}, deptId={}", + dto.getId(), dto.getUserId(), dto.getDeptId()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[UserDeptSync] 用户-部门关系获取失败,尝试创建, id={}", dto.getId()); - userDeptApi.createUserDept(dto).checkError(); - log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + log.error("[UserDeptSync] 用户-部门关系全量同步失败, id={}, userId={}, deptId={}, error={}", + dto.getId(), dto.getUserId(), dto.getDeptId(), e.getMessage()); + throw e; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java index 01eb2b4b..47251092 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java @@ -70,20 +70,13 @@ public class UserPostSyncServiceImpl implements UserPostSyncService { } UserPostSaveReqDTO dto = buildUserPostDTO(data); try { - // 尝试获取,存在则更新,不存在则创建 - var existing = userPostApi.getUserPost(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - userPostApi.updateUserPost(dto).checkError(); - log.info("[UserPostSync] 用户-岗位关系全量同步-更新成功, id={}", dto.getId()); - } else { - userPostApi.createUserPost(dto).checkError(); - log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); - } + userPostApi.syncUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步成功, id={}, userId={}, postId={}", + dto.getId(), dto.getUserId(), dto.getPostId()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[UserPostSync] 用户-岗位关系获取失败,尝试创建, id={}", dto.getId()); - userPostApi.createUserPost(dto).checkError(); - log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + log.error("[UserPostSync] 用户-岗位关系全量同步失败, id={}, userId={}, postId={}, error={}", + dto.getId(), dto.getUserId(), dto.getPostId(), e.getMessage()); + throw e; } } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java index eea5499e..abc53972 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java @@ -86,4 +86,10 @@ public interface DeptApi { @Parameter(name = "userId", description = "用户编号", example = "1", required = true) CommonResult> getCompanyDeptInfoListByUserId(@RequestParam("userId") Long userId); + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步部门") + CommonResult syncDept(@RequestBody DeptSaveReqDTO syncReqDTO); + } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java index fed71544..4ef8bd45 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java @@ -64,4 +64,10 @@ public interface PostApi { return CollectionUtils.convertMap(list, PostRespDTO::getId); } + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步岗位") + CommonResult syncPost(@RequestBody PostSaveReqDTO syncReqDTO); + } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java index fbb311cc..b01a712d 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java @@ -15,9 +15,15 @@ public class DeptSaveReqDTO { @Schema(description = "部门编号", example = "1024") private Long id; + @Schema(description = "部门编码", example = "ZT001") + private String code; + @Schema(description = "部门名称", example = "ZT") private String name; + @Schema(description = "部门简称", example = "技术") + private String shortName; + @Schema(description = "父部门 ID", example = "1024") private Long parentId; @@ -36,6 +42,15 @@ public class DeptSaveReqDTO { @Schema(description = "状态,见 CommonStatusEnum 枚举0 开启 1 关闭", example = "0") private Integer status; + @Schema(description = "是否集团", example = "false") + private Boolean isGroup; + + @Schema(description = "是否公司", example = "false") + private Boolean isCompany; + + @Schema(description = "部门来源类型", example = "1") + private Integer deptSource; + @Schema(description = "外部系统标识,用于建立编码映射", example = "ERP") private String externalSystemCode; diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java index 9831e89f..31a7a5ee 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java @@ -104,6 +104,12 @@ public interface AdminUserApi extends AutoTransable { @Parameter(name = "ids", description = "用户编号数组", example = "3,5", required = true) CommonResult validateUserList(@RequestParam("ids") Collection ids); + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步用户") + CommonResult syncUser(@RequestBody AdminUserSaveReqDTO syncReqDTO); + @Override @FeignIgnore default List selectByIds(List ids) { diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java index 4e4a30c2..691f5204 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java @@ -50,4 +50,10 @@ public class AdminUserSaveReqDTO { @Schema(description = "密码", example = "123456") private String password; + @Schema(description = "工号", example = "A00123") + private String workcode; + + @Schema(description = "用户来源类型", example = "1") + private Integer userSource; + } \ No newline at end of file diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java index d48c6b69..050216ae 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java @@ -61,4 +61,10 @@ public interface UserDeptApi { @Operation(summary = "通过部门ID删除用户部门关系") @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) CommonResult deleteUserDeptByDeptId(@RequestParam("deptId") Long deptId); + + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步用户部门关系") + CommonResult syncUserDept(@RequestBody UserDeptSaveReqDTO syncReqDTO); } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java index a58e09cb..d72e4706 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java @@ -61,4 +61,10 @@ public interface UserPostApi { @Operation(summary = "通过岗位ID删除用户岗位关系") @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) CommonResult deleteUserPostByPostId(@RequestParam("postId") Long postId); + + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步用户岗位关系") + CommonResult syncUserPost(@RequestBody UserPostSaveReqDTO syncReqDTO); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java index 3a461df9..efbe2e1d 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -38,7 +38,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的部门关系 + // 查询用户部门关系 List list = userDeptMapper.selectPageByCursorWithUserSource( reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), @@ -67,7 +67,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp // 首次查询时返���总数 Long total = null; if (reqDTO.isFirstPage()) { - // ⚠️ 只统计 userSource = 2 的用户的部门关系 + // 统计用户部门关系 total = userDeptMapper.countWithUserSource(reqDTO.getTenantId()); } @@ -107,7 +107,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult count(Long tenantId) { - // ⚠️ 只统计 userSource = 2 的用户的部门关系 + // 统计用户部门关系 return success(userDeptMapper.countWithUserSource(tenantId)); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java index d06b79a6..bed2d2b6 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java @@ -107,4 +107,13 @@ public class DeptApiImpl implements DeptApi { return success(BeanUtils.toBean(companyDeptInfos, CompanyDeptInfoRespDTO.class)); } + // ========== 数据同步专用接口 ========== + + @Override + public CommonResult syncDept(DeptSaveReqDTO syncReqDTO) { + DeptSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, DeptSaveReqVO.class); + deptService.syncDept(reqVO); + return success(true); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java index 97cf029e..bb760ec4 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java @@ -38,7 +38,6 @@ public class PostApiImpl implements PostApi { @Override public CommonResult updatePost(PostSaveReqDTO updateReqVO) { - log.error("ssssssssss"); PostSaveReqVO reqVO = BeanUtils.toBean(updateReqVO, PostSaveReqVO.class); postService.updatePost(reqVO); return success(true); @@ -76,4 +75,11 @@ public class PostApiImpl implements PostApi { return success(BeanUtils.toBean(list, PostRespDTO.class)); } + @Override + public CommonResult syncPost(PostSaveReqDTO syncReqDTO) { + PostSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, PostSaveReqVO.class); + postService.syncPost(reqVO); + return success(true); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java index a80db06e..523e432a 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java @@ -149,4 +149,11 @@ public class AdminUserApiImpl implements AdminUserApi { return success(true); } + @Override + public CommonResult syncUser(AdminUserSaveReqDTO syncReqDTO) { + UserSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, UserSaveReqVO.class); + userService.syncUser(reqVO); + return success(true); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java new file mode 100644 index 00000000..91b30187 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java @@ -0,0 +1,88 @@ +package com.zt.plat.module.system.api.userdept; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.util.object.BeanUtils; +import com.zt.plat.module.system.api.userdept.dto.UserDeptRespDTO; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; +import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; +import com.zt.plat.module.system.service.userdept.UserDeptService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * 用户-部门关系 API 实现类 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class UserDeptApiImpl implements UserDeptApi { + + @Resource + private UserDeptService userDeptService; + + @Override + public CommonResult createUserDept(UserDeptSaveReqDTO reqVO) { + UserDeptDO userDept = BeanUtils.toBean(reqVO, UserDeptDO.class); + Long id = userDeptService.createUserDept(userDept); + return success(id); + } + + @Override + public CommonResult updateUserDept(UserDeptSaveReqDTO reqVO) { + UserDeptDO userDept = BeanUtils.toBean(reqVO, UserDeptDO.class); + userDeptService.updateUserDept(userDept); + return success(true); + } + + @Override + public CommonResult deleteUserDept(Long id) { + userDeptService.deleteUserDept(id); + return success(true); + } + + @Override + public CommonResult getUserDept(Long id) { + UserDeptDO userDept = userDeptService.getUserDept(id); + return success(BeanUtils.toBean(userDept, UserDeptRespDTO.class)); + } + + @Override + public CommonResult> getUserDeptListByUserId(Long userId) { + List list = userDeptService.getValidUserDeptListByUserIds(List.of(userId)); + return success(BeanUtils.toBean(list, UserDeptRespDTO.class)); + } + + @Override + public CommonResult> getUserDeptListByDeptId(Long deptId) { + List list = userDeptService.getValidUserDeptListByDeptIds(List.of(deptId)); + return success(BeanUtils.toBean(list, UserDeptRespDTO.class)); + } + + @Override + public CommonResult deleteUserDeptByUserId(Long userId) { + userDeptService.deleteUserDeptByUserId(userId); + return success(true); + } + + @Override + public CommonResult deleteUserDeptByDeptId(Long deptId) { + // 需要实现此方法,暂时返回成功 + return success(true); + } + + @Override + public CommonResult syncUserDept(UserDeptSaveReqDTO syncReqDTO) { + UserDeptDO userDept = BeanUtils.toBean(syncReqDTO, UserDeptDO.class); + userDeptService.syncUserDept(userDept); + return success(true); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java new file mode 100644 index 00000000..1ee2db26 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java @@ -0,0 +1,106 @@ +package com.zt.plat.module.system.api.userpost; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.util.object.BeanUtils; +import com.zt.plat.module.system.api.userpost.dto.UserPostRespDTO; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; +import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; +import com.zt.plat.module.system.dal.mysql.dept.UserPostMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * 用户-岗位关系 API 实现类 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class UserPostApiImpl implements UserPostApi { + + @Resource + private UserPostMapper userPostMapper; + + @Override + public CommonResult createUserPost(UserPostSaveReqDTO reqVO) { + UserPostDO userPost = BeanUtils.toBean(reqVO, UserPostDO.class); + userPostMapper.insert(userPost); + return success(userPost.getId()); + } + + @Override + public CommonResult updateUserPost(UserPostSaveReqDTO reqVO) { + UserPostDO userPost = BeanUtils.toBean(reqVO, UserPostDO.class); + userPostMapper.updateById(userPost); + return success(true); + } + + @Override + public CommonResult deleteUserPost(Long id) { + userPostMapper.deleteById(id); + return success(true); + } + + @Override + public CommonResult getUserPost(Long id) { + UserPostDO userPost = userPostMapper.selectById(id); + return success(BeanUtils.toBean(userPost, UserPostRespDTO.class)); + } + + @Override + public CommonResult> getUserPostListByUserId(Long userId) { + List list = userPostMapper.selectListByUserId(userId); + return success(BeanUtils.toBean(list, UserPostRespDTO.class)); + } + + @Override + public CommonResult> getUserPostListByPostId(Long postId) { + List list = userPostMapper.selectListByPostIds(List.of(postId)); + return success(BeanUtils.toBean(list, UserPostRespDTO.class)); + } + + @Override + public CommonResult deleteUserPostByUserId(Long userId) { + userPostMapper.deleteByUserId(userId); + return success(true); + } + + @Override + public CommonResult deleteUserPostByPostId(Long postId) { + userPostMapper.delete(UserPostDO::getPostId, postId); + return success(true); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public CommonResult syncUserPost(UserPostSaveReqDTO syncReqDTO) { + if (syncReqDTO.getId() == null) { + return success(false); + } + + UserPostDO existing = userPostMapper.selectById(syncReqDTO.getId()); + UserPostDO userPost = BeanUtils.toBean(syncReqDTO, UserPostDO.class); + + if (existing != null) { + userPostMapper.updateById(userPost); + log.info("[syncUserPost] 用户岗位关系同步-更新成功, id={}, userId={}, postId={}", + userPost.getId(), userPost.getUserId(), userPost.getPostId()); + } else { + userPostMapper.insert(userPost); + log.info("[syncUserPost] 用户岗位关系同步-创建成功, id={}, userId={}, postId={}", + userPost.getId(), userPost.getUserId(), userPost.getPostId()); + } + + return success(true); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java index 76943edf..a8416485 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java @@ -127,12 +127,17 @@ public interface DeptMapper extends BaseMapperX { /** * 根据部门编码查询部门 + *

+ * 注意:如果存在多条相同编码的记录,只返回第一条 * * @param code 部门编码 * @return 部门信息 */ default DeptDO selectByCode(String code) { - return selectOne(DeptDO::getCode, code); + List list = selectList(new LambdaQueryWrapperX() + .eq(DeptDO::getCode, code) + .last("LIMIT 1")); + return CollUtil.isNotEmpty(list) ? list.get(0) : null; } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java index 80834565..3996eef8 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java @@ -181,4 +181,8 @@ public interface DeptService { * @param deptIds 需要回填的部门 ID 列表 */ void backfillMissingCodesWithoutEvent(Collection deptIds); + + // ========== 数据同步专用接口 ========== + + void syncDept(DeptSaveReqVO syncReqVO); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java index 24104dc1..0a5c607e 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java @@ -923,4 +923,41 @@ public class DeptServiceImpl implements DeptService { } } + // ========== 数据同步专用接口 ========== + + @Override + @Transactional(rollbackFor = Exception.class) + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, allEntries = true) + @DataPermission(enable = false) + public void syncDept(DeptSaveReqVO syncReqVO) { + if (syncReqVO.getId() == null) { + log.warn("[syncDept] 同步部门失败,ID 不能为空"); + return; + } + // 标准化父部门 ID + syncReqVO.setParentId(normalizeParentId(syncReqVO.getParentId())); + // 默认部门来源 + if (syncReqVO.getDeptSource() == null) { + syncReqVO.setDeptSource(DeptSourceEnum.EXTERNAL.getSource()); + } + + // 检查部门是否存在 + DeptDO existingDept = deptMapper.selectById(syncReqVO.getId()); + + // 转换为 DO + DeptDO dept = BeanUtils.toBean(syncReqVO, DeptDO.class); + + if (existingDept != null) { + // 部门存在,执行更新 + deptMapper.updateById(dept); + log.info("[syncDept] 部门同步-更新成功, deptId={}, deptName={}", dept.getId(), dept.getName()); + } else { + // 部门不存在,执行插入 + deptMapper.insert(dept); + log.info("[syncDept] 部门同步-创建成功, deptId={}, deptName={}", dept.getId(), dept.getName()); + } + + // 注意:不发布变更事件,避免循环同步 + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java index 4ece87ea..153c7fd3 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java @@ -89,4 +89,8 @@ public interface PostService { */ Long getOrCreatePostByName(String postName); + // ========== 数据同步专用接口 ========== + + void syncPost(PostSaveReqVO syncReqVO); + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java index ff0aa7b4..9dcf31e2 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java @@ -191,4 +191,25 @@ public class PostServiceImpl implements PostService { return createPost(createReqVO); } + + // ========== 数据同步专用接口 ========== + + @Override + public void syncPost(PostSaveReqVO syncReqVO) { + if (syncReqVO.getId() == null) { + return; + } + + PostDO existingPost = postMapper.selectById(syncReqVO.getId()); + PostDO post = BeanUtils.toBean(syncReqVO, PostDO.class); + + if (existingPost != null) { + postMapper.updateById(post); + } else { + if (post.getStatus() == null) { + post.setStatus(CommonStatusEnum.ENABLE.getStatus()); + } + postMapper.insert(post); + } + } } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java index 382a15fd..5ca6e39c 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java @@ -212,4 +212,8 @@ public interface AdminUserService { */ boolean isPasswordMatch(AdminUserDO user, String rawPassword); + // ========== 数据同步专用接口 ========== + + void syncUser(UserSaveReqVO syncReqVO); + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java index 93058b6f..cd4480c4 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java @@ -725,4 +725,48 @@ public class AdminUserServiceImpl implements AdminUserService { return StrUtil.isNotBlank(value) && value.startsWith("$2"); } + // ========== 数据同步专用接口 ========== + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncUser(UserSaveReqVO syncReqVO) { + if (syncReqVO.getId() == null) { + log.warn("[syncUser] 同步用户失败,ID 不能为空"); + return; + } + + // 检查用户是否存在 + AdminUserDO existingUser = userMapper.selectById(syncReqVO.getId()); + + // 转换为 DO(只同步用户主表,不处理关联关系) + AdminUserDO user = BeanUtils.toBean(syncReqVO, AdminUserDO.class); + user.setDeptIds(null); // 部门关联单独同步 + user.setPostIds(null); // 岗位关联单独同步 + + if (existingUser != null) { + // 用户存在,执行更新(不更新密码) + user.setPassword(null); + userMapper.updateById(user); + log.info("[syncUser] 用户同步-更新成功, userId={}, username={}", user.getId(), user.getUsername()); + } else { + // 用户不存在,执行插入 + // 设置默认状态 + if (user.getStatus() == null) { + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); + } + // 设置默认用户来源 + if (user.getUserSource() == null) { + user.setUserSource(UserSourceEnum.EXTERNAL.getSource()); + } + // 如果没有密码,设置默认密码 + if (StrUtil.isBlank(user.getPassword())) { + user.setPassword(passwordEncoder.encode("123456")); + } + userMapper.insert(user); + log.info("[syncUser] 用户同步-创建成功, userId={}, username={}", user.getId(), user.getUsername()); + } + + // 注意:不发布变更事件,避免循环同步 + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java index 378637eb..26c728b7 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java @@ -76,5 +76,8 @@ public interface UserDeptService { */ void batchCreateUserDept(List createReqVOList); + // ========== 数据同步专用接口 ========== + + void syncUserDept(UserDeptDO syncReqVO); } \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java index 3b699c91..8c71a020 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java @@ -155,4 +155,22 @@ public class UserDeptServiceImpl implements UserDeptService { } } -} \ No newline at end of file + // ========== 数据同步专用接口 ========== + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncUserDept(UserDeptDO syncReqVO) { + if (syncReqVO.getId() == null) { + return; + } + + UserDeptDO existing = userDeptMapper.selectById(syncReqVO.getId()); + + if (existing != null) { + userDeptMapper.updateById(syncReqVO); + } else { + userDeptMapper.insert(syncReqVO); + } + } + +} From 2dc0de96a347e42b3422a9070efc9aede3e7f7b9 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Wed, 24 Dec 2025 10:41:51 +0800 Subject: [PATCH 21/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-framework/zt-spring-boot-starter-databus-client/pom.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zt-framework/zt-spring-boot-starter-databus-client/pom.xml b/zt-framework/zt-spring-boot-starter-databus-client/pom.xml index 08e8dcc8..ce35f87e 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/pom.xml +++ b/zt-framework/zt-spring-boot-starter-databus-client/pom.xml @@ -46,14 +46,12 @@ com.zt.plat zt-spring-boot-starter-mq - - com.zt.plat - zt-spring-boot-starter-redis + zt-spring-boot-starter-biz-tenant - + org.springframework.boot spring-boot-starter-web From bf27ebd5ba4ccac413e66312fde67d0090b94676 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Wed, 24 Dec 2025 10:42:18 +0800 Subject: [PATCH 22/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-module-databus/zt-module-databus-server/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zt-module-databus/zt-module-databus-server/pom.xml b/zt-module-databus/zt-module-databus-server/pom.xml index e94168ad..ceec001c 100644 --- a/zt-module-databus/zt-module-databus-server/pom.xml +++ b/zt-module-databus/zt-module-databus-server/pom.xml @@ -185,6 +185,11 @@ 4.12.0 test + + com.zt.plat + zt-spring-boot-starter-databus-client + ${revision} + From 2baede83e50085d13d35bcdd6796fb1ec6b51ac7 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Wed, 17 Dec 2025 11:31:57 +0800 Subject: [PATCH 23/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=9F=E4=BA=A7topic?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zt/plat/module/databus/enums/DatabusEventType.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java index 80886ad3..679bfa49 100644 --- a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java +++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/enums/DatabusEventType.java @@ -311,11 +311,14 @@ public enum DatabusEventType { } /** - * 获取完整Topic名称(服务端转发用) - * 格式: {topicBase}-{module}-{entity}-{action}-{clientCode} + * 获取完整Topic名称(服务端转发用 - 统一消费者架构) + *

+ * 新架构:所有事件类型都推送到同一个客户端 Topic,通过消息体中的 eventType 字段区分 + * 格式: {topicBase}-{clientCode} + * 示例: databus-sync-hwc-test */ public String getTopic(String topicBase, String clientCode) { - return String.format("%s-%s-%s-%s-%s", topicBase, module, entity, action, clientCode); + return String.format("%s-%s", topicBase, clientCode); } /** From 9b0e63a33e519f540345bd136d1cba57dfb8d79f Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 22 Dec 2025 09:51:05 +0800 Subject: [PATCH 24/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../provider/UserDeptDataFeignProvider.java | 81 ++++++++++ .../provider/UserPostDataFeignProvider.java | 81 ++++++++++ .../provider/DatabusUserDeptProviderApi.java | 71 ++++++++ .../provider/DatabusUserPostProviderApi.java | 71 ++++++++ .../rpc/config/RpcConfiguration.java | 9 +- .../DatabusUserDeptProviderApiImpl.java | 151 ++++++++++++++++++ .../DatabusUserPostProviderApiImpl.java | 139 ++++++++++++++++ .../module/system/api/dept/PostApiImpl.java | 4 + 8 files changed, 604 insertions(+), 3 deletions(-) create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java create mode 100644 zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java create mode 100644 zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java new file mode 100644 index 00000000..81f3bcf2 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserDeptDataFeignProvider.java @@ -0,0 +1,81 @@ +package com.zt.plat.framework.databus.server.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.databus.server.core.provider.DataProvider; +import com.zt.plat.framework.databus.server.core.provider.DataProviderRegistry; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * 用户-部门关系数据提供者 + */ +@Slf4j +@Component +public class UserDeptDataFeignProvider implements DataProvider { + + public static final String PROVIDER_TYPE = "USER_DEPT"; + + @Resource + private DatabusUserDeptProviderApi userDeptProviderApi; + + @Resource + private DataProviderRegistry dataProviderRegistry; + + @PostConstruct + public void init() { + dataProviderRegistry.register(this); + } + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public CursorPageData getPageByCursor(LocalDateTime cursorTime, Long cursorId, + int batchSize, Long tenantId) { + CursorPageReqDTO reqDTO = CursorPageReqDTO.builder() + .cursorTime(cursorTime) + .cursorId(cursorId) + .batchSize(batchSize) + .tenantId(tenantId) + .build(); + + CommonResult> result = userDeptProviderApi.getPageByCursor(reqDTO); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-部门关系数据失败: " + result.getMsg()); + } + + CursorPageResult pageResult = result.getData(); + return CursorPageData.of( + pageResult.getList(), + pageResult.getNextCursorTime(), + pageResult.getNextCursorId(), + pageResult.getCount(), + Boolean.TRUE.equals(pageResult.getHasMore()), + (pageResult.getTotal() != null ? pageResult.getTotal() : 0L) + ); + } + + @Override + public long count(Long tenantId) { + CommonResult result = userDeptProviderApi.count(tenantId); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-部门关系总数失败: " + result.getMsg()); + } + return result.getData(); + } + + @Override + public Long extractUid(DatabusUserDeptData data) { + return data.getId(); + } +} diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java new file mode 100644 index 00000000..b7df241a --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/provider/UserPostDataFeignProvider.java @@ -0,0 +1,81 @@ +package com.zt.plat.framework.databus.server.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.databus.server.core.provider.DataProvider; +import com.zt.plat.framework.databus.server.core.provider.DataProviderRegistry; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * 用户-岗位关系数据提供者 + */ +@Slf4j +@Component +public class UserPostDataFeignProvider implements DataProvider { + + public static final String PROVIDER_TYPE = "USER_POST"; + + @Resource + private DatabusUserPostProviderApi userPostProviderApi; + + @Resource + private DataProviderRegistry dataProviderRegistry; + + @PostConstruct + public void init() { + dataProviderRegistry.register(this); + } + + @Override + public String getProviderType() { + return PROVIDER_TYPE; + } + + @Override + public CursorPageData getPageByCursor(LocalDateTime cursorTime, Long cursorId, + int batchSize, Long tenantId) { + CursorPageReqDTO reqDTO = CursorPageReqDTO.builder() + .cursorTime(cursorTime) + .cursorId(cursorId) + .batchSize(batchSize) + .tenantId(tenantId) + .build(); + + CommonResult> result = userPostProviderApi.getPageByCursor(reqDTO); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-岗位关系数据失败: " + result.getMsg()); + } + + CursorPageResult pageResult = result.getData(); + return CursorPageData.of( + pageResult.getList(), + pageResult.getNextCursorTime(), + pageResult.getNextCursorId(), + pageResult.getCount(), + Boolean.TRUE.equals(pageResult.getHasMore()), + (pageResult.getTotal() != null ? pageResult.getTotal() : 0L) + ); + } + + @Override + public long count(Long tenantId) { + CommonResult result = userPostProviderApi.count(tenantId); + if (!result.isSuccess()) { + throw new RuntimeException("获取用户-岗位关系总数失败: " + result.getMsg()); + } + return result.getData(); + } + + @Override + public Long extractUid(DatabusUserPostData data) { + return data.getId(); + } +} diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java new file mode 100644 index 00000000..5e393626 --- /dev/null +++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserDeptProviderApi.java @@ -0,0 +1,71 @@ +package com.zt.plat.module.databus.api.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Databus 用户-部门关系数据提供者 API + *

+ * 供 Databus 调用,获取用户-部门关联数据用于全量/增量同步 + * + * @author ZT + */ +@FeignClient(name = "${databus.provider.user-dept.service:system-server}") +@Tag(name = "RPC 服务 - Databus 用户-部门关系数据提供者") +public interface DatabusUserDeptProviderApi { + + String PREFIX = "/rpc/databus/user-dept"; + + /** + * 游标分页查询用户-部门关系数据(用于全量同步) + * + * @param reqDTO 游标分页请求 + * @return 用户-部门关系数据分页结果 + */ + @PostMapping(PREFIX + "/page-by-cursor") + @Operation(summary = "游标分页查询用户-部门关系数据") + CommonResult> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO); + + /** + * 根据ID查询用户-部门关系详情(用于增量同步) + * + * @param id 关系ID + * @return 用户-部门关系数据 + */ + @GetMapping(PREFIX + "/get") + @Operation(summary = "查询用户-部门关系详情") + @Parameter(name = "id", description = "关系ID", required = true, example = "1001") + CommonResult getById(@RequestParam("id") Long id); + + /** + * 批量查询用户-部门关系详情(用于增量同步批量获取) + * + * @param ids 关系ID列表 + * @return 用户-部门关系数据列表 + */ + @GetMapping(PREFIX + "/list") + @Operation(summary = "批量查询用户-部门关系详情") + @Parameter(name = "ids", description = "关系ID列表", required = true, example = "1001,1002,1003") + CommonResult> getListByIds(@RequestParam("ids") List ids); + + /** + * 统计用户-部门关系总数(用于全量同步进度计算) + * + * @param tenantId 租户ID(可选) + * @return 用户-部门关系总数 + */ + @GetMapping(PREFIX + "/count") + @Operation(summary = "统计用户-部门关系总数") + @Parameter(name = "tenantId", description = "租户ID", example = "1") + CommonResult count(@RequestParam(value = "tenantId", required = false) Long tenantId); + +} diff --git a/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java new file mode 100644 index 00000000..6e00365d --- /dev/null +++ b/zt-module-databus/zt-module-databus-api/src/main/java/com/zt/plat/module/databus/api/provider/DatabusUserPostProviderApi.java @@ -0,0 +1,71 @@ +package com.zt.plat.module.databus.api.provider; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Databus 用户-岗位关系数据提供者 API + *

+ * 供 Databus 调用,获取用户-岗位关联数据用于全量/增量同步 + * + * @author ZT + */ +@FeignClient(name = "${databus.provider.user-post.service:system-server}") +@Tag(name = "RPC 服务 - Databus 用户-岗位关系数据提供者") +public interface DatabusUserPostProviderApi { + + String PREFIX = "/rpc/databus/user-post"; + + /** + * 游标分页查询用户-岗位关系数据(用于全量同步) + * + * @param reqDTO 游标分页请求 + * @return 用户-岗位关系数据分页结果 + */ + @PostMapping(PREFIX + "/page-by-cursor") + @Operation(summary = "游标分页查询用户-岗位关系数据") + CommonResult> getPageByCursor(@RequestBody CursorPageReqDTO reqDTO); + + /** + * 根据ID查询用户-岗位关系详情(用于增量同步) + * + * @param id 关系ID + * @return 用户-岗位关系数据 + */ + @GetMapping(PREFIX + "/get") + @Operation(summary = "查询用户-岗位关系详情") + @Parameter(name = "id", description = "关系ID", required = true, example = "1001") + CommonResult getById(@RequestParam("id") Long id); + + /** + * 批量查询用户-岗位关系详情(用于增量同步批量获取) + * + * @param ids 关系ID列表 + * @return 用户-岗位关系数据列表 + */ + @GetMapping(PREFIX + "/list") + @Operation(summary = "批量查询用户-岗位关系详情") + @Parameter(name = "ids", description = "关系ID列表", required = true, example = "1001,1002,1003") + CommonResult> getListByIds(@RequestParam("ids") List ids); + + /** + * 统计用户-岗位关系总数(用于全量同步进度计算) + * + * @param tenantId 租户ID(可选) + * @return 用户-岗位关系总数 + */ + @GetMapping(PREFIX + "/count") + @Operation(summary = "统计用户-岗位关系总数") + @Parameter(name = "tenantId", description = "租户ID", example = "1") + CommonResult count(@RequestParam(value = "tenantId", required = false) Long tenantId); + +} diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java index 32e911e1..c62e2b2d 100644 --- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java +++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java @@ -4,6 +4,8 @@ import com.zt.plat.framework.common.biz.system.oauth2.OAuth2TokenCommonApi; import com.zt.plat.module.databus.api.provider.DatabusDeptProviderApi; import com.zt.plat.module.databus.api.provider.DatabusPostProviderApi; import com.zt.plat.module.databus.api.provider.DatabusUserProviderApi; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.system.api.dept.PostApi; import com.zt.plat.module.system.api.user.AdminUserApi; @@ -21,9 +23,10 @@ import org.springframework.context.annotation.Configuration; DatabusDeptProviderApi.class, DatabusUserProviderApi.class, DatabusPostProviderApi.class, - PostApi.class, - DeptApi.class, - AdminUserApi.class, + DatabusUserDeptProviderApi.class, + DatabusUserPostProviderApi.class, + PostApi.class, + DeptApi.class, }) public class RpcConfiguration { } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java new file mode 100644 index 00000000..15b375eb --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -0,0 +1,151 @@ +package com.zt.plat.module.system.api.databus; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.provider.DatabusUserDeptProviderApi; +import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; +import com.zt.plat.module.system.dal.mysql.userdept.UserDeptMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * Databus 用户-部门关系数据提供者 API 实现 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderApi { + + @Resource + private UserDeptMapper userDeptMapper; + + @Override + public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { + // 构建游标查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) + if (!reqDTO.isFirstPage()) { + queryWrapper.and(w -> w + .gt(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) + .or(o -> o + .eq(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) + .gt(UserDeptDO::getId, reqDTO.getCursorId()) + ) + ); + } + + // 租户过滤(如果指定) + if (reqDTO.getTenantId() != null) { + queryWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); + } + + // 按 create_time, id 升序排列,确保顺序稳定 + queryWrapper.orderByAsc(UserDeptDO::getCreateTime) + .orderByAsc(UserDeptDO::getId); + + // 多查一条判断是否有更多数据 + int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; + queryWrapper.last("LIMIT " + (limit + 1)); + + List list = userDeptMapper.selectList(queryWrapper); + + // 判断是否有更多 + boolean hasMore = list.size() > limit; + if (hasMore) { + list = list.subList(0, limit); + } + + if (CollUtil.isEmpty(list)) { + return success(CursorPageResult.empty()); + } + + // 转换为同步数据 + List dataList = list.stream() + .map(this::convertToData) + .collect(Collectors.toList()); + + // 获取最后一条数据的游标 + UserDeptDO last = list.get(list.size() - 1); + + // 首次查询时返回总数 + Long total = null; + if (reqDTO.isFirstPage()) { + LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); + if (reqDTO.getTenantId() != null) { + countWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); + } + total = userDeptMapper.selectCount(countWrapper); + } + + return success(CursorPageResult.of( + dataList, + last.getCreateTime(), + last.getId(), + hasMore, + total + )); + } + + @Override + public CommonResult getById(Long id) { + UserDeptDO userDept = userDeptMapper.selectById(id); + if (userDept == null) { + return success(null); + } + return success(convertToData(userDept)); + } + + @Override + public CommonResult> getListByIds(List ids) { + if (CollUtil.isEmpty(ids)) { + return success(Collections.emptyList()); + } + + List list = userDeptMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + return success(list.stream() + .map(this::convertToData) + .collect(Collectors.toList())); + } + + @Override + public CommonResult count(Long tenantId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if (tenantId != null) { + queryWrapper.eq(UserDeptDO::getTenantId, tenantId); + } + return success(userDeptMapper.selectCount(queryWrapper)); + } + + /** + * 将 UserDeptDO 转换为 DatabusUserDeptData + */ + private DatabusUserDeptData convertToData(UserDeptDO userDept) { + return DatabusUserDeptData.builder() + .id(userDept.getId()) + .userId(userDept.getUserId()) + .deptId(userDept.getDeptId()) + .tenantId(userDept.getTenantId()) + .remark(userDept.getRemark()) + .build(); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java new file mode 100644 index 00000000..96db8704 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java @@ -0,0 +1,139 @@ +package com.zt.plat.module.system.api.databus; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.databus.api.dto.CursorPageReqDTO; +import com.zt.plat.module.databus.api.dto.CursorPageResult; +import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; +import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; +import com.zt.plat.module.system.dal.mysql.dept.UserPostMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * Databus 用户-岗位关系数据提供者 API 实现 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderApi { + + @Resource + private UserPostMapper userPostMapper; + + @Override + public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { + // 构建游标查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) + if (!reqDTO.isFirstPage()) { + queryWrapper.and(w -> w + .gt(UserPostDO::getCreateTime, reqDTO.getCursorTime()) + .or(o -> o + .eq(UserPostDO::getCreateTime, reqDTO.getCursorTime()) + .gt(UserPostDO::getId, reqDTO.getCursorId()) + ) + ); + } + + // 注意:UserPostDO 没有租户字段,忽略 tenantId 过滤 + + // 按 create_time, id 升序排列,确保顺序稳定 + queryWrapper.orderByAsc(UserPostDO::getCreateTime) + .orderByAsc(UserPostDO::getId); + + // 多查一条判断是否有更多数据 + int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; + queryWrapper.last("LIMIT " + (limit + 1)); + + List list = userPostMapper.selectList(queryWrapper); + + // 判断是否有更多 + boolean hasMore = list.size() > limit; + if (hasMore) { + list = list.subList(0, limit); + } + + if (CollUtil.isEmpty(list)) { + return success(CursorPageResult.empty()); + } + + // 转换为同步数据 + List dataList = list.stream() + .map(this::convertToData) + .collect(Collectors.toList()); + + // 获取最后一条数据的游标 + UserPostDO last = list.get(list.size() - 1); + + // 首次查询时返回总数 + Long total = null; + if (reqDTO.isFirstPage()) { + total = userPostMapper.selectCount(new LambdaQueryWrapper<>()); + } + + return success(CursorPageResult.of( + dataList, + last.getCreateTime(), + last.getId(), + hasMore, + total + )); + } + + @Override + public CommonResult getById(Long id) { + UserPostDO userPost = userPostMapper.selectById(id); + if (userPost == null) { + return success(null); + } + return success(convertToData(userPost)); + } + + @Override + public CommonResult> getListByIds(List ids) { + if (CollUtil.isEmpty(ids)) { + return success(Collections.emptyList()); + } + + List list = userPostMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + return success(list.stream() + .map(this::convertToData) + .collect(Collectors.toList())); + } + + @Override + public CommonResult count(Long tenantId) { + // 注意:UserPostDO 没有租户字段,返回全量总数 + return success(userPostMapper.selectCount(new LambdaQueryWrapper<>())); + } + + /** + * 将 UserPostDO 转换为 DatabusUserPostData + */ + private DatabusUserPostData convertToData(UserPostDO userPost) { + return DatabusUserPostData.builder() + .id(userPost.getId()) + .userId(userPost.getUserId()) + .postId(userPost.getPostId()) + .build(); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java index 40c7e22b..97cf029e 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java @@ -10,6 +10,7 @@ import com.zt.plat.module.system.controller.admin.dept.vo.post.PostSaveReqVO; import com.zt.plat.module.system.dal.dataobject.dept.PostDO; import com.zt.plat.module.system.service.dept.PostService; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -20,6 +21,7 @@ import java.util.List; import static com.zt.plat.framework.common.pojo.CommonResult.success; +@Slf4j @RestController // 提供 RESTful API 接口,给 Feign 调用 @Validated public class PostApiImpl implements PostApi { @@ -36,6 +38,7 @@ public class PostApiImpl implements PostApi { @Override public CommonResult updatePost(PostSaveReqDTO updateReqVO) { + log.error("ssssssssss"); PostSaveReqVO reqVO = BeanUtils.toBean(updateReqVO, PostSaveReqVO.class); postService.updatePost(reqVO); return success(true); @@ -49,6 +52,7 @@ public class PostApiImpl implements PostApi { @Override public CommonResult getPost(Long id) { + log.error("cccccccc"+id); PostDO post = postService.getPost(id); return success(BeanUtils.toBean(post, PostRespDTO.class)); } From 7ef5545dc03cee9dcfb94bf15b20b791a0add029 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 22 Dec 2025 11:03:15 +0800 Subject: [PATCH 25/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../userdept/UserDeptSyncServiceImpl.java | 85 ++++++++++++++----- .../userpost/UserPostSyncServiceImpl.java | 84 +++++++++++++----- .../consumer/DatabusUserChangeConsumer.java | 10 ++- .../rpc/config/RpcConfiguration.java | 4 + .../system/api/userdept/UserDeptApi.java | 64 ++++++++++++++ .../api/userdept/dto/UserDeptRespDTO.java | 31 +++++++ .../api/userdept/dto/UserDeptSaveReqDTO.java | 26 ++++++ .../system/api/userpost/UserPostApi.java | 64 ++++++++++++++ .../api/userpost/dto/UserPostRespDTO.java | 28 ++++++ .../api/userpost/dto/UserPostSaveReqDTO.java | 23 +++++ .../DatabusUserDeptProviderApiImpl.java | 48 +++-------- .../DatabusUserPostProviderApiImpl.java | 36 +++----- .../databus/DatabusUserProviderApiImpl.java | 7 ++ .../system/dal/mysql/dept/UserPostMapper.java | 43 ++++++++++ .../dal/mysql/userdept/UserDeptMapper.java | 43 ++++++++++ 15 files changed, 494 insertions(+), 102 deletions(-) create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java index 9027e379..04f16ae4 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java @@ -1,56 +1,101 @@ package com.zt.plat.framework.databus.client.handler.userdept; import com.zt.plat.module.databus.api.data.DatabusUserDeptData; +import com.zt.plat.module.system.api.userdept.UserDeptApi; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; /** - * 用户-部门关系同步服务实现 + * 用户-部门关系同步服务实现(通过 Feign API 调用远程服务) *

* 使用条件: * 1. zt.databus.sync.client.enabled=true + * 2. 系统中存在 UserDeptApi 接口(Feign 客户端) *

- * 注意:由于用户-部门关系通常集成在用户管理中,此实现为占位符。 - * 分公司可以根据实际情况: - * 1. 自定义实现此接口,直接操作本地数据库 - * 2. 或者通过用户管理 API 间接处理关联关系 + * 如果分公司需要自定义实现,可以创建自己的 UserDeptSyncService Bean, + * 此默认实现会自动失效(@ConditionalOnMissingBean) * * @author ZT */ @Slf4j @Service @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") +@ConditionalOnClass(name = "com.zt.plat.module.system.api.userdept.UserDeptApi") public class UserDeptSyncServiceImpl implements UserDeptSyncService { + @Autowired(required = false) + private UserDeptApi userDeptApi; // Feign 远程调用接口 + @Override public void create(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到创建用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,通过本地 API 或直接数据库操作完成同步 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过创建用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系创建成功, userId={}, deptId={}", data.getUserId(), data.getDeptId()); } @Override public void update(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到更新用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过更新用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + userDeptApi.updateUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系更新成功, userId={}, deptId={}", data.getUserId(), data.getDeptId()); } @Override public void delete(Long id) { - log.info("[UserDeptSync] 收到删除用户-部门关系请求, id={}", id); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过删除用户-部门关系, id={}", id); + return; + } + userDeptApi.deleteUserDept(id).checkError(); + log.info("[UserDeptSync] 用户-部门关系删除成功, id={}", id); } @Override public void fullSync(DatabusUserDeptData data) { - log.info("[UserDeptSync] 收到全量同步用户-部门关系请求, userId={}, deptId={}", - data.getUserId(), data.getDeptId()); - log.warn("[UserDeptSync] 用户-部门关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,逻辑:存在则更新,不存在则插入 + if (userDeptApi == null) { + log.warn("[UserDeptSync] UserDeptApi未注入,跳过全量同步用户-部门关系, userId={}", data.getUserId()); + return; + } + UserDeptSaveReqDTO dto = buildUserDeptDTO(data); + try { + // 尝试获取,存在则更新,不存在则创建 + var existing = userDeptApi.getUserDept(dto.getId()); + if (existing.isSuccess() && existing.getData() != null) { + userDeptApi.updateUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-更新成功, id={}", dto.getId()); + } else { + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + } + } catch (Exception e) { + // 获取失败,尝试创建 + log.warn("[UserDeptSync] 用户-部门关系获取失败,尝试创建, id={}", dto.getId()); + userDeptApi.createUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + } + } + + /** + * 构建用户部门关系 DTO(用于 Feign 调用) + */ + private UserDeptSaveReqDTO buildUserDeptDTO(DatabusUserDeptData data) { + UserDeptSaveReqDTO dto = new UserDeptSaveReqDTO(); + dto.setId(data.getId()); + dto.setUserId(data.getUserId()); + dto.setDeptId(data.getDeptId()); + dto.setRemark(data.getRemark()); + return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java index b41d6ac8..01eb2b4b 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java @@ -1,56 +1,100 @@ package com.zt.plat.framework.databus.client.handler.userpost; import com.zt.plat.module.databus.api.data.DatabusUserPostData; +import com.zt.plat.module.system.api.userpost.UserPostApi; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; /** - * 用户-岗位关系同步服务实现 + * 用户-岗位关系同步服务实现(通过 Feign API 调用远程服务) *

* 使用条件: * 1. zt.databus.sync.client.enabled=true + * 2. 系统中存在 UserPostApi 接口(Feign 客户端) *

- * 注意:由于用户-岗位关系通常集成在用户管理中,此实现为占位符。 - * 分公司可以根据实际情况: - * 1. 自定义实现此接口,直接操作本地数据库 - * 2. 或者通过用户管理 API 间接处理关联关系 + * 如果分公司需要自定义实现,可以创建自己的 UserPostSyncService Bean, + * 此默认实现会自动失效(@ConditionalOnMissingBean) * * @author ZT */ @Slf4j @Service @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") +@ConditionalOnClass(name = "com.zt.plat.module.system.api.userpost.UserPostApi") public class UserPostSyncServiceImpl implements UserPostSyncService { + @Autowired(required = false) + private UserPostApi userPostApi; // Feign 远程调用接口 + @Override public void create(DatabusUserPostData data) { - log.info("[UserPostSync] 收到创建用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,通过本地 API 或直接数据库操作完成同步 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过创建用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系创建成功, userId={}, postId={}", data.getUserId(), data.getPostId()); } @Override public void update(DatabusUserPostData data) { - log.info("[UserPostSync] 收到更新用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过更新用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + userPostApi.updateUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系更新成功, userId={}, postId={}", data.getUserId(), data.getPostId()); } @Override public void delete(Long id) { - log.info("[UserPostSync] 收到删除用户-岗位关系请求, id={}", id); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过删除用户-岗位关系, id={}", id); + return; + } + userPostApi.deleteUserPost(id).checkError(); + log.info("[UserPostSync] 用户-岗位关系删除成功, id={}", id); } @Override public void fullSync(DatabusUserPostData data) { - log.info("[UserPostSync] 收到全量同步用户-岗位关系请求, userId={}, postId={}", - data.getUserId(), data.getPostId()); - log.warn("[UserPostSync] 用户-岗位关系同步服务需要分公司自定义实现,当前为占位符实现"); - // TODO: 分公司需要实现此方法,逻辑:存在则更新,不存在则插入 + if (userPostApi == null) { + log.warn("[UserPostSync] UserPostApi未注入,跳过全量同步用户-岗位关系, userId={}", data.getUserId()); + return; + } + UserPostSaveReqDTO dto = buildUserPostDTO(data); + try { + // 尝试获取,存在则更新,不存在则创建 + var existing = userPostApi.getUserPost(dto.getId()); + if (existing.isSuccess() && existing.getData() != null) { + userPostApi.updateUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-更新成功, id={}", dto.getId()); + } else { + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + } + } catch (Exception e) { + // 获取失败,尝试创建 + log.warn("[UserPostSync] 用户-岗位关系获取失败,尝试创建, id={}", dto.getId()); + userPostApi.createUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + } + } + + /** + * 构建用户岗位关系 DTO(用于 Feign 调用) + */ + private UserPostSaveReqDTO buildUserPostDTO(DatabusUserPostData data) { + UserPostSaveReqDTO dto = new UserPostSaveReqDTO(); + dto.setId(data.getId()); + dto.setUserId(data.getUserId()); + dto.setPostId(data.getPostId()); + return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java index dd3a52e0..43fd8e97 100644 --- a/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java +++ b/zt-framework/zt-spring-boot-starter-databus-server/src/main/java/com/zt/plat/framework/databus/server/consumer/DatabusUserChangeConsumer.java @@ -34,7 +34,15 @@ public class DatabusUserChangeConsumer implements RocketMQListener dataMap = new HashMap<>(); diff --git a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java index c62e2b2d..d79beb52 100644 --- a/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java +++ b/zt-module-databus/zt-module-databus-server/src/main/java/com/zt/plat/module/databus/framework/rpc/config/RpcConfiguration.java @@ -9,6 +9,8 @@ import com.zt.plat.module.databus.api.provider.DatabusUserPostProviderApi; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.system.api.dept.PostApi; import com.zt.plat.module.system.api.user.AdminUserApi; +import com.zt.plat.module.system.api.userdept.UserDeptApi; +import com.zt.plat.module.system.api.userpost.UserPostApi; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Configuration; @@ -27,6 +29,8 @@ import org.springframework.context.annotation.Configuration; DatabusUserPostProviderApi.class, PostApi.class, DeptApi.class, + UserDeptApi.class, + UserPostApi.class, }) public class RpcConfiguration { } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java new file mode 100644 index 00000000..d48c6b69 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java @@ -0,0 +1,64 @@ +package com.zt.plat.module.system.api.userdept; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.system.api.userdept.dto.UserDeptRespDTO; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; +import com.zt.plat.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.List; + +/** + * 用户-部门关系 Feign API + * + * @author ZT + */ +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 用户部门关系") +public interface UserDeptApi { + + String PREFIX = ApiConstants.PREFIX + "/user-dept"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增用户部门关系") + CommonResult createUserDept(@RequestBody UserDeptSaveReqDTO reqVO); + + @PutMapping(PREFIX + "/update") + @Operation(summary = "修改用户部门关系") + CommonResult updateUserDept(@RequestBody UserDeptSaveReqDTO reqVO); + + @DeleteMapping(PREFIX + "/delete") + @Operation(summary = "删除用户部门关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult deleteUserDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "通过ID查询用户部门关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult getUserDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list-by-user-id") + @Operation(summary = "通过用户ID查询用户部门关系列表") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult> getUserDeptListByUserId(@RequestParam("userId") Long userId); + + @GetMapping(PREFIX + "/list-by-dept-id") + @Operation(summary = "通过部门ID查询用户部门关系列表") + @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) + CommonResult> getUserDeptListByDeptId(@RequestParam("deptId") Long deptId); + + @DeleteMapping(PREFIX + "/delete-by-user-id") + @Operation(summary = "通过用户ID删除用户部门关系") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult deleteUserDeptByUserId(@RequestParam("userId") Long userId); + + @DeleteMapping(PREFIX + "/delete-by-dept-id") + @Operation(summary = "通过部门ID删除用户部门关系") + @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) + CommonResult deleteUserDeptByDeptId(@RequestParam("deptId") Long deptId); +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java new file mode 100644 index 00000000..5a558b90 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptRespDTO.java @@ -0,0 +1,31 @@ +package com.zt.plat.module.system.api.userdept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户部门关系 Response DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户部门关系 Response DTO") +@Data +public class UserDeptRespDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "部门编号", example = "100") + private Long deptId; + + @Schema(description = "备注", example = "主部门") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java new file mode 100644 index 00000000..b18f2a56 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/dto/UserDeptSaveReqDTO.java @@ -0,0 +1,26 @@ +package com.zt.plat.module.system.api.userdept.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户部门关系创建/修改 Request DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户部门关系创建/修改 Request DTO") +@Data +public class UserDeptSaveReqDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1", required = true) + private Long userId; + + @Schema(description = "部门编号", example = "100", required = true) + private Long deptId; + + @Schema(description = "备注", example = "主部门") + private String remark; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java new file mode 100644 index 00000000..a58e09cb --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java @@ -0,0 +1,64 @@ +package com.zt.plat.module.system.api.userpost; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.system.api.userpost.dto.UserPostRespDTO; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; +import com.zt.plat.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.Collection; +import java.util.List; + +/** + * 用户-岗位关系 Feign API + * + * @author ZT + */ +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 用户岗位关系") +public interface UserPostApi { + + String PREFIX = ApiConstants.PREFIX + "/user-post"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增用户岗位关系") + CommonResult createUserPost(@RequestBody UserPostSaveReqDTO reqVO); + + @PutMapping(PREFIX + "/update") + @Operation(summary = "修改用户岗位关系") + CommonResult updateUserPost(@RequestBody UserPostSaveReqDTO reqVO); + + @DeleteMapping(PREFIX + "/delete") + @Operation(summary = "删除用户岗位关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult deleteUserPost(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "通过ID查询用户岗位关系") + @Parameter(name = "id", description = "关系编号", example = "1", required = true) + CommonResult getUserPost(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list-by-user-id") + @Operation(summary = "通过用户ID查询用户岗位关系列表") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult> getUserPostListByUserId(@RequestParam("userId") Long userId); + + @GetMapping(PREFIX + "/list-by-post-id") + @Operation(summary = "通过岗位ID查询用户岗位关系列表") + @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) + CommonResult> getUserPostListByPostId(@RequestParam("postId") Long postId); + + @DeleteMapping(PREFIX + "/delete-by-user-id") + @Operation(summary = "通过用户ID删除用户岗位关系") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult deleteUserPostByUserId(@RequestParam("userId") Long userId); + + @DeleteMapping(PREFIX + "/delete-by-post-id") + @Operation(summary = "通过岗位ID删除用户岗位关系") + @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) + CommonResult deleteUserPostByPostId(@RequestParam("postId") Long postId); +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java new file mode 100644 index 00000000..e7251a61 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostRespDTO.java @@ -0,0 +1,28 @@ +package com.zt.plat.module.system.api.userpost.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户岗位关系 Response DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户岗位关系 Response DTO") +@Data +public class UserPostRespDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "岗位编号", example = "100") + private Long postId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java new file mode 100644 index 00000000..4ad5af68 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/dto/UserPostSaveReqDTO.java @@ -0,0 +1,23 @@ +package com.zt.plat.module.system.api.userpost.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 用户岗位关系创建/修改 Request DTO + * + * @author ZT + */ +@Schema(description = "RPC 服务 - 用户岗位关系创建/修改 Request DTO") +@Data +public class UserPostSaveReqDTO { + + @Schema(description = "关系编号", example = "1024") + private Long id; + + @Schema(description = "用户编号", example = "1", required = true) + private Long userId; + + @Schema(description = "岗位编号", example = "100", required = true) + private Long postId; +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java index 15b375eb..3a461df9 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -35,34 +35,16 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { - // 构建游标查询条件 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) - if (!reqDTO.isFirstPage()) { - queryWrapper.and(w -> w - .gt(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) - .or(o -> o - .eq(UserDeptDO::getCreateTime, reqDTO.getCursorTime()) - .gt(UserDeptDO::getId, reqDTO.getCursorId()) - ) - ); - } - - // 租户过滤(如果指定) - if (reqDTO.getTenantId() != null) { - queryWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); - } - - // 按 create_time, id 升序排列,确保顺序稳定 - queryWrapper.orderByAsc(UserDeptDO::getCreateTime) - .orderByAsc(UserDeptDO::getId); - // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - queryWrapper.last("LIMIT " + (limit + 1)); - List list = userDeptMapper.selectList(queryWrapper); + // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的部门关系 + List list = userDeptMapper.selectPageByCursorWithUserSource( + reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), + reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), + reqDTO.getTenantId(), + limit + 1 + ); // 判断是否有更多 boolean hasMore = list.size() > limit; @@ -82,14 +64,11 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp // 获取最后一条数据的游标 UserDeptDO last = list.get(list.size() - 1); - // 首次查询时返回总数 + // 首次查询时返���总数 Long total = null; if (reqDTO.isFirstPage()) { - LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); - if (reqDTO.getTenantId() != null) { - countWrapper.eq(UserDeptDO::getTenantId, reqDTO.getTenantId()); - } - total = userDeptMapper.selectCount(countWrapper); + // ⚠️ 只统计 userSource = 2 的用户的部门关系 + total = userDeptMapper.countWithUserSource(reqDTO.getTenantId()); } return success(CursorPageResult.of( @@ -128,11 +107,8 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult count(Long tenantId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - if (tenantId != null) { - queryWrapper.eq(UserDeptDO::getTenantId, tenantId); - } - return success(userDeptMapper.selectCount(queryWrapper)); + // ⚠️ 只统计 userSource = 2 的用户的部门关系 + return success(userDeptMapper.countWithUserSource(tenantId)); } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java index 96db8704..faabe471 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserPostProviderApiImpl.java @@ -35,31 +35,16 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp @Override public CommonResult> getPageByCursor(CursorPageReqDTO reqDTO) { - // 构建游标查询条件 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) - if (!reqDTO.isFirstPage()) { - queryWrapper.and(w -> w - .gt(UserPostDO::getCreateTime, reqDTO.getCursorTime()) - .or(o -> o - .eq(UserPostDO::getCreateTime, reqDTO.getCursorTime()) - .gt(UserPostDO::getId, reqDTO.getCursorId()) - ) - ); - } - - // 注意:UserPostDO 没有租户字段,忽略 tenantId 过滤 - - // 按 create_time, id 升序排列,确保顺序稳定 - queryWrapper.orderByAsc(UserPostDO::getCreateTime) - .orderByAsc(UserPostDO::getId); - // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - queryWrapper.last("LIMIT " + (limit + 1)); - List list = userPostMapper.selectList(queryWrapper); + // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的岗位关系 + List list = userPostMapper.selectPageByCursorWithUserSource( + reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), + reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), + reqDTO.getTenantId(), + limit + 1 + ); // 判断是否有更多 boolean hasMore = list.size() > limit; @@ -82,7 +67,8 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp // 首次查询时返回总数 Long total = null; if (reqDTO.isFirstPage()) { - total = userPostMapper.selectCount(new LambdaQueryWrapper<>()); + // ⚠️ 只统计 userSource = 2 的用户的岗位关系 + total = userPostMapper.countWithUserSource(reqDTO.getTenantId()); } return success(CursorPageResult.of( @@ -121,8 +107,8 @@ public class DatabusUserPostProviderApiImpl implements DatabusUserPostProviderAp @Override public CommonResult count(Long tenantId) { - // 注意:UserPostDO 没有租户字段,返回全量总数 - return success(userPostMapper.selectCount(new LambdaQueryWrapper<>())); + // ⚠️ 只统计 userSource = 2 的用户的岗位关系 + return success(userPostMapper.countWithUserSource(tenantId)); } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java index 286b9984..f6b9050a 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserProviderApiImpl.java @@ -54,6 +54,9 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { // 构建游标查询条件 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只同步 userSource = 2 的用户 + queryWrapper.eq(AdminUserDO::getUserSource, 2); + // 游标条件:create_time > cursorTime OR (create_time = cursorTime AND id > cursorId) if (!reqDTO.isFirstPage()) { queryWrapper.and(w -> w @@ -100,6 +103,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { Long total = null; if (reqDTO.isFirstPage()) { LambdaQueryWrapper countWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只统计 userSource = 2 的用户 + countWrapper.eq(AdminUserDO::getUserSource, 2); if (reqDTO.getTenantId() != null) { countWrapper.eq(AdminUserDO::getTenantId, reqDTO.getTenantId()); } @@ -143,6 +148,8 @@ public class DatabusUserProviderApiImpl implements DatabusUserProviderApi { @Override public CommonResult count(Long tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // ⚠️ 只统计 userSource = 2 的用户 + queryWrapper.eq(AdminUserDO::getUserSource, 2); if (tenantId != null) { queryWrapper.eq(AdminUserDO::getTenantId, tenantId); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java index fa9bd6aa..2df5c891 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/UserPostMapper.java @@ -5,7 +5,10 @@ import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX; import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -29,4 +32,44 @@ public interface UserPostMapper extends BaseMapperX { default void deleteByUserId(Long userId) { delete(Wrappers.lambdaUpdate(UserPostDO.class).eq(UserPostDO::getUserId, userId)); } + + /** + * 游标分页查询用户-岗位关系(只查询 userSource = 2 的用户) + * @param cursorTime 游标时间 + * @param cursorId 游标ID + * @param tenantId 租户ID(可选) + * @param limit 限制数量 + * @return 用户岗位关系列表 + */ + @Select("") + List selectPageByCursorWithUserSource(@Param("cursorTime") LocalDateTime cursorTime, + @Param("cursorId") Long cursorId, + @Param("tenantId") Long tenantId, + @Param("limit") Integer limit); + + /** + * 统计用户-岗位关系数量(只统计 userSource = 2 的用户) + * @param tenantId 租户ID(可选) + * @return 数量 + */ + @Select("") + Long countWithUserSource(@Param("tenantId") Long tenantId); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java index b9aad69a..bf21f41d 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/userdept/UserDeptMapper.java @@ -4,7 +4,10 @@ import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX; import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX; import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import java.time.LocalDateTime; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -45,4 +48,44 @@ public interface UserDeptMapper extends BaseMapperX { ); } + /** + * 游标分页查询用户-部门关系(只查询 userSource = 2 的用户) + * @param cursorTime 游标时间 + * @param cursorId 游标ID + * @param tenantId 租户ID(可选) + * @param limit 限制数量 + * @return 用户部门关系列表 + */ + @Select("") + List selectPageByCursorWithUserSource(@Param("cursorTime") LocalDateTime cursorTime, + @Param("cursorId") Long cursorId, + @Param("tenantId") Long tenantId, + @Param("limit") Integer limit); + + /** + * 统计用户-部门关系数量(只统计 userSource = 2 的用户) + * @param tenantId 租户ID(可选) + * @return 数量 + */ + @Select("") + Long countWithUserSource(@Param("tenantId") Long tenantId); + } \ No newline at end of file From 7f54e7f07df30695c2fd29b06d35e082dbc67be9 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Tue, 23 Dec 2025 18:20:42 +0800 Subject: [PATCH 26/48] =?UTF-8?q?update=EF=BC=9A=E5=8D=87=E7=BA=A7seata?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=88=B02.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-dependencies/pom.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/zt-dependencies/pom.xml b/zt-dependencies/pom.xml index b0a132d9..a519b38d 100644 --- a/zt-dependencies/pom.xml +++ b/zt-dependencies/pom.xml @@ -32,6 +32,7 @@ 3.4.5 2024.0.1 2023.0.3.2 + 2.4.0 2.8.3 4.6.0 @@ -132,6 +133,18 @@ import + + + org.apache.seata + seata-all + ${seata.version} + + + org.apache.seata + seata-spring-boot-starter + ${seata.version} + + io.github.mouzt From 516198ab53d12253839530614e41388d203378ee Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Wed, 24 Dec 2025 10:36:00 +0800 Subject: [PATCH 27/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/consumer/DatabusClientConsumer.java | 7 +- .../handler/dept/DeptSyncServiceImpl.java | 25 ++--- .../handler/post/PostSyncServiceImpl.java | 23 +--- .../user/AdminUserSyncServiceImpl.java | 19 +--- .../userdept/UserDeptSyncServiceImpl.java | 19 +--- .../userpost/UserPostSyncServiceImpl.java | 19 +--- .../plat/module/system/api/dept/DeptApi.java | 6 + .../plat/module/system/api/dept/PostApi.java | 6 + .../system/api/dept/dto/DeptSaveReqDTO.java | 15 +++ .../module/system/api/user/AdminUserApi.java | 6 + .../api/user/dto/AdminUserSaveReqDTO.java | 6 + .../system/api/userdept/UserDeptApi.java | 6 + .../system/api/userpost/UserPostApi.java | 6 + .../DatabusUserDeptProviderApiImpl.java | 6 +- .../module/system/api/dept/DeptApiImpl.java | 9 ++ .../module/system/api/dept/PostApiImpl.java | 8 +- .../system/api/user/AdminUserApiImpl.java | 7 ++ .../system/api/userdept/UserDeptApiImpl.java | 88 +++++++++++++++ .../system/api/userpost/UserPostApiImpl.java | 106 ++++++++++++++++++ .../system/dal/mysql/dept/DeptMapper.java | 7 +- .../system/service/dept/DeptService.java | 11 ++ .../system/service/dept/DeptServiceImpl.java | 37 ++++++ .../system/service/dept/PostService.java | 4 + .../system/service/dept/PostServiceImpl.java | 21 ++++ .../system/service/user/AdminUserService.java | 4 + .../service/user/AdminUserServiceImpl.java | 44 ++++++++ .../service/userdept/UserDeptService.java | 3 + .../service/userdept/UserDeptServiceImpl.java | 20 +++- 28 files changed, 460 insertions(+), 78 deletions(-) create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java index 4a7c5cdb..0000776e 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/core/consumer/DatabusClientConsumer.java @@ -13,7 +13,7 @@ import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; - +import com.zt.plat.framework.tenant.core.context.TenantContextHolder; /** * DataBus 客户端统一消费者 *

@@ -33,8 +33,8 @@ import org.springframework.stereotype.Component; @Component @ConditionalOnProperty(prefix = "zt.databus.sync.client", name = "enabled", havingValue = "true") @RocketMQMessageListener( - topic = "${zt.databus.sync.client.mq.topic:databus-sync}-${zt.databus.sync.client.client-code}", - consumerGroup = "${zt.databus.sync.client.mq.consumer-group:databus-client-consumer}-${zt.databus.sync.client.client-code}" + topic = "${zt.databus.sync.client.mq.topic-base:databus-sync}-${zt.databus.sync.client.client-code}", + consumerGroup = "${zt.databus.sync.client.mq.consumer-group-prefix:databus-client-consumer}-${zt.databus.sync.client.client-code}" ) public class DatabusClientConsumer implements RocketMQListener { @@ -46,6 +46,7 @@ public class DatabusClientConsumer implements RocketMQListener { log.debug("[DatabusClient] 收到消息, body={}", body); try { + TenantContextHolder.setTenantId(1L); // 1. 解析消息获取 eventType DatabusEventType eventType = parseEventType(body); if (eventType == null) { diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java index ca760435..00d9913a 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/dept/DeptSyncServiceImpl.java @@ -69,21 +69,15 @@ public class DeptSyncServiceImpl implements DeptSyncService { return; } DeptSaveReqDTO dto = buildDeptDTO(data); + + // 使用专用同步接口,跳过业务校验,直接 upsert try { - // 尝试获取,存在则更新,不存在则创建 - var existing = deptApi.getDept(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - deptApi.updateDept(dto).checkError(); - log.info("[DeptSync] 部门全量同步-更新成功, deptId={}", dto.getId()); - } else { - deptApi.createDept(dto).checkError(); - log.info("[DeptSync] 部门全量同步-创建成功, deptId={}", dto.getId()); - } + deptApi.syncDept(dto).checkError(); + log.info("[DeptSync] 部门全量同步成功, deptId={}, deptName={}", dto.getId(), dto.getName()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[DeptSync] 部门获取失败,尝试创建, deptId={}", dto.getId()); - deptApi.createDept(dto).checkError(); - log.info("[DeptSync] 部门全量同步-创建成功, deptId={}", dto.getId()); + log.error("[DeptSync] 部门全量同步失败, deptId={}, deptName={}, parentId={}, code={}, error={}", + dto.getId(), dto.getName(), dto.getParentId(), dto.getCode(), e.getMessage()); + throw e; } } @@ -93,13 +87,18 @@ public class DeptSyncServiceImpl implements DeptSyncService { private DeptSaveReqDTO buildDeptDTO(DatabusDeptData data) { DeptSaveReqDTO dto = new DeptSaveReqDTO(); dto.setId(data.getId()); + dto.setCode(data.getCode()); // ⚠️ 重要:传递编码,保持一致 dto.setName(data.getName()); + dto.setShortName(data.getShortName()); dto.setParentId(data.getParentId()); dto.setSort(data.getSort()); dto.setLeaderUserId(data.getLeaderUserId()); dto.setPhone(data.getPhone()); dto.setEmail(data.getEmail()); dto.setStatus(data.getStatus()); + dto.setIsGroup(data.getIsGroup()); + dto.setIsCompany(data.getIsCompany()); + dto.setDeptSource(data.getDeptSource()); return dto; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java index 463fdc6e..6ad68f2e 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/post/PostSyncServiceImpl.java @@ -68,25 +68,14 @@ public class PostSyncServiceImpl implements PostSyncService { return; } PostSaveReqDTO dto = buildPostDTO(data); + try { - // 尝试获取,存在则更新,不存在则创建 - var existing = postApi.getPost(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - postApi.updatePost(dto).checkError(); - log.info("[PostSync] 岗位全量同步-更新成功, postId={}, postName={}", dto.getId(), dto.getName()); - } else { - postApi.createPost(dto).checkError(); - log.info("[PostSync] 岗位全量同步-创建成功, postId={}, postName={}", dto.getId(), dto.getName()); - } + postApi.syncPost(dto).checkError(); + log.info("[PostSync] 岗位全量同步成功, postId={}, postName={}", dto.getId(), dto.getName()); } catch (Exception e) { - // 获取失败,尝试创建 - try { - postApi.createPost(dto).checkError(); - log.info("[PostSync] 岗位全量同步-创建成功, postId={}, postName={}", dto.getId(), dto.getName()); - } catch (Exception createEx) { - log.error("[PostSync] 岗位全量同步失败, postId={}, postName={}", dto.getId(), dto.getName(), createEx); - throw createEx; - } + log.error("[PostSync] 岗位全量同步失败, postId={}, postName={}, code={}, error={}", + dto.getId(), dto.getName(), dto.getCode(), e.getMessage()); + throw e; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java index d40cfd51..a0b239df 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/user/AdminUserSyncServiceImpl.java @@ -72,21 +72,14 @@ public class AdminUserSyncServiceImpl implements AdminUserSyncService { return; } AdminUserSaveReqDTO dto = buildUserDTO(data); + try { - // 尝试获取,存在则更新,不存在则创建 - var existing = adminUserApi.getUser(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - adminUserApi.updateUser(dto).checkError(); - log.info("[UserSync] 用户全量同步-更新成功, userId={}", dto.getId()); - } else { - adminUserApi.createUser(dto).checkError(); - log.info("[UserSync] 用户全量同步-创建成功, userId={}", dto.getId()); - } + adminUserApi.syncUser(dto).checkError(); + log.info("[UserSync] 用户全量同步成功, userId={}, username={}", dto.getId(), dto.getUsername()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[UserSync] 用户获取失败,尝试创建, userId={}", dto.getId()); - adminUserApi.createUser(dto).checkError(); - log.info("[UserSync] 用户全量同步-创建成功, userId={}", dto.getId()); + log.error("[UserSync] 用户全量同步失败, userId={}, username={}, error={}", + dto.getId(), dto.getUsername(), e.getMessage()); + throw e; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java index 04f16ae4..36914af0 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userdept/UserDeptSyncServiceImpl.java @@ -70,20 +70,13 @@ public class UserDeptSyncServiceImpl implements UserDeptSyncService { } UserDeptSaveReqDTO dto = buildUserDeptDTO(data); try { - // 尝试获取,存在则更新,不存在则创建 - var existing = userDeptApi.getUserDept(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - userDeptApi.updateUserDept(dto).checkError(); - log.info("[UserDeptSync] 用户-部门关系全量同步-更新成功, id={}", dto.getId()); - } else { - userDeptApi.createUserDept(dto).checkError(); - log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); - } + userDeptApi.syncUserDept(dto).checkError(); + log.info("[UserDeptSync] 用户-部门关系全量同步成功, id={}, userId={}, deptId={}", + dto.getId(), dto.getUserId(), dto.getDeptId()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[UserDeptSync] 用户-部门关系获取失败,尝试创建, id={}", dto.getId()); - userDeptApi.createUserDept(dto).checkError(); - log.info("[UserDeptSync] 用户-部门关系全量同步-创建成功, id={}", dto.getId()); + log.error("[UserDeptSync] 用户-部门关系全量同步失败, id={}, userId={}, deptId={}, error={}", + dto.getId(), dto.getUserId(), dto.getDeptId(), e.getMessage()); + throw e; } } diff --git a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java index 01eb2b4b..47251092 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java +++ b/zt-framework/zt-spring-boot-starter-databus-client/src/main/java/com/zt/plat/framework/databus/client/handler/userpost/UserPostSyncServiceImpl.java @@ -70,20 +70,13 @@ public class UserPostSyncServiceImpl implements UserPostSyncService { } UserPostSaveReqDTO dto = buildUserPostDTO(data); try { - // 尝试获取,存在则更新,不存在则创建 - var existing = userPostApi.getUserPost(dto.getId()); - if (existing.isSuccess() && existing.getData() != null) { - userPostApi.updateUserPost(dto).checkError(); - log.info("[UserPostSync] 用户-岗位关系全量同步-更新成功, id={}", dto.getId()); - } else { - userPostApi.createUserPost(dto).checkError(); - log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); - } + userPostApi.syncUserPost(dto).checkError(); + log.info("[UserPostSync] 用户-岗位关系全量同步成功, id={}, userId={}, postId={}", + dto.getId(), dto.getUserId(), dto.getPostId()); } catch (Exception e) { - // 获取失败,尝试创建 - log.warn("[UserPostSync] 用户-岗位关系获取失败,尝试创建, id={}", dto.getId()); - userPostApi.createUserPost(dto).checkError(); - log.info("[UserPostSync] 用户-岗位关系全量同步-创建成功, id={}", dto.getId()); + log.error("[UserPostSync] 用户-岗位关系全量同步失败, id={}, userId={}, postId={}, error={}", + dto.getId(), dto.getUserId(), dto.getPostId(), e.getMessage()); + throw e; } } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java index eea5499e..abc53972 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/DeptApi.java @@ -86,4 +86,10 @@ public interface DeptApi { @Parameter(name = "userId", description = "用户编号", example = "1", required = true) CommonResult> getCompanyDeptInfoListByUserId(@RequestParam("userId") Long userId); + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步部门") + CommonResult syncDept(@RequestBody DeptSaveReqDTO syncReqDTO); + } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java index fed71544..4ef8bd45 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/PostApi.java @@ -64,4 +64,10 @@ public interface PostApi { return CollectionUtils.convertMap(list, PostRespDTO::getId); } + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步岗位") + CommonResult syncPost(@RequestBody PostSaveReqDTO syncReqDTO); + } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java index fbb311cc..b01a712d 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/dept/dto/DeptSaveReqDTO.java @@ -15,9 +15,15 @@ public class DeptSaveReqDTO { @Schema(description = "部门编号", example = "1024") private Long id; + @Schema(description = "部门编码", example = "ZT001") + private String code; + @Schema(description = "部门名称", example = "ZT") private String name; + @Schema(description = "部门简称", example = "技术") + private String shortName; + @Schema(description = "父部门 ID", example = "1024") private Long parentId; @@ -36,6 +42,15 @@ public class DeptSaveReqDTO { @Schema(description = "状态,见 CommonStatusEnum 枚举0 开启 1 关闭", example = "0") private Integer status; + @Schema(description = "是否集团", example = "false") + private Boolean isGroup; + + @Schema(description = "是否公司", example = "false") + private Boolean isCompany; + + @Schema(description = "部门来源类型", example = "1") + private Integer deptSource; + @Schema(description = "外部系统标识,用于建立编码映射", example = "ERP") private String externalSystemCode; diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java index 02443415..293608b8 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/AdminUserApi.java @@ -104,6 +104,12 @@ public interface AdminUserApi extends AutoTransable { @Parameter(name = "ids", description = "用户编号数组", example = "3,5", required = true) CommonResult validateUserList(@RequestParam("ids") Collection ids); + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步用户") + CommonResult syncUser(@RequestBody AdminUserSaveReqDTO syncReqDTO); + @Override @FeignIgnore default List selectByIds(List ids) { diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java index 4e4a30c2..691f5204 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/user/dto/AdminUserSaveReqDTO.java @@ -50,4 +50,10 @@ public class AdminUserSaveReqDTO { @Schema(description = "密码", example = "123456") private String password; + @Schema(description = "工号", example = "A00123") + private String workcode; + + @Schema(description = "用户来源类型", example = "1") + private Integer userSource; + } \ No newline at end of file diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java index d48c6b69..050216ae 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApi.java @@ -61,4 +61,10 @@ public interface UserDeptApi { @Operation(summary = "通过部门ID删除用户部门关系") @Parameter(name = "deptId", description = "部门编号", example = "1", required = true) CommonResult deleteUserDeptByDeptId(@RequestParam("deptId") Long deptId); + + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步用户部门关系") + CommonResult syncUserDept(@RequestBody UserDeptSaveReqDTO syncReqDTO); } diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java index a58e09cb..d72e4706 100644 --- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApi.java @@ -61,4 +61,10 @@ public interface UserPostApi { @Operation(summary = "通过岗位ID删除用户岗位关系") @Parameter(name = "postId", description = "岗位编号", example = "1", required = true) CommonResult deleteUserPostByPostId(@RequestParam("postId") Long postId); + + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步用户岗位关系") + CommonResult syncUserPost(@RequestBody UserPostSaveReqDTO syncReqDTO); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java index 3a461df9..efbe2e1d 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/databus/DatabusUserDeptProviderApiImpl.java @@ -38,7 +38,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp // 多查一条判断是否有更多数据 int limit = reqDTO.getBatchSize() != null ? reqDTO.getBatchSize() : 100; - // ⚠️ 使用关联查询,只查询 userSource = 2 的用户的部门关系 + // 查询用户部门关系 List list = userDeptMapper.selectPageByCursorWithUserSource( reqDTO.isFirstPage() ? null : reqDTO.getCursorTime(), reqDTO.isFirstPage() ? null : reqDTO.getCursorId(), @@ -67,7 +67,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp // 首次查询时返���总数 Long total = null; if (reqDTO.isFirstPage()) { - // ⚠️ 只统计 userSource = 2 的用户的部门关系 + // 统计用户部门关系 total = userDeptMapper.countWithUserSource(reqDTO.getTenantId()); } @@ -107,7 +107,7 @@ public class DatabusUserDeptProviderApiImpl implements DatabusUserDeptProviderAp @Override public CommonResult count(Long tenantId) { - // ⚠️ 只统计 userSource = 2 的用户的部门关系 + // 统计用户部门关系 return success(userDeptMapper.countWithUserSource(tenantId)); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java index d06b79a6..bed2d2b6 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/DeptApiImpl.java @@ -107,4 +107,13 @@ public class DeptApiImpl implements DeptApi { return success(BeanUtils.toBean(companyDeptInfos, CompanyDeptInfoRespDTO.class)); } + // ========== 数据同步专用接口 ========== + + @Override + public CommonResult syncDept(DeptSaveReqDTO syncReqDTO) { + DeptSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, DeptSaveReqVO.class); + deptService.syncDept(reqVO); + return success(true); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java index 97cf029e..bb760ec4 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/dept/PostApiImpl.java @@ -38,7 +38,6 @@ public class PostApiImpl implements PostApi { @Override public CommonResult updatePost(PostSaveReqDTO updateReqVO) { - log.error("ssssssssss"); PostSaveReqVO reqVO = BeanUtils.toBean(updateReqVO, PostSaveReqVO.class); postService.updatePost(reqVO); return success(true); @@ -76,4 +75,11 @@ public class PostApiImpl implements PostApi { return success(BeanUtils.toBean(list, PostRespDTO.class)); } + @Override + public CommonResult syncPost(PostSaveReqDTO syncReqDTO) { + PostSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, PostSaveReqVO.class); + postService.syncPost(reqVO); + return success(true); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java index a80db06e..523e432a 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/user/AdminUserApiImpl.java @@ -149,4 +149,11 @@ public class AdminUserApiImpl implements AdminUserApi { return success(true); } + @Override + public CommonResult syncUser(AdminUserSaveReqDTO syncReqDTO) { + UserSaveReqVO reqVO = BeanUtils.toBean(syncReqDTO, UserSaveReqVO.class); + userService.syncUser(reqVO); + return success(true); + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java new file mode 100644 index 00000000..91b30187 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userdept/UserDeptApiImpl.java @@ -0,0 +1,88 @@ +package com.zt.plat.module.system.api.userdept; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.util.object.BeanUtils; +import com.zt.plat.module.system.api.userdept.dto.UserDeptRespDTO; +import com.zt.plat.module.system.api.userdept.dto.UserDeptSaveReqDTO; +import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO; +import com.zt.plat.module.system.service.userdept.UserDeptService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * 用户-部门关系 API 实现类 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class UserDeptApiImpl implements UserDeptApi { + + @Resource + private UserDeptService userDeptService; + + @Override + public CommonResult createUserDept(UserDeptSaveReqDTO reqVO) { + UserDeptDO userDept = BeanUtils.toBean(reqVO, UserDeptDO.class); + Long id = userDeptService.createUserDept(userDept); + return success(id); + } + + @Override + public CommonResult updateUserDept(UserDeptSaveReqDTO reqVO) { + UserDeptDO userDept = BeanUtils.toBean(reqVO, UserDeptDO.class); + userDeptService.updateUserDept(userDept); + return success(true); + } + + @Override + public CommonResult deleteUserDept(Long id) { + userDeptService.deleteUserDept(id); + return success(true); + } + + @Override + public CommonResult getUserDept(Long id) { + UserDeptDO userDept = userDeptService.getUserDept(id); + return success(BeanUtils.toBean(userDept, UserDeptRespDTO.class)); + } + + @Override + public CommonResult> getUserDeptListByUserId(Long userId) { + List list = userDeptService.getValidUserDeptListByUserIds(List.of(userId)); + return success(BeanUtils.toBean(list, UserDeptRespDTO.class)); + } + + @Override + public CommonResult> getUserDeptListByDeptId(Long deptId) { + List list = userDeptService.getValidUserDeptListByDeptIds(List.of(deptId)); + return success(BeanUtils.toBean(list, UserDeptRespDTO.class)); + } + + @Override + public CommonResult deleteUserDeptByUserId(Long userId) { + userDeptService.deleteUserDeptByUserId(userId); + return success(true); + } + + @Override + public CommonResult deleteUserDeptByDeptId(Long deptId) { + // 需要实现此方法,暂时返回成功 + return success(true); + } + + @Override + public CommonResult syncUserDept(UserDeptSaveReqDTO syncReqDTO) { + UserDeptDO userDept = BeanUtils.toBean(syncReqDTO, UserDeptDO.class); + userDeptService.syncUserDept(userDept); + return success(true); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java new file mode 100644 index 00000000..1ee2db26 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/userpost/UserPostApiImpl.java @@ -0,0 +1,106 @@ +package com.zt.plat.module.system.api.userpost; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.util.object.BeanUtils; +import com.zt.plat.module.system.api.userpost.dto.UserPostRespDTO; +import com.zt.plat.module.system.api.userpost.dto.UserPostSaveReqDTO; +import com.zt.plat.module.system.dal.dataobject.dept.UserPostDO; +import com.zt.plat.module.system.dal.mysql.dept.UserPostMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +/** + * 用户-岗位关系 API 实现类 + * + * @author ZT + */ +@Slf4j +@RestController +@Validated +public class UserPostApiImpl implements UserPostApi { + + @Resource + private UserPostMapper userPostMapper; + + @Override + public CommonResult createUserPost(UserPostSaveReqDTO reqVO) { + UserPostDO userPost = BeanUtils.toBean(reqVO, UserPostDO.class); + userPostMapper.insert(userPost); + return success(userPost.getId()); + } + + @Override + public CommonResult updateUserPost(UserPostSaveReqDTO reqVO) { + UserPostDO userPost = BeanUtils.toBean(reqVO, UserPostDO.class); + userPostMapper.updateById(userPost); + return success(true); + } + + @Override + public CommonResult deleteUserPost(Long id) { + userPostMapper.deleteById(id); + return success(true); + } + + @Override + public CommonResult getUserPost(Long id) { + UserPostDO userPost = userPostMapper.selectById(id); + return success(BeanUtils.toBean(userPost, UserPostRespDTO.class)); + } + + @Override + public CommonResult> getUserPostListByUserId(Long userId) { + List list = userPostMapper.selectListByUserId(userId); + return success(BeanUtils.toBean(list, UserPostRespDTO.class)); + } + + @Override + public CommonResult> getUserPostListByPostId(Long postId) { + List list = userPostMapper.selectListByPostIds(List.of(postId)); + return success(BeanUtils.toBean(list, UserPostRespDTO.class)); + } + + @Override + public CommonResult deleteUserPostByUserId(Long userId) { + userPostMapper.deleteByUserId(userId); + return success(true); + } + + @Override + public CommonResult deleteUserPostByPostId(Long postId) { + userPostMapper.delete(UserPostDO::getPostId, postId); + return success(true); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public CommonResult syncUserPost(UserPostSaveReqDTO syncReqDTO) { + if (syncReqDTO.getId() == null) { + return success(false); + } + + UserPostDO existing = userPostMapper.selectById(syncReqDTO.getId()); + UserPostDO userPost = BeanUtils.toBean(syncReqDTO, UserPostDO.class); + + if (existing != null) { + userPostMapper.updateById(userPost); + log.info("[syncUserPost] 用户岗位关系同步-更新成功, id={}, userId={}, postId={}", + userPost.getId(), userPost.getUserId(), userPost.getPostId()); + } else { + userPostMapper.insert(userPost); + log.info("[syncUserPost] 用户岗位关系同步-创建成功, id={}, userId={}, postId={}", + userPost.getId(), userPost.getUserId(), userPost.getPostId()); + } + + return success(true); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java index fbd7c2c0..b030665c 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/DeptMapper.java @@ -124,12 +124,17 @@ public interface DeptMapper extends BaseMapperX { /** * 根据部门编码查询部门 + *

+ * 注意:如果存在多条相同编码的记录,只返回第一条 * * @param code 部门编码 * @return 部门信息 */ default DeptDO selectByCode(String code) { - return selectOne(DeptDO::getCode, code); + List list = selectList(new LambdaQueryWrapperX() + .eq(DeptDO::getCode, code) + .last("LIMIT 1")); + return CollUtil.isNotEmpty(list) ? list.get(0) : null; } /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java index c97510df..3996eef8 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptService.java @@ -174,4 +174,15 @@ public interface DeptService { * @return 部门列表 */ List searchDeptTree(String keyword); + + /** + * 回填缺失的部门编码(不触发事件)。 + * + * @param deptIds 需要回填的部门 ID 列表 + */ + void backfillMissingCodesWithoutEvent(Collection deptIds); + + // ========== 数据同步专用接口 ========== + + void syncDept(DeptSaveReqVO syncReqVO); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java index 7a4e6bbe..edfb3267 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/DeptServiceImpl.java @@ -802,4 +802,41 @@ public class DeptServiceImpl implements DeptService { } } + // ========== 数据同步专用接口 ========== + + @Override + @Transactional(rollbackFor = Exception.class) + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, allEntries = true) + @DataPermission(enable = false) + public void syncDept(DeptSaveReqVO syncReqVO) { + if (syncReqVO.getId() == null) { + log.warn("[syncDept] 同步部门失败,ID 不能为空"); + return; + } + // 标准化父部门 ID + syncReqVO.setParentId(normalizeParentId(syncReqVO.getParentId())); + // 默认部门来源 + if (syncReqVO.getDeptSource() == null) { + syncReqVO.setDeptSource(DeptSourceEnum.EXTERNAL.getSource()); + } + + // 检查部门是否存在 + DeptDO existingDept = deptMapper.selectById(syncReqVO.getId()); + + // 转换为 DO + DeptDO dept = BeanUtils.toBean(syncReqVO, DeptDO.class); + + if (existingDept != null) { + // 部门存在,执行更新 + deptMapper.updateById(dept); + log.info("[syncDept] 部门同步-更新成功, deptId={}, deptName={}", dept.getId(), dept.getName()); + } else { + // 部门不存在,执行插入 + deptMapper.insert(dept); + log.info("[syncDept] 部门同步-创建成功, deptId={}, deptName={}", dept.getId(), dept.getName()); + } + + // 注意:不发布变更事件,避免循环同步 + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java index 4ece87ea..153c7fd3 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostService.java @@ -89,4 +89,8 @@ public interface PostService { */ Long getOrCreatePostByName(String postName); + // ========== 数据同步专用接口 ========== + + void syncPost(PostSaveReqVO syncReqVO); + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java index ff0aa7b4..9dcf31e2 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/PostServiceImpl.java @@ -191,4 +191,25 @@ public class PostServiceImpl implements PostService { return createPost(createReqVO); } + + // ========== 数据同步专用接口 ========== + + @Override + public void syncPost(PostSaveReqVO syncReqVO) { + if (syncReqVO.getId() == null) { + return; + } + + PostDO existingPost = postMapper.selectById(syncReqVO.getId()); + PostDO post = BeanUtils.toBean(syncReqVO, PostDO.class); + + if (existingPost != null) { + postMapper.updateById(post); + } else { + if (post.getStatus() == null) { + post.setStatus(CommonStatusEnum.ENABLE.getStatus()); + } + postMapper.insert(post); + } + } } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java index 967f3161..4244e9cf 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserService.java @@ -208,4 +208,8 @@ public interface AdminUserService { */ boolean isPasswordMatch(AdminUserDO user, String rawPassword); + // ========== 数据同步专用接口 ========== + + void syncUser(UserSaveReqVO syncReqVO); + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java index b9126216..1fb85004 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/user/AdminUserServiceImpl.java @@ -725,4 +725,48 @@ public class AdminUserServiceImpl implements AdminUserService { return StrUtil.isNotBlank(value) && value.startsWith("$2"); } + // ========== 数据同步专用接口 ========== + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncUser(UserSaveReqVO syncReqVO) { + if (syncReqVO.getId() == null) { + log.warn("[syncUser] 同步用户失败,ID 不能为空"); + return; + } + + // 检查用户是否存在 + AdminUserDO existingUser = userMapper.selectById(syncReqVO.getId()); + + // 转换为 DO(只同步用户主表,不处理关联关系) + AdminUserDO user = BeanUtils.toBean(syncReqVO, AdminUserDO.class); + user.setDeptIds(null); // 部门关联单独同步 + user.setPostIds(null); // 岗位关联单独同步 + + if (existingUser != null) { + // 用户存在,执行更新(不更新密码) + user.setPassword(null); + userMapper.updateById(user); + log.info("[syncUser] 用户同步-更新成功, userId={}, username={}", user.getId(), user.getUsername()); + } else { + // 用户不存在,执行插入 + // 设置默认状态 + if (user.getStatus() == null) { + user.setStatus(CommonStatusEnum.ENABLE.getStatus()); + } + // 设置默认用户来源 + if (user.getUserSource() == null) { + user.setUserSource(UserSourceEnum.EXTERNAL.getSource()); + } + // 如果没有密码,设置默认密码 + if (StrUtil.isBlank(user.getPassword())) { + user.setPassword(passwordEncoder.encode("123456")); + } + userMapper.insert(user); + log.info("[syncUser] 用户同步-创建成功, userId={}, username={}", user.getId(), user.getUsername()); + } + + // 注意:不发布变更事件,避免循环同步 + } + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java index 378637eb..26c728b7 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptService.java @@ -76,5 +76,8 @@ public interface UserDeptService { */ void batchCreateUserDept(List createReqVOList); + // ========== 数据同步专用接口 ========== + + void syncUserDept(UserDeptDO syncReqVO); } \ No newline at end of file diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java index 3b699c91..8c71a020 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/userdept/UserDeptServiceImpl.java @@ -155,4 +155,22 @@ public class UserDeptServiceImpl implements UserDeptService { } } -} \ No newline at end of file + // ========== 数据同步专用接口 ========== + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncUserDept(UserDeptDO syncReqVO) { + if (syncReqVO.getId() == null) { + return; + } + + UserDeptDO existing = userDeptMapper.selectById(syncReqVO.getId()); + + if (existing != null) { + userDeptMapper.updateById(syncReqVO); + } else { + userDeptMapper.insert(syncReqVO); + } + } + +} From 01847264d5770fa453e5bfb74d0f8e2046ad1703 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Wed, 24 Dec 2025 10:41:51 +0800 Subject: [PATCH 28/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-framework/zt-spring-boot-starter-databus-client/pom.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zt-framework/zt-spring-boot-starter-databus-client/pom.xml b/zt-framework/zt-spring-boot-starter-databus-client/pom.xml index 08e8dcc8..ce35f87e 100644 --- a/zt-framework/zt-spring-boot-starter-databus-client/pom.xml +++ b/zt-framework/zt-spring-boot-starter-databus-client/pom.xml @@ -46,14 +46,12 @@ com.zt.plat zt-spring-boot-starter-mq - - com.zt.plat - zt-spring-boot-starter-redis + zt-spring-boot-starter-biz-tenant - + org.springframework.boot spring-boot-starter-web From 8823e316a0124d5daa677373e75c49c85535df81 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Wed, 24 Dec 2025 10:42:18 +0800 Subject: [PATCH 29/48] =?UTF-8?q?update=EF=BC=9A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7-?= =?UTF-8?q?=E9=83=A8=E9=97=A8=EF=BC=8C=E7=94=A8=E6=88=B7-=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E5=90=8C=E6=AD=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-module-databus/zt-module-databus-server/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zt-module-databus/zt-module-databus-server/pom.xml b/zt-module-databus/zt-module-databus-server/pom.xml index e94168ad..ceec001c 100644 --- a/zt-module-databus/zt-module-databus-server/pom.xml +++ b/zt-module-databus/zt-module-databus-server/pom.xml @@ -185,6 +185,11 @@ 4.12.0 test + + com.zt.plat + zt-spring-boot-starter-databus-client + ${revision} + From 89a047d28bd6861a6b7ebbac793306c212b924c4 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Wed, 24 Dec 2025 14:30:03 +0800 Subject: [PATCH 30/48] =?UTF-8?q?1.=20=E6=8F=90=E5=8D=87=20infra=20?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E4=B8=8A=E4=BC=A0=E7=9A=84=E9=99=84=E4=BB=B6?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zt-module-infra/zt-module-infra-server/src/main/resources/application.yaml b/zt-module-infra/zt-module-infra-server/src/main/resources/application.yaml index bbf43124..73104a95 100644 --- a/zt-module-infra/zt-module-infra-server/src/main/resources/application.yaml +++ b/zt-module-infra/zt-module-infra-server/src/main/resources/application.yaml @@ -32,8 +32,8 @@ spring: servlet: # 文件上传相关配置项 multipart: - max-file-size: 16MB # 单个文件大小 - max-request-size: 32MB # 设置总上传的文件大小 + max-file-size: 128MB # 单个文件大小 + max-request-size: 512MB # 设置总上传的文件大小 # Jackson 配置项 jackson: From 09c726d51bbeba2173caa361bd5dd7bf79a8e5cf Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 25 Dec 2025 10:46:45 +0800 Subject: [PATCH 31/48] =?UTF-8?q?1.=20=E9=81=BF=E5=85=8D=E6=97=A0=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E7=9A=84=E6=93=8D=E4=BD=9C=E6=97=A0=E6=B3=95=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E6=97=A5=E5=BF=97=E7=9A=84=E6=83=85=E5=86=B5=202.=20?= =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E7=99=BB=E5=BD=95=E5=8F=AF=E4=BB=A5=E4=B8=8D?= =?UTF-8?q?=E4=BC=A0=E9=80=92=E7=A7=9F=E6=88=B7=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 2 +- .../module/system/controller/admin/auth/AuthController.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index 42b3bd3d..1aa21a6d 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -1944,7 +1944,7 @@ COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 刷新令牌'; CREATE TABLE system_operate_log ( id bigint NOT NULL PRIMARY KEY, trace_id varchar(64) DEFAULT '' NULL, - user_id bigint NOT NULL, + user_id bigint NULL, user_type smallint DEFAULT 0 NOT NULL, type varchar(50) NOT NULL, sub_type varchar(50) NOT NULL, diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java index 510eb674..ca3fb848 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/auth/AuthController.java @@ -143,6 +143,7 @@ public class AuthController { @PostMapping("/sms-login") @PermitAll + @TenantIgnore @Operation(summary = "使用短信验证码登录") public CommonResult smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) { return success(authService.smsLogin(reqVO)); From e6fc24d3b174dc200d8cc56a5c21316a1dccee20 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 25 Dec 2025 17:29:45 +0800 Subject: [PATCH 32/48] =?UTF-8?q?1.=20=E7=9B=AE=E5=89=8D=E6=B6=89=E5=8F=8A?= =?UTF-8?q?=E5=88=B0=E5=A4=AA=E5=A4=9A=E6=B2=A1=E6=9C=89=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=E7=9A=84=E5=9C=BA=E6=99=AF=EF=BC=8C=E9=BB=98=E8=AE=A4=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E4=B8=BB=E7=A7=9F=E6=88=B7=E5=85=9C=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenant/core/context/TenantContextHolder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/TenantContextHolder.java b/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/TenantContextHolder.java index ac0b17aa..be8d66ca 100644 --- a/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/TenantContextHolder.java +++ b/zt-framework/zt-spring-boot-starter-biz-tenant/src/main/java/com/zt/plat/framework/tenant/core/context/TenantContextHolder.java @@ -1,7 +1,5 @@ package com.zt.plat.framework.tenant.core.context; -import cn.hutool.core.util.StrUtil; -import com.zt.plat.framework.common.enums.DocumentEnum; import com.alibaba.ttl.TransmittableThreadLocal; /** @@ -38,8 +36,10 @@ public class TenantContextHolder { public static Long getRequiredTenantId() { Long tenantId = getTenantId(); if (tenantId == null) { - throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:" - + DocumentEnum.TENANT.getUrl()); +// throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:" +// + DocumentEnum.TENANT.getUrl()); + // 暂定所有获取不到租户的操作,默认都使用主租户进行操作 1l + tenantId = 1L; } return tenantId; } From 666008e3c6ec36297d8558b16d7ac338dae7c596 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Thu, 25 Dec 2025 17:44:34 +0800 Subject: [PATCH 33/48] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E5=A4=8Dseata2.4?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=B8=8B=E8=BE=BE=E6=A2=A6=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E5=9B=9E=E6=BB=9A=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-dependencies/pom.xml | 6 + .../zt-spring-boot-starter-seata-dm/pom.xml | 32 ++ .../seata/rm/datasource/DataCompareUtils.java | 311 ++++++++++++++++++ 3 files changed, 349 insertions(+) create mode 100644 zt-framework/zt-spring-boot-starter-seata-dm/pom.xml create mode 100644 zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java diff --git a/zt-dependencies/pom.xml b/zt-dependencies/pom.xml index d9a30c74..e3e5f972 100644 --- a/zt-dependencies/pom.xml +++ b/zt-dependencies/pom.xml @@ -145,6 +145,12 @@ seata-spring-boot-starter ${seata.version} + + + com.zt.plat + zt-spring-boot-starter-seata-dm + ${revision} + diff --git a/zt-framework/zt-spring-boot-starter-seata-dm/pom.xml b/zt-framework/zt-spring-boot-starter-seata-dm/pom.xml new file mode 100644 index 00000000..49d7b1e2 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-seata-dm/pom.xml @@ -0,0 +1,32 @@ + + + + zt-framework + com.zt.plat + ${revision} + + 4.0.0 + jar + + zt-spring-boot-starter-seata-dm + + ${project.artifactId} + + Seata 达梦数据库补丁模块 + 解决 DmdbTimestamp 时区格式不一致导致的 dirty undo log 回滚失败问题 + 补丁来源: https://github.com/apache/incubator-seata/pull/7538 + Seata 2.6.0 发布后可移除此模块 + + + + + + org.apache.seata + seata-spring-boot-starter + provided + + + + diff --git a/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java b/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java new file mode 100644 index 00000000..2d596096 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java @@ -0,0 +1,311 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.seata.rm.datasource; + +import org.apache.seata.common.util.CollectionUtils; +import org.apache.seata.common.util.StringUtils; +import org.apache.seata.core.model.Result; +import org.apache.seata.rm.datasource.sql.struct.Field; +import org.apache.seata.rm.datasource.sql.struct.Row; +import org.apache.seata.rm.datasource.sql.struct.TableRecords; +import org.apache.seata.rm.datasource.undo.AbstractUndoLogManager; +import org.apache.seata.rm.datasource.undo.parser.FastjsonUndoLogParser; +import org.apache.seata.rm.datasource.undo.parser.JacksonUndoLogParser; +import org.apache.seata.sqlparser.struct.TableMeta; + +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * DataCompareUtils - 包含达梦数据库 DmdbTimestamp 时区问题的补丁 + *

+ * 此类覆盖 Seata 原有的 DataCompareUtils,添加了对达梦数据库 DmdbTimestamp 类型的特殊处理。 + * 通过将 DmdbTimestamp 转换为 UTC Instant 进行比较,解决时区格式不一致导致的 dirty undo log 问题。 + *

+ * 问题背景: + * - 达梦数据库的 DmdbTimestamp 类型在序列化/反序列化后时区格式不一致 + * - 例如:beforeImage 为 "2025-12-25 09:38:54.077811 +08:00" + * afterImage 为 "2025-12-25 09:38:54.077811" + * - 导致 Seata AT 模式回滚时 dirty undo log 检查失败 + *

+ * 解决方案: + * - 当检测到 DmdbTimestamp 类型时,将两个值都转换为 UTC Instant 进行比较 + * - 这样可以忽略时区格式差异,只比较实际的时间点 + *

+ * 补丁来源: https://github.com/apache/incubator-seata/pull/7538 + * 相关 Issue: https://github.com/apache/incubator-seata/issues/7453 + * 该修复已合并到 Seata 2.x 分支,将在 Seata 2.6.0 正式发布,届时可删除此模块。 + * + * @author Seata Community (PR #7538) + */ +public class DataCompareUtils { + + private DataCompareUtils() {} + + /** + * Is field equals result. + * + * @param f0 the f 0 + * @param f1 the f 1 + * @return the result + */ + public static Result isFieldEquals(Field f0, Field f1) { + if (f0 == null) { + return Result.build(f1 == null); + } else { + if (f1 == null) { + return Result.build(false); + } else { + if (StringUtils.equalsIgnoreCase(f0.getName(), f1.getName()) && f0.getType() == f1.getType()) { + if (f0.getValue() == null) { + return Result.build(f1.getValue() == null); + } else { + if (f1.getValue() == null) { + return Result.buildWithParams( + false, "Field not equals, name {}, new value is null", f0.getName()); + } else { + String currentSerializer = AbstractUndoLogManager.getCurrentSerializer(); + if (StringUtils.equals(currentSerializer, FastjsonUndoLogParser.NAME)) { + convertType(f0, f1); + } + // 达梦数据库 DmdbTimestamp 时区补丁 (PR #7538) + if (StringUtils.equals(currentSerializer, JacksonUndoLogParser.NAME)) { + Object v0 = f0.getValue(); + Object v1 = f1.getValue(); + if (isDmdbTimestamp(v0) && isDmdbTimestamp(v1)) { + Instant i0 = toInstant(v0); + Instant i1 = toInstant(v1); + boolean equals = Objects.equals(i0, i1); + return equals + ? Result.ok() + : Result.buildWithParams( + false, + "Field not equals (DmdbTimestamp), name {}, old value {}, new value {}", + f0.getName(), + v0, + v1); + } + } + boolean result = Objects.deepEquals(f0.getValue(), f1.getValue()); + if (result) { + return Result.ok(); + } else { + return Result.buildWithParams( + false, + "Field not equals, name {}, old value {}, new value {}", + f0.getName(), + f0.getValue(), + f1.getValue()); + } + } + } + } else { + return Result.buildWithParams( + false, + "Field not equals, old name {} type {}, new name {} type {}", + f0.getName(), + f0.getType(), + f1.getName(), + f1.getType()); + } + } + } + } + + private static void convertType(Field f0, Field f1) { + int f0Type = f0.getType(); + int f1Type = f1.getType(); + if (f0Type == Types.DATE && f0.getValue().getClass().equals(String.class)) { + String[] strings = f0.getValue().toString().split(" "); + f0.setValue(Date.valueOf(strings[0])); + } + if (f1Type == Types.DATE && f1.getValue().getClass().equals(String.class)) { + String[] strings = f1.getValue().toString().split(" "); + f1.setValue(Date.valueOf(strings[0])); + } + if (f0Type == Types.TIME && f0.getValue().getClass().equals(String.class)) { + f0.setValue(Time.valueOf(f0.getValue().toString())); + } + if (f1Type == Types.TIME && f1.getValue().getClass().equals(String.class)) { + f1.setValue(Time.valueOf(f1.getValue().toString())); + } + if (f0Type == Types.TIMESTAMP && f0.getValue().getClass().equals(String.class)) { + if (f1.getValue().getClass().equals(LocalDateTime.class)) { + f0.setValue(LocalDateTime.parse(f0.getValue().toString())); + } else { + f0.setValue(Timestamp.valueOf(f0.getValue().toString())); + } + } + if (f1Type == Types.TIMESTAMP && f1.getValue().getClass().equals(String.class)) { + f1.setValue(Timestamp.valueOf(f1.getValue().toString())); + } + if (f0Type == Types.DECIMAL && f0.getValue().getClass().equals(Integer.class)) { + f0.setValue(new BigDecimal(f0.getValue().toString())); + } + if (f1Type == Types.DECIMAL && f1.getValue().getClass().equals(Integer.class)) { + f1.setValue(new BigDecimal(f1.getValue().toString())); + } + if (f0Type == Types.BIGINT && f0.getValue().getClass().equals(Integer.class)) { + f0.setValue(Long.parseLong(f0.getValue().toString())); + } + if (f1Type == Types.BIGINT && f1.getValue().getClass().equals(Integer.class)) { + f1.setValue(Long.parseLong(f1.getValue().toString())); + } + } + + /** + * Is records equals result. + * + * @param beforeImage the before image + * @param afterImage the after image + * @return the result + */ + public static Result isRecordsEquals(TableRecords beforeImage, TableRecords afterImage) { + if (beforeImage == null) { + return Result.build(afterImage == null, null); + } else { + if (afterImage == null) { + return Result.build(false, null); + } + if (beforeImage.getTableName().equalsIgnoreCase(afterImage.getTableName()) + && CollectionUtils.isSizeEquals(beforeImage.getRows(), afterImage.getRows())) { + // when image is EmptyTableRecords, getTableMeta will throw an exception + if (CollectionUtils.isEmpty(beforeImage.getRows())) { + return Result.ok(); + } + return compareRows(beforeImage.getTableMeta(), beforeImage.getRows(), afterImage.getRows()); + } else { + return Result.build(false, null); + } + } + } + + /** + * Is rows equals result. + * + * @param tableMetaData the table meta data + * @param oldRows the old rows + * @param newRows the new rows + * @return the result + */ + public static Result isRowsEquals(TableMeta tableMetaData, List oldRows, List newRows) { + if (!CollectionUtils.isSizeEquals(oldRows, newRows)) { + return Result.build(false, null); + } + return compareRows(tableMetaData, oldRows, newRows); + } + + private static Result compareRows(TableMeta tableMetaData, List oldRows, List newRows) { + // old row to map + Map> oldRowsMap = rowListToMap(oldRows, tableMetaData.getPrimaryKeyOnlyName()); + // new row to map + Map> newRowsMap = rowListToMap(newRows, tableMetaData.getPrimaryKeyOnlyName()); + // compare data + for (Map.Entry> oldEntry : oldRowsMap.entrySet()) { + String key = oldEntry.getKey(); + Map oldRow = oldEntry.getValue(); + Map newRow = newRowsMap.get(key); + if (newRow == null) { + return Result.buildWithParams(false, "compare row failed, rowKey {}, reason [newRow is null]", key); + } + for (Map.Entry oldRowEntry : oldRow.entrySet()) { + String fieldName = oldRowEntry.getKey(); + Field oldField = oldRowEntry.getValue(); + Field newField = newRow.get(fieldName); + if (newField == null) { + return Result.buildWithParams( + false, + "compare row failed, rowKey {}, fieldName {}, reason [newField is null]", + key, + fieldName); + } + Result oldEqualsNewFieldResult = isFieldEquals(oldField, newField); + if (!oldEqualsNewFieldResult.getResult()) { + return oldEqualsNewFieldResult; + } + } + } + return Result.ok(); + } + + /** + * Row list to map map. + * + * @param rowList the row list + * @param primaryKeyList the primary key list + * @return the map + */ + public static Map> rowListToMap(List rowList, List primaryKeyList) { + // {value of primaryKey, value of all columns} + Map> rowMap = new HashMap<>(); + for (Row row : rowList) { + // ensure the order of column + List rowFieldList = row.getFields().stream() + .sorted(Comparator.comparing(Field::getName)) + .collect(Collectors.toList()); + // {uppercase fieldName : field} + Map colsMap = new HashMap<>(); + StringBuilder rowKey = new StringBuilder(); + boolean firstUnderline = false; + for (int j = 0; j < rowFieldList.size(); j++) { + Field field = rowFieldList.get(j); + if (primaryKeyList.stream().anyMatch(e -> field.getName().equals(e))) { + if (firstUnderline && j > 0) { + rowKey.append("_"); + } + rowKey.append(String.valueOf(field.getValue())); + firstUnderline = true; + } + colsMap.put(field.getName().trim().toUpperCase(), field); + } + rowMap.put(rowKey.toString(), colsMap); + } + return rowMap; + } + + /** + * 判断是否为达梦数据库的 DmdbTimestamp 类型 + */ + private static boolean isDmdbTimestamp(Object obj) { + return obj != null + && "dm.jdbc.driver.DmdbTimestamp".equals(obj.getClass().getName()); + } + + /** + * 将 DmdbTimestamp 转换为 Instant + */ + private static Instant toInstant(Object dmdbTimestamp) { + try { + Method toInstantMethod = dmdbTimestamp.getClass().getMethod("toInstant"); + return (Instant) toInstantMethod.invoke(dmdbTimestamp); + } catch (Exception e) { + throw new RuntimeException("Failed to convert DmdbTimestamp to Instant", e); + } + } +} From 91b54cc9d19b92781c84bdbde108f13f355527d8 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Thu, 25 Dec 2025 18:19:46 +0800 Subject: [PATCH 34/48] =?UTF-8?q?1.=20=E6=96=B0=E5=A2=9E=20seata=20?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=A8=A1=E5=9D=97=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-framework/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/zt-framework/pom.xml b/zt-framework/pom.xml index 241a211e..5eca3e83 100644 --- a/zt-framework/pom.xml +++ b/zt-framework/pom.xml @@ -33,6 +33,7 @@ zt-spring-boot-starter-biz-data-permission zt-spring-boot-starter-biz-ip zt-spring-boot-starter-biz-business + zt-spring-boot-starter-seata-dm zt-framework From 26e59522524d9f57f6cb3e226691db7d07649566 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Sat, 27 Dec 2025 12:26:27 +0800 Subject: [PATCH 35/48] =?UTF-8?q?1.=20=E4=B8=B4=E6=97=B6=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E9=9B=86=E7=BE=A4=E9=85=8D=E5=90=88=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deployment.yaml | 289 ++++++++++++++++++++---------------------- zt-gateway/Dockerfile | 2 +- 2 files changed, 141 insertions(+), 150 deletions(-) diff --git a/deployment.yaml b/deployment.yaml index f2e31e3e..3526660d 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -1,57 +1,57 @@ -## zt-gateway -#apiVersion: apps/v1 -#kind: Deployment -#metadata: -# namespace: ns-d6a0e78ebd674c279614498e4c57b133 -# name: zt-gateway -# labels: -# app: zt-gateway -#spec: -# replicas: 1 -# selector: -# matchLabels: -# app: zt-gateway -# template: -# metadata: -# labels: -# app: zt-gateway -# spec: -# containers: -# - name: zt-gateway -# image: 172.16.46.66:10043/zt/zt-gateway:VERSION_PLACEHOLDER -# imagePullPolicy: Always -# env: -# - name: TZ -# value: Asia/Shanghai -# ports: -# - containerPort: 48080 -# readinessProbe: -# httpGet: -# path: /actuator/health -# port: 48080 -# initialDelaySeconds: 50 -# periodSeconds: 5 -# failureThreshold: 3 -# livenessProbe: -# httpGet: -# path: /actuator/health -# port: 48080 -# initialDelaySeconds: 50 -# periodSeconds: 10 -# failureThreshold: 5 -# resources: -# requests: -# cpu: "500m" -# memory: "1024Mi" -# limits: -# cpu: "1024m" -# memory: "2048Mi" -# terminationGracePeriodSeconds: 30 -#--- +# zt-gateway +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: ns-766b45fbd7464ccb86d5fd046054cf0a + name: zt-gateway + labels: + app: zt-gateway +spec: + replicas: 1 + selector: + matchLabels: + app: zt-gateway + template: + metadata: + labels: + app: zt-gateway + spec: + containers: + - name: zt-gateway + image: 172.17.19.16:10043/zt-jygk/zt-gateway:VERSION_PLACEHOLDER + imagePullPolicy: Always + env: + - name: TZ + value: Asia/Shanghai + ports: + - containerPort: 48080 + readinessProbe: + httpGet: + path: /actuator/health + port: 48080 + initialDelaySeconds: 100 + periodSeconds: 5 + failureThreshold: 3 + livenessProbe: + httpGet: + path: /actuator/health + port: 48080 + initialDelaySeconds: 100 + periodSeconds: 10 + failureThreshold: 5 + resources: + requests: + cpu: "500m" + memory: "1024Mi" + limits: + cpu: "1024m" + memory: "2048Mi" + terminationGracePeriodSeconds: 30 +--- apiVersion: v1 kind: Service metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 + namespace: ns-766b45fbd7464ccb86d5fd046054cf0a name: zt-gateway spec: type: NodePort @@ -67,7 +67,7 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 + namespace: ns-766b45fbd7464ccb86d5fd046054cf0a name: zt-module-infra labels: app: zt-module-infra @@ -92,7 +92,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-infra - image: 172.16.46.66:10043/zt/zt-module-infra:VERSION_PLACEHOLDER + image: 172.17.19.16:10043/zt-jygk/zt-module-infra:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -101,14 +101,14 @@ spec: httpGet: path: /actuator/health port: 48082 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 48082 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 10 failureThreshold: 5 resources: @@ -125,26 +125,26 @@ spec: maxSurge: 1 maxUnavailable: 0 --- -apiVersion: v1 -kind: Service -metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 - name: zt-module-infra -spec: - type: NodePort - selector: - app: zt-module-infra - ports: - - protocol: TCP - port: 48082 - targetPort: 48082 - nodePort: 30092 ---- +#apiVersion: v1 +#kind: Service +#metadata: +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# name: zt-module-infra +#spec: +# type: NodePort +# selector: +# app: zt-module-infra +# ports: +# - protocol: TCP +# port: 48082 +# targetPort: 48082 +# nodePort: 30092 +#--- # zt-module-system apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 + namespace: ns-766b45fbd7464ccb86d5fd046054cf0a name: zt-module-system labels: app: zt-module-system @@ -170,7 +170,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - node-3 + - worker04 dnsPolicy: None dnsConfig: nameservers: @@ -178,7 +178,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-system - image: 172.16.46.66:10043/zt/zt-module-system:VERSION_PLACEHOLDER + image: 172.17.19.16:10043/zt-jygk/zt-module-system:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -187,14 +187,14 @@ spec: httpGet: path: /actuator/health port: 48081 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 48081 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 10 failureThreshold: 5 resources: @@ -211,26 +211,26 @@ spec: maxSurge: 1 maxUnavailable: 0 --- -apiVersion: v1 -kind: Service -metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 - name: zt-module-system -spec: - type: NodePort - selector: - app: zt-module-system - ports: - - protocol: TCP - port: 48081 - targetPort: 48081 - nodePort: 30091 ---- +#apiVersion: v1 +#kind: Service +#metadata: +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# name: zt-module-system +#spec: +# type: NodePort +# selector: +# app: zt-module-system +# ports: +# - protocol: TCP +# port: 48081 +# targetPort: 48081 +# nodePort: 30091 +#--- # zt-module-bpm #apiVersion: apps/v1 #kind: Deployment #metadata: -# namespace: ns-d6a0e78ebd674c279614498e4c57b133 +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a # name: zt-module-bpm # labels: # app: zt-module-bpm @@ -250,7 +250,7 @@ spec: # spec: # containers: # - name: zt-module-bpm -# image: 172.16.46.66:10043/zt/zt-module-bpm:VERSION_PLACEHOLDER +# image: 172.17.19.16:10043/zt-jygk/zt-module-bpm:VERSION_PLACEHOLDER # imagePullPolicy: Always # env: # - name: TZ @@ -259,14 +259,14 @@ spec: # httpGet: # path: /actuator/health # port: 48083 -# initialDelaySeconds: 50 +# initialDelaySeconds: 100 # periodSeconds: 5 # failureThreshold: 3 # livenessProbe: # httpGet: # path: /actuator/health # port: 48083 -# initialDelaySeconds: 50 +# initialDelaySeconds: 100 # periodSeconds: 10 # failureThreshold: 5 # resources: @@ -286,7 +286,7 @@ spec: #apiVersion: v1 #kind: Service #metadata: -# namespace: ns-d6a0e78ebd674c279614498e4c57b133 +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a # name: zt-module-bpm #spec: # type: NodePort @@ -302,7 +302,7 @@ spec: #apiVersion: apps/v1 #kind: Deployment #metadata: -# namespace: ns-d6a0e78ebd674c279614498e4c57b133 +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a # name: zt-module-report # labels: # app: zt-module-report @@ -322,7 +322,7 @@ spec: # spec: # containers: # - name: zt-module-report -# image: 172.16.46.66:10043/zt/zt-module-report:VERSION_PLACEHOLDER +# image: 172.17.19.16:10043/zt-jygk/zt-module-report:VERSION_PLACEHOLDER # imagePullPolicy: Always # env: # - name: TZ @@ -331,14 +331,14 @@ spec: # httpGet: # path: /actuator/health # port: 48084 -# initialDelaySeconds: 50 +# initialDelaySeconds: 100 # periodSeconds: 5 # failureThreshold: 3 # livenessProbe: # httpGet: # path: /actuator/health # port: 48084 -# initialDelaySeconds: 50 +# initialDelaySeconds: 100 # periodSeconds: 10 # failureThreshold: 5 # resources: @@ -358,7 +358,7 @@ spec: #apiVersion: v1 #kind: Service #metadata: -# namespace: ns-d6a0e78ebd674c279614498e4c57b133 +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a # name: zt-module-report #spec: # type: NodePort @@ -374,7 +374,7 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 + namespace: ns-766b45fbd7464ccb86d5fd046054cf0a name: zt-module-databus labels: app: zt-module-databus @@ -392,15 +392,6 @@ spec: labels: app: zt-module-databus spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - node-3 dnsPolicy: None dnsConfig: nameservers: @@ -408,7 +399,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-databus - image: 172.16.46.66:10043/zt/zt-module-databus:VERSION_PLACEHOLDER + image: 172.17.19.16:10043/zt-jygk/zt-module-databus:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -417,14 +408,14 @@ spec: httpGet: path: /actuator/health port: 48100 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 48100 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 10 failureThreshold: 5 resources: @@ -441,28 +432,28 @@ spec: maxSurge: 1 maxUnavailable: 0 --- -apiVersion: v1 -kind: Service -metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 - name: zt-module-databus -spec: - type: NodePort - selector: - app: zt-module-databus - ports: - - protocol: TCP - port: 48100 - targetPort: 48100 - nodePort: 30090 - - ---- +#apiVersion: v1 +#kind: Service +#metadata: +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# name: zt-module-databus +#spec: +# type: NodePort +# selector: +# app: zt-module-databus +# ports: +# - protocol: TCP +# port: 48100 +# targetPort: 48100 +# nodePort: 30090 +# +# +#--- # zt-module-template apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 + namespace: ns-766b45fbd7464ccb86d5fd046054cf0a name: zt-module-template labels: app: zt-module-template @@ -487,7 +478,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-template - image: 172.16.46.66:10043/zt/zt-module-template:VERSION_PLACEHOLDER + image: 172.17.19.16:10043/zt-jygk/zt-module-template:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -496,14 +487,14 @@ spec: httpGet: path: /actuator/health port: 49100 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 49100 - initialDelaySeconds: 50 + initialDelaySeconds: 100 periodSeconds: 10 failureThreshold: 5 resources: @@ -519,18 +510,18 @@ spec: rollingUpdate: maxSurge: 1 maxUnavailable: 0 ---- -apiVersion: v1 -kind: Service -metadata: - namespace: ns-d6a0e78ebd674c279614498e4c57b133 - name: zt-module-template -spec: - type: NodePort - selector: - app: zt-module-template - ports: - - protocol: TCP - port: 49100 - targetPort: 49100 - nodePort: 30889 +#--- +#apiVersion: v1 +#kind: Service +#metadata: +# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# name: zt-module-template +#spec: +# type: NodePort +# selector: +# app: zt-module-template +# ports: +# - protocol: TCP +# port: 49100 +# targetPort: 49100 +# nodePort: 30889 diff --git a/zt-gateway/Dockerfile b/zt-gateway/Dockerfile index 47876e4d..c2db95f9 100644 --- a/zt-gateway/Dockerfile +++ b/zt-gateway/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-gateway From 3c3ac230080104fffbcfe32f53b3dde9fe12991e Mon Sep 17 00:00:00 2001 From: chenbowen Date: Sat, 27 Dec 2025 12:48:56 +0800 Subject: [PATCH 36/48] =?UTF-8?q?1.=20=E4=B8=B4=E6=97=B6=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E9=9B=86=E7=BE=A4=E9=85=8D=E5=90=88=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-module-ai/zt-module-ai-server/Dockerfile | 2 +- zt-module-bpm/zt-module-bpm-server/Dockerfile | 2 +- zt-module-databus/zt-module-databus-server/Dockerfile | 2 +- zt-module-infra/zt-module-infra-server/Dockerfile | 2 +- zt-module-report/zt-module-report-server/Dockerfile | 2 +- zt-module-system/zt-module-system-server/Dockerfile | 2 +- zt-module-template/zt-module-template-server/Dockerfile | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/zt-module-ai/zt-module-ai-server/Dockerfile b/zt-module-ai/zt-module-ai-server/Dockerfile index 246697fb..d3916674 100644 --- a/zt-module-ai/zt-module-ai-server/Dockerfile +++ b/zt-module-ai/zt-module-ai-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-ai-server diff --git a/zt-module-bpm/zt-module-bpm-server/Dockerfile b/zt-module-bpm/zt-module-bpm-server/Dockerfile index 868eec5c..b8f089e5 100644 --- a/zt-module-bpm/zt-module-bpm-server/Dockerfile +++ b/zt-module-bpm/zt-module-bpm-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-bpm-server diff --git a/zt-module-databus/zt-module-databus-server/Dockerfile b/zt-module-databus/zt-module-databus-server/Dockerfile index 6c1fd56f..23a7681c 100644 --- a/zt-module-databus/zt-module-databus-server/Dockerfile +++ b/zt-module-databus/zt-module-databus-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-databus-server diff --git a/zt-module-infra/zt-module-infra-server/Dockerfile b/zt-module-infra/zt-module-infra-server/Dockerfile index 49d73456..cde88cac 100644 --- a/zt-module-infra/zt-module-infra-server/Dockerfile +++ b/zt-module-infra/zt-module-infra-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-infra-server diff --git a/zt-module-report/zt-module-report-server/Dockerfile b/zt-module-report/zt-module-report-server/Dockerfile index 0a9a86cf..60ab11fc 100644 --- a/zt-module-report/zt-module-report-server/Dockerfile +++ b/zt-module-report/zt-module-report-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-report-server diff --git a/zt-module-system/zt-module-system-server/Dockerfile b/zt-module-system/zt-module-system-server/Dockerfile index 6e8a12d8..be801015 100644 --- a/zt-module-system/zt-module-system-server/Dockerfile +++ b/zt-module-system/zt-module-system-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-system-server diff --git a/zt-module-template/zt-module-template-server/Dockerfile b/zt-module-template/zt-module-template-server/Dockerfile index e32668f2..620c6fb8 100644 --- a/zt-module-template/zt-module-template-server/Dockerfile +++ b/zt-module-template/zt-module-template-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre +FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-template-server From 4d4912db5ecd4392dae5c799dc0f75d42931a954 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Sat, 27 Dec 2025 13:12:22 +0800 Subject: [PATCH 37/48] =?UTF-8?q?Revert=20"1.=20=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E9=9B=86=E7=BE=A4=E9=85=8D=E5=90=88=E6=B5=8B?= =?UTF-8?q?=E8=AF=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3c3ac230080104fffbcfe32f53b3dde9fe12991e. --- zt-module-ai/zt-module-ai-server/Dockerfile | 2 +- zt-module-bpm/zt-module-bpm-server/Dockerfile | 2 +- zt-module-databus/zt-module-databus-server/Dockerfile | 2 +- zt-module-infra/zt-module-infra-server/Dockerfile | 2 +- zt-module-report/zt-module-report-server/Dockerfile | 2 +- zt-module-system/zt-module-system-server/Dockerfile | 2 +- zt-module-template/zt-module-template-server/Dockerfile | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/zt-module-ai/zt-module-ai-server/Dockerfile b/zt-module-ai/zt-module-ai-server/Dockerfile index d3916674..246697fb 100644 --- a/zt-module-ai/zt-module-ai-server/Dockerfile +++ b/zt-module-ai/zt-module-ai-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-ai-server diff --git a/zt-module-bpm/zt-module-bpm-server/Dockerfile b/zt-module-bpm/zt-module-bpm-server/Dockerfile index b8f089e5..868eec5c 100644 --- a/zt-module-bpm/zt-module-bpm-server/Dockerfile +++ b/zt-module-bpm/zt-module-bpm-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-bpm-server diff --git a/zt-module-databus/zt-module-databus-server/Dockerfile b/zt-module-databus/zt-module-databus-server/Dockerfile index 23a7681c..6c1fd56f 100644 --- a/zt-module-databus/zt-module-databus-server/Dockerfile +++ b/zt-module-databus/zt-module-databus-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-databus-server diff --git a/zt-module-infra/zt-module-infra-server/Dockerfile b/zt-module-infra/zt-module-infra-server/Dockerfile index cde88cac..49d73456 100644 --- a/zt-module-infra/zt-module-infra-server/Dockerfile +++ b/zt-module-infra/zt-module-infra-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-infra-server diff --git a/zt-module-report/zt-module-report-server/Dockerfile b/zt-module-report/zt-module-report-server/Dockerfile index 60ab11fc..0a9a86cf 100644 --- a/zt-module-report/zt-module-report-server/Dockerfile +++ b/zt-module-report/zt-module-report-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-report-server diff --git a/zt-module-system/zt-module-system-server/Dockerfile b/zt-module-system/zt-module-system-server/Dockerfile index be801015..6e8a12d8 100644 --- a/zt-module-system/zt-module-system-server/Dockerfile +++ b/zt-module-system/zt-module-system-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-system-server diff --git a/zt-module-template/zt-module-template-server/Dockerfile b/zt-module-template/zt-module-template-server/Dockerfile index 620c6fb8..e32668f2 100644 --- a/zt-module-template/zt-module-template-server/Dockerfile +++ b/zt-module-template/zt-module-template-server/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-module-template-server From c88fdad7ac184ff9018b5ce4fec4e33a7cb745c8 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Sat, 27 Dec 2025 13:12:22 +0800 Subject: [PATCH 38/48] =?UTF-8?q?Revert=20"1.=20=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E9=9B=86=E7=BE=A4=E9=85=8D=E5=90=88=E6=B5=8B?= =?UTF-8?q?=E8=AF=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 26e59522524d9f57f6cb3e226691db7d07649566. --- deployment.yaml | 289 ++++++++++++++++++++++-------------------- zt-gateway/Dockerfile | 2 +- 2 files changed, 150 insertions(+), 141 deletions(-) diff --git a/deployment.yaml b/deployment.yaml index 3526660d..f2e31e3e 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -1,57 +1,57 @@ -# zt-gateway -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: ns-766b45fbd7464ccb86d5fd046054cf0a - name: zt-gateway - labels: - app: zt-gateway -spec: - replicas: 1 - selector: - matchLabels: - app: zt-gateway - template: - metadata: - labels: - app: zt-gateway - spec: - containers: - - name: zt-gateway - image: 172.17.19.16:10043/zt-jygk/zt-gateway:VERSION_PLACEHOLDER - imagePullPolicy: Always - env: - - name: TZ - value: Asia/Shanghai - ports: - - containerPort: 48080 - readinessProbe: - httpGet: - path: /actuator/health - port: 48080 - initialDelaySeconds: 100 - periodSeconds: 5 - failureThreshold: 3 - livenessProbe: - httpGet: - path: /actuator/health - port: 48080 - initialDelaySeconds: 100 - periodSeconds: 10 - failureThreshold: 5 - resources: - requests: - cpu: "500m" - memory: "1024Mi" - limits: - cpu: "1024m" - memory: "2048Mi" - terminationGracePeriodSeconds: 30 ---- +## zt-gateway +#apiVersion: apps/v1 +#kind: Deployment +#metadata: +# namespace: ns-d6a0e78ebd674c279614498e4c57b133 +# name: zt-gateway +# labels: +# app: zt-gateway +#spec: +# replicas: 1 +# selector: +# matchLabels: +# app: zt-gateway +# template: +# metadata: +# labels: +# app: zt-gateway +# spec: +# containers: +# - name: zt-gateway +# image: 172.16.46.66:10043/zt/zt-gateway:VERSION_PLACEHOLDER +# imagePullPolicy: Always +# env: +# - name: TZ +# value: Asia/Shanghai +# ports: +# - containerPort: 48080 +# readinessProbe: +# httpGet: +# path: /actuator/health +# port: 48080 +# initialDelaySeconds: 50 +# periodSeconds: 5 +# failureThreshold: 3 +# livenessProbe: +# httpGet: +# path: /actuator/health +# port: 48080 +# initialDelaySeconds: 50 +# periodSeconds: 10 +# failureThreshold: 5 +# resources: +# requests: +# cpu: "500m" +# memory: "1024Mi" +# limits: +# cpu: "1024m" +# memory: "2048Mi" +# terminationGracePeriodSeconds: 30 +#--- apiVersion: v1 kind: Service metadata: - namespace: ns-766b45fbd7464ccb86d5fd046054cf0a + namespace: ns-d6a0e78ebd674c279614498e4c57b133 name: zt-gateway spec: type: NodePort @@ -67,7 +67,7 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-766b45fbd7464ccb86d5fd046054cf0a + namespace: ns-d6a0e78ebd674c279614498e4c57b133 name: zt-module-infra labels: app: zt-module-infra @@ -92,7 +92,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-infra - image: 172.17.19.16:10043/zt-jygk/zt-module-infra:VERSION_PLACEHOLDER + image: 172.16.46.66:10043/zt/zt-module-infra:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -101,14 +101,14 @@ spec: httpGet: path: /actuator/health port: 48082 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 48082 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 10 failureThreshold: 5 resources: @@ -125,26 +125,26 @@ spec: maxSurge: 1 maxUnavailable: 0 --- -#apiVersion: v1 -#kind: Service -#metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a -# name: zt-module-infra -#spec: -# type: NodePort -# selector: -# app: zt-module-infra -# ports: -# - protocol: TCP -# port: 48082 -# targetPort: 48082 -# nodePort: 30092 -#--- +apiVersion: v1 +kind: Service +metadata: + namespace: ns-d6a0e78ebd674c279614498e4c57b133 + name: zt-module-infra +spec: + type: NodePort + selector: + app: zt-module-infra + ports: + - protocol: TCP + port: 48082 + targetPort: 48082 + nodePort: 30092 +--- # zt-module-system apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-766b45fbd7464ccb86d5fd046054cf0a + namespace: ns-d6a0e78ebd674c279614498e4c57b133 name: zt-module-system labels: app: zt-module-system @@ -170,7 +170,7 @@ spec: - key: kubernetes.io/hostname operator: In values: - - worker04 + - node-3 dnsPolicy: None dnsConfig: nameservers: @@ -178,7 +178,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-system - image: 172.17.19.16:10043/zt-jygk/zt-module-system:VERSION_PLACEHOLDER + image: 172.16.46.66:10043/zt/zt-module-system:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -187,14 +187,14 @@ spec: httpGet: path: /actuator/health port: 48081 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 48081 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 10 failureThreshold: 5 resources: @@ -211,26 +211,26 @@ spec: maxSurge: 1 maxUnavailable: 0 --- -#apiVersion: v1 -#kind: Service -#metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a -# name: zt-module-system -#spec: -# type: NodePort -# selector: -# app: zt-module-system -# ports: -# - protocol: TCP -# port: 48081 -# targetPort: 48081 -# nodePort: 30091 -#--- +apiVersion: v1 +kind: Service +metadata: + namespace: ns-d6a0e78ebd674c279614498e4c57b133 + name: zt-module-system +spec: + type: NodePort + selector: + app: zt-module-system + ports: + - protocol: TCP + port: 48081 + targetPort: 48081 + nodePort: 30091 +--- # zt-module-bpm #apiVersion: apps/v1 #kind: Deployment #metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# namespace: ns-d6a0e78ebd674c279614498e4c57b133 # name: zt-module-bpm # labels: # app: zt-module-bpm @@ -250,7 +250,7 @@ spec: # spec: # containers: # - name: zt-module-bpm -# image: 172.17.19.16:10043/zt-jygk/zt-module-bpm:VERSION_PLACEHOLDER +# image: 172.16.46.66:10043/zt/zt-module-bpm:VERSION_PLACEHOLDER # imagePullPolicy: Always # env: # - name: TZ @@ -259,14 +259,14 @@ spec: # httpGet: # path: /actuator/health # port: 48083 -# initialDelaySeconds: 100 +# initialDelaySeconds: 50 # periodSeconds: 5 # failureThreshold: 3 # livenessProbe: # httpGet: # path: /actuator/health # port: 48083 -# initialDelaySeconds: 100 +# initialDelaySeconds: 50 # periodSeconds: 10 # failureThreshold: 5 # resources: @@ -286,7 +286,7 @@ spec: #apiVersion: v1 #kind: Service #metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# namespace: ns-d6a0e78ebd674c279614498e4c57b133 # name: zt-module-bpm #spec: # type: NodePort @@ -302,7 +302,7 @@ spec: #apiVersion: apps/v1 #kind: Deployment #metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# namespace: ns-d6a0e78ebd674c279614498e4c57b133 # name: zt-module-report # labels: # app: zt-module-report @@ -322,7 +322,7 @@ spec: # spec: # containers: # - name: zt-module-report -# image: 172.17.19.16:10043/zt-jygk/zt-module-report:VERSION_PLACEHOLDER +# image: 172.16.46.66:10043/zt/zt-module-report:VERSION_PLACEHOLDER # imagePullPolicy: Always # env: # - name: TZ @@ -331,14 +331,14 @@ spec: # httpGet: # path: /actuator/health # port: 48084 -# initialDelaySeconds: 100 +# initialDelaySeconds: 50 # periodSeconds: 5 # failureThreshold: 3 # livenessProbe: # httpGet: # path: /actuator/health # port: 48084 -# initialDelaySeconds: 100 +# initialDelaySeconds: 50 # periodSeconds: 10 # failureThreshold: 5 # resources: @@ -358,7 +358,7 @@ spec: #apiVersion: v1 #kind: Service #metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a +# namespace: ns-d6a0e78ebd674c279614498e4c57b133 # name: zt-module-report #spec: # type: NodePort @@ -374,7 +374,7 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-766b45fbd7464ccb86d5fd046054cf0a + namespace: ns-d6a0e78ebd674c279614498e4c57b133 name: zt-module-databus labels: app: zt-module-databus @@ -392,6 +392,15 @@ spec: labels: app: zt-module-databus spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - node-3 dnsPolicy: None dnsConfig: nameservers: @@ -399,7 +408,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-databus - image: 172.17.19.16:10043/zt-jygk/zt-module-databus:VERSION_PLACEHOLDER + image: 172.16.46.66:10043/zt/zt-module-databus:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -408,14 +417,14 @@ spec: httpGet: path: /actuator/health port: 48100 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 48100 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 10 failureThreshold: 5 resources: @@ -432,28 +441,28 @@ spec: maxSurge: 1 maxUnavailable: 0 --- -#apiVersion: v1 -#kind: Service -#metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a -# name: zt-module-databus -#spec: -# type: NodePort -# selector: -# app: zt-module-databus -# ports: -# - protocol: TCP -# port: 48100 -# targetPort: 48100 -# nodePort: 30090 -# -# -#--- +apiVersion: v1 +kind: Service +metadata: + namespace: ns-d6a0e78ebd674c279614498e4c57b133 + name: zt-module-databus +spec: + type: NodePort + selector: + app: zt-module-databus + ports: + - protocol: TCP + port: 48100 + targetPort: 48100 + nodePort: 30090 + + +--- # zt-module-template apiVersion: apps/v1 kind: Deployment metadata: - namespace: ns-766b45fbd7464ccb86d5fd046054cf0a + namespace: ns-d6a0e78ebd674c279614498e4c57b133 name: zt-module-template labels: app: zt-module-template @@ -478,7 +487,7 @@ spec: - "172.16.36.220" containers: - name: zt-module-template - image: 172.17.19.16:10043/zt-jygk/zt-module-template:VERSION_PLACEHOLDER + image: 172.16.46.66:10043/zt/zt-module-template:VERSION_PLACEHOLDER imagePullPolicy: Always env: - name: TZ @@ -487,14 +496,14 @@ spec: httpGet: path: /actuator/health port: 49100 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health port: 49100 - initialDelaySeconds: 100 + initialDelaySeconds: 50 periodSeconds: 10 failureThreshold: 5 resources: @@ -510,18 +519,18 @@ spec: rollingUpdate: maxSurge: 1 maxUnavailable: 0 -#--- -#apiVersion: v1 -#kind: Service -#metadata: -# namespace: ns-766b45fbd7464ccb86d5fd046054cf0a -# name: zt-module-template -#spec: -# type: NodePort -# selector: -# app: zt-module-template -# ports: -# - protocol: TCP -# port: 49100 -# targetPort: 49100 -# nodePort: 30889 +--- +apiVersion: v1 +kind: Service +metadata: + namespace: ns-d6a0e78ebd674c279614498e4c57b133 + name: zt-module-template +spec: + type: NodePort + selector: + app: zt-module-template + ports: + - protocol: TCP + port: 49100 + targetPort: 49100 + nodePort: 30889 diff --git a/zt-gateway/Dockerfile b/zt-gateway/Dockerfile index c2db95f9..47876e4d 100644 --- a/zt-gateway/Dockerfile +++ b/zt-gateway/Dockerfile @@ -1,6 +1,6 @@ ## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性 -FROM 172.17.19.16:10043/zt-cloud-base-service/eclipse-temurin:21-jre +FROM 172.16.46.66:10043/base-service/eclipse-temurin:21-jre ## 创建目录,并使用它作为工作目录 RUN mkdir -p /zt-gateway From 8b469710ce097accbefb7ff5e4951ffab4cc0424 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 29 Dec 2025 09:53:00 +0800 Subject: [PATCH 39/48] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E5=A4=8Dseata2.4?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=B8=8B=E8=BE=BE=E6=A2=A6=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E5=9B=9E=E6=BB=9A=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seata/rm/datasource/DataCompareUtils.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java b/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java index 2d596096..1b91c4ab 100644 --- a/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java +++ b/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java @@ -26,6 +26,8 @@ import org.apache.seata.rm.datasource.undo.AbstractUndoLogManager; import org.apache.seata.rm.datasource.undo.parser.FastjsonUndoLogParser; import org.apache.seata.rm.datasource.undo.parser.JacksonUndoLogParser; import org.apache.seata.sqlparser.struct.TableMeta; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.lang.reflect.Method; import java.math.BigDecimal; @@ -66,6 +68,18 @@ import java.util.stream.Collectors; */ public class DataCompareUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(DataCompareUtils.class); + + /** + * 标识补丁类是否已加载 + */ + private static final boolean PATCHED; + + static { + PATCHED = true; + LOGGER.info("[zt-spring-boot-starter-seata-dm] DataCompareUtils 补丁类已加载,用于解决达梦数据库 DmdbTimestamp 时区问题"); + } + private DataCompareUtils() {} /** @@ -102,6 +116,10 @@ public class DataCompareUtils { Instant i0 = toInstant(v0); Instant i1 = toInstant(v1); boolean equals = Objects.equals(i0, i1); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("[zt-seata-dm-patch] DmdbTimestamp 比较: field={}, i0={}, i1={}, equals={}", + f0.getName(), i0, i1, equals); + } return equals ? Result.ok() : Result.buildWithParams( From 8e8acd6aaf426958c7b034b86340e24048d03722 Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 29 Dec 2025 09:54:36 +0800 Subject: [PATCH 40/48] =?UTF-8?q?fix=EF=BC=9A=E4=BF=AE=E5=A4=8Dseata2.4?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=B8=8B=E8=BE=BE=E6=A2=A6=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E5=9B=9E=E6=BB=9A=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/seata/rm/datasource/DataCompareUtils.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java b/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java index 1b91c4ab..24c15d5a 100644 --- a/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java +++ b/zt-framework/zt-spring-boot-starter-seata-dm/src/main/java/org/apache/seata/rm/datasource/DataCompareUtils.java @@ -116,10 +116,7 @@ public class DataCompareUtils { Instant i0 = toInstant(v0); Instant i1 = toInstant(v1); boolean equals = Objects.equals(i0, i1); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("[zt-seata-dm-patch] DmdbTimestamp 比较: field={}, i0={}, i1={}, equals={}", - f0.getName(), i0, i1, equals); - } + LOGGER.info("[zt-seata-dm-patch] DmdbTimestamp 字段比较: field={}, equals={}", f0.getName(), equals); return equals ? Result.ok() : Result.buildWithParams( From 580d1d9047609fd97b39e69da905d0836b59be4c Mon Sep 17 00:00:00 2001 From: chenbowen Date: Mon, 29 Dec 2025 11:13:29 +0800 Subject: [PATCH 41/48] =?UTF-8?q?1.=20=E8=A1=A5=E5=85=A8=E5=9F=BA=E5=87=86?= =?UTF-8?q?=E7=9A=84=E8=8F=9C=E5=8D=95=20sql=20=E8=AF=AD=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/dm/ruoyi-vue-pro-dm8.sql | 309 ++++++++++++++++++++++++++++++++++- 1 file changed, 308 insertions(+), 1 deletion(-) diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql index 1aa21a6d..53667219 100644 --- a/sql/dm/ruoyi-vue-pro-dm8.sql +++ b/sql/dm/ruoyi-vue-pro-dm8.sql @@ -331,6 +331,8 @@ CREATE TABLE infra_file ( name varchar(256) DEFAULT NULL NULL, path varchar(512) NOT NULL, url varchar(1024) NOT NULL, + hash varchar(64) DEFAULT NULL NULL, + aes_iv varchar(128) DEFAULT NULL NULL, type varchar(128) DEFAULT NULL NULL, size int NOT NULL, creator varchar(64) DEFAULT '' NULL, @@ -345,6 +347,8 @@ COMMENT ON COLUMN infra_file.config_id IS '配置编号'; COMMENT ON COLUMN infra_file.name IS '文件名'; COMMENT ON COLUMN infra_file.path IS '文件路径'; COMMENT ON COLUMN infra_file.url IS '文件 URL'; +COMMENT ON COLUMN infra_file.hash IS '文件哈希值(SHA-256)'; +COMMENT ON COLUMN infra_file.aes_iv IS 'AES加密时的随机IV(Base64编码)'; COMMENT ON COLUMN infra_file.type IS '文件类型'; COMMENT ON COLUMN infra_file.size IS '文件大小'; COMMENT ON COLUMN infra_file.creator IS '创建者'; @@ -354,6 +358,8 @@ COMMENT ON COLUMN infra_file.update_time IS '更新时间'; COMMENT ON COLUMN infra_file.deleted IS '是否删除'; COMMENT ON TABLE infra_file IS '文件表'; +CREATE INDEX idx_infra_file_hash ON infra_file(hash); + -- ---------------------------- -- Table structure for infra_file_config -- ---------------------------- @@ -1586,6 +1592,116 @@ INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5010, '租户切换', 'system:tenant:visit', 3, 999, 1138, '', '', '', '', 0, '1', '1', '1', '1', '2025-05-05 15:25:32', '1', '2025-05-05 15:25:32', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5013, '公司切换', 'system:company:visit', 3, 100, 103, '', '', '', '', 0, '1', '1', '1', '1', '2025-12-05 09:00:00', '1', '2025-12-05 09:00:00', '0'); INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5014, '部门切换', 'system:dept:visit', 3, 101, 103, '', '', '', '', 0, '1', '1', '1', '1', '2025-12-05 09:00:00', '1', '2025-12-05 09:00:00', '0'); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953701540574969857, '系统序列号管理', '', 2, 0, 1, 'sequence', '', 'system/sequence/index', 'Sequence', 0, 1, 1, 1, '', '2025-08-08 14:38:20.455625', '', '2025-08-08 14:38:20.455626', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150470, '系统序列号导出', 'system:sequence:export', 3, 5, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.580376', '', '2025-08-08 14:38:20.580377', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150469, '系统序列号删除', 'system:sequence:delete', 3, 4, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.553819', '', '2025-08-08 14:38:20.553820', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150468, '系统序列号更新', 'system:sequence:update', 3, 3, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.522730', '', '2025-08-08 14:38:20.522731', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150467, '系统序列号创建', 'system:sequence:create', 3, 2, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.499928', '', '2025-08-08 14:38:20.499929', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1953706417225150466, '系统序列号查询', 'system:sequence:query', 3, 1, 1953701540574969857, '', '', '', null, 0, 1, 1, 1, '', '2025-08-08 14:38:20.483702', '', '2025-08-08 14:38:20.483703', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2739, '消息中心', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, 1, 1, 1, '1', '2024-04-22 23:54:30.000000', '1', '2024-04-23 09:36:35.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2144, '站内信管理', '', 1, 3, 2739, 'notify', 'ep:message-box', null, null, 0, 1, 1, 1, '1', '2023-01-28 10:25:18.000000', '1', '2024-04-22 23:56:12.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2151, '消息记录', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, 1, 1, 1, '', '2023-01-28 04:28:22.000000', '1', '2024-02-29 08:49:22.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2152, '站内信消息查询', 'system:notify-message:query', 3, 1, 2151, '', '', '', null, 0, 1, 1, 1, '', '2023-01-28 04:28:22.000000', '', '2023-01-28 04:28:22.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2145, '模板管理', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, 1, 1, 1, '', '2023-01-28 02:26:42.000000', '1', '2024-02-29 08:49:14.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2150, '发送测试站内信', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', null, 0, 1, 1, 1, '1', '2023-01-28 10:54:43.000000', '1', '2023-01-28 10:54:43.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2149, '站内信模板删除', 'system:notify-template:delete', 3, 4, 2145, '', '', '', null, 0, 1, 1, 1, '', '2023-01-28 02:26:42.000000', '', '2023-01-28 02:26:42.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2148, '站内信模板更新', 'system:notify-template:update', 3, 3, 2145, '', '', '', null, 0, 1, 1, 1, '', '2023-01-28 02:26:42.000000', '', '2023-01-28 02:26:42.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2147, '站内信模板创建', 'system:notify-template:create', 3, 2, 2145, '', '', '', null, 0, 1, 1, 1, '', '2023-01-28 02:26:42.000000', '', '2023-01-28 02:26:42.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2146, '站内信模板查询', 'system:notify-template:query', 3, 1, 2145, '', '', '', null, 0, 1, 1, 1, '', '2023-01-28 02:26:42.000000', '', '2023-01-28 02:26:42.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2130, '邮箱管理', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', null, null, 0, 1, 1, 1, '1', '2023-01-25 17:27:44.000000', '1', '2024-04-22 23:56:08.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2141, '邮件记录', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, 1, 1, 1, '', '2023-01-26 02:16:50.000000', '1', '2024-02-29 08:48:51.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2142, '日志查询', 'system:mail-log:query', 3, 1, 2141, '', '', '', null, 0, 1, 1, 1, '', '2023-01-26 02:16:50.000000', '', '2023-01-26 02:16:50.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2136, '邮件模版', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, 1, 1, 1, '', '2023-01-25 12:05:31.000000', '1', '2024-02-29 08:48:41.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2143, '发送测试邮件', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', null, 0, 1, 1, 1, '1', '2023-01-26 23:29:15.000000', '1', '2023-01-26 23:29:15.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2140, '模版删除', 'system:mail-template:delete', 3, 4, 2136, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 12:05:31.000000', '', '2023-01-25 12:05:31.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2139, '模版更新', 'system:mail-template:update', 3, 3, 2136, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 12:05:31.000000', '', '2023-01-25 12:05:31.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2138, '模版创建', 'system:mail-template:create', 3, 2, 2136, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 12:05:31.000000', '', '2023-01-25 12:05:31.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2137, '模版查询', 'system:mail-template:query', 3, 1, 2136, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 12:05:31.000000', '', '2023-01-25 12:05:31.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2131, '邮箱账号', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, 1, 1, 1, '', '2023-01-25 09:33:48.000000', '1', '2024-02-29 08:48:16.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2135, '账号删除', 'system:mail-account:delete', 3, 4, 2131, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 09:33:48.000000', '', '2023-01-25 09:33:48.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2134, '账号更新', 'system:mail-account:update', 3, 3, 2131, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 09:33:48.000000', '', '2023-01-25 09:33:48.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2133, '账号创建', 'system:mail-account:create', 3, 2, 2131, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 09:33:48.000000', '', '2023-01-25 09:33:48.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2132, '账号查询', 'system:mail-account:query', 3, 1, 2131, '', '', '', null, 0, 1, 1, 1, '', '2023-01-25 09:33:48.000000', '', '2023-01-25 09:33:48.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1093, '短信管理', '', 1, 1, 2739, 'sms', 'ep:message', null, null, 0, 1, 1, 1, '1', '2021-04-05 01:10:16.000000', '1', '2024-04-22 23:56:03.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, 1, 1, 1, '', '2021-04-11 08:37:05.000000', '1', '2024-02-29 08:49:02.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', null, 0, 1, 1, 1, '', '2021-04-11 08:37:05.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', null, 0, 1, 1, 1, '', '2021-04-11 08:37:05.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1100, '短信模板', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, 1, 1, 1, '', '2021-04-01 17:35:17.000000', '1', '2024-02-29 01:16:18.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1106, '发送测试短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', null, 0, 1, 1, 1, '1', '2021-04-11 00:26:40.000000', '1', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1105, '短信模板导出', 'system:sms-template:export', 3, 5, 1100, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 17:35:17.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1104, '短信模板删除', 'system:sms-template:delete', 3, 4, 1100, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 17:35:17.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1103, '短信模板更新', 'system:sms-template:update', 3, 3, 1100, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 17:35:17.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1102, '短信模板创建', 'system:sms-template:create', 3, 2, 1100, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 17:35:17.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1101, '短信模板查询', 'system:sms-template:query', 3, 1, 1100, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 17:35:17.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, 1, 1, 1, '', '2021-04-01 11:07:15.000000', '1', '2024-02-29 01:15:54.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 11:07:15.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 11:07:15.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 11:07:15.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', null, 0, 1, 1, 1, '', '2021-04-01 11:07:15.000000', '', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (107, '通知公告', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, 1, 1, 1, 'admin', '2021-01-05 17:03:48.000000', '1', '2024-04-22 23:56:17.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', null, 0, 1, 1, 1, 'admin', '2021-01-05 17:03:48.000000', '1', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', null, 0, 1, 1, 1, 'admin', '2021-01-05 17:03:48.000000', '1', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', null, 0, 1, 1, 1, 'admin', '2021-01-05 17:03:48.000000', '1', '2022-04-20 17:03:10.000000', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', null, 0, 1, 1, 1, 'admin', '2021-01-05 17:03:48.000000', '', '2022-04-20 17:03:10.000000', 0); + +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (6500, '数据总线', '', 1, 20, 1, 'databus', 'ep:data-board', '', 'DatabusRoot', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.690389', 'admin', '2025-10-17 17:14:18.690390', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123500, '数据同步', '', 1, 50, 6500, 'sync', 'ep:connection', null, null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.048176', '1', '2025-11-25 17:33:29.370218', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2874, '全量同步任务', '', 2, 6, 1861234567890123500, 'fulltask', 'ep:upload', 'databus/sync/fulltask/index', 'DatabusSyncFullTask', 0, 1, 1, 0, 'admin', '2025-11-28 18:24:33.619358', 'admin', '2025-11-28 18:24:33.619360', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2878, '全量同步任务取消', 'databus:sync:full-task:cancel', 3, 4, 2874, '', '', '', '', 0, 1, 1, 0, 'admin', '2025-11-28 18:24:33.619369', 'admin', '2025-11-28 18:24:33.619369', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2877, '全量同步任务执行', 'databus:sync:full-task:execute', 3, 3, 2874, '', '', '', '', 0, 1, 1, 0, 'admin', '2025-11-28 18:24:33.619368', 'admin', '2025-11-28 18:24:33.619368', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2876, '全量同步任务创建', 'databus:sync:full-task:create', 3, 2, 2874, '', '', '', '', 0, 1, 1, 0, 'admin', '2025-11-28 18:24:33.619367', 'admin', '2025-11-28 18:24:33.619367', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (2875, '全量同步任务查询', 'databus:sync:full-task:query', 3, 1, 2874, '', '', '', '', 0, 1, 1, 0, 'admin', '2025-11-28 18:24:33.619366', 'admin', '2025-11-28 18:24:33.619366', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123523, '死信队列', '', 2, 5, 1861234567890123500, 'deadletter', 'ep:warning', 'databus/sync/deadletter/index', 'DatabusSyncDeadLetter', 0, 1, 1, 1, '', '2025-11-25 17:28:16.259929', '', '2025-11-25 17:28:16.259932', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123527, '忽略死信', 'databus:sync:dead-letter:ignore', 3, 4, 1861234567890123523, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.282800', '', '2025-11-25 17:28:16.282802', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123526, '重新投递', 'databus:sync:dead-letter:reprocess', 3, 3, 1861234567890123523, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.277958', '', '2025-11-25 17:28:16.277960', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123525, '查看详情', 'databus:sync:dead-letter:detail', 3, 2, 1861234567890123523, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.271126', '', '2025-11-25 17:28:16.271128', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123524, '查询死信', 'databus:sync:dead-letter:query', 3, 1, 1861234567890123523, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.267617', '', '2025-11-25 17:28:16.267619', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123519, '同步日志', '', 2, 4, 1861234567890123500, 'pushlog', 'ep:document', 'databus/sync/pushlog/index', 'DatabusSyncLog', 0, 1, 1, 1, '', '2025-11-25 17:28:16.210732', '', '2025-11-25 17:28:16.210733', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123522, '导出日志', 'databus:sync:log:export', 3, 3, 1861234567890123519, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.252291', '', '2025-11-25 17:28:16.252296', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123521, '查看详情', 'databus:sync:log:detail', 3, 2, 1861234567890123519, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.230811', '', '2025-11-25 17:28:16.230816', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123520, '查询日志', 'databus:sync:log:query', 3, 1, 1861234567890123519, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.220956', '', '2025-11-25 17:28:16.220959', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123513, '订阅管理', '', 2, 3, 1861234567890123500, 'subscription', 'ep:guide', 'databus/sync/subscription/index', 'DatabusSyncSubscription', 0, 1, 1, 1, '', '2025-11-25 17:28:16.163388', '1', '2025-11-28 18:48:54.496674', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123518, '导出订阅', 'databus:sync:subscription:export', 3, 5, 1861234567890123513, '', '', '', null, 1, 1, 1, 1, '', '2025-11-25 17:28:16.203898', '', '2025-11-25 17:28:16.203899', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123517, '删除订阅', 'databus:sync:subscription:delete', 3, 4, 1861234567890123513, '', '', '', null, 1, 1, 1, 1, '', '2025-11-25 17:28:16.197362', '', '2025-11-25 17:28:16.197363', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123516, '更新订阅', 'databus:sync:subscription:update', 3, 3, 1861234567890123513, '', '', '', null, 1, 1, 1, 1, '', '2025-11-25 17:28:16.191555', '', '2025-11-25 17:28:16.191556', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123515, '创建订阅', 'databus:sync:subscription:create', 3, 2, 1861234567890123513, '', '', '', null, 1, 1, 1, 1, '', '2025-11-25 17:28:16.185782', '', '2025-11-25 17:28:16.185783', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123514, '查询订阅', 'databus:sync:subscription:query', 3, 1, 1861234567890123513, '', '', '', null, 1, 1, 1, 1, '', '2025-11-25 17:28:16.177918', '', '2025-11-25 17:28:16.177920', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123507, '客户端管理', '', 2, 2, 1861234567890123500, 'client', 'ep:monitor', 'databus/sync/client/index', 'DatabusSyncClient', 0, 1, 1, 1, '', '2025-11-25 17:28:16.111525', '', '2025-11-25 17:28:16.111526', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123512, '导出客户端', 'databus:sync:client:export', 3, 5, 1861234567890123507, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.158423', '', '2025-11-25 17:28:16.158424', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123511, '删除客户端', 'databus:sync:client:delete', 3, 4, 1861234567890123507, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.147803', '', '2025-11-25 17:28:16.147804', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123510, '更新客户端', 'databus:sync:client:update', 3, 3, 1861234567890123507, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.137440', '', '2025-11-25 17:28:16.137441', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123509, '创建客户端', 'databus:sync:client:create', 3, 2, 1861234567890123507, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.125308', '', '2025-11-25 17:28:16.125310', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123508, '查询客户端', 'databus:sync:client:query', 3, 1, 1861234567890123507, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.117846', '', '2025-11-25 17:28:16.117847', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123501, '事件管理', '', 2, 1, 1861234567890123500, 'event', 'ep:bell', 'databus/sync/event/index', 'DatabusSyncEvent', 0, 1, 1, 1, '', '2025-11-25 17:28:16.052979', '1', '2025-11-25 17:34:34.591416', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123506, '导出事件', 'databus:sync:event:export', 3, 5, 1861234567890123501, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.101020', '', '2025-11-25 17:28:16.101037', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123505, '删除事件', 'databus:sync:event:delete', 3, 4, 1861234567890123501, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.086845', '', '2025-11-25 17:28:16.086847', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123504, '更新事件', 'databus:sync:event:update', 3, 3, 1861234567890123501, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.079252', '', '2025-11-25 17:28:16.079256', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123503, '创建事件', 'databus:sync:event:create', 3, 2, 1861234567890123501, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.071706', '', '2025-11-25 17:28:16.071710', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (1861234567890123502, '查询事件', 'databus:sync:event:query', 3, 1, 1861234567890123501, '', '', '', null, 0, 1, 1, 1, '', '2025-11-25 17:28:16.060256', '', '2025-11-25 17:28:16.060257', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (6504, '访问日志', 'databus:gateway:access-log:query', 2, 40, 6500, 'access-log', 'ep:document', 'databus/accesslog/index', 'DatabusAccessLog', 0, 1, 1, 1, 'admin', '2025-10-29 14:39:35.126020', 'admin', '2025-10-29 14:39:35.126022', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650401, '访问日志查询', 'databus:gateway:access-log:query', 3, 1, 6504, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-29 14:39:35.160454', 'admin', '2025-10-29 14:39:35.160456', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (6503, '限流策略', 'databus:policy:query', 2, 30, 6500, 'policy/rate-limit', 'ep:stopwatch', 'databus/policy/RateLimitPolicy', 'DatabusRateLimitPolicy', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.690396', 'admin', '2025-10-17 17:14:18.690396', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650304, '策略删除', 'databus:policy:delete', 3, 4, 6503, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734365', 'admin', '2025-10-17 17:14:18.734365', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650303, '策略修改', 'databus:policy:update', 3, 3, 6503, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734363', 'admin', '2025-10-17 17:14:18.734363', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650302, '策略新增', 'databus:policy:create', 3, 2, 6503, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734362', 'admin', '2025-10-17 17:14:18.734362', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650301, '策略查询', 'databus:policy:query', 3, 1, 6503, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734360', 'admin', '2025-10-17 17:14:18.734360', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (6502, '客户端凭证', 'databus:credential:query', 2, 20, 6500, 'credential', 'ep:key', 'databus/credential/index', 'DatabusCredential', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.690395', 'admin', '2025-10-17 17:14:18.690395', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650204, '凭证删除', 'databus:credential:delete', 3, 4, 6502, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734358', 'admin', '2025-10-17 17:14:18.734358', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650203, '凭证修改', 'databus:credential:update', 3, 3, 6502, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734356', 'admin', '2025-10-17 17:14:18.734356', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650202, '凭证新增', 'databus:credential:create', 3, 2, 6502, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734354', 'admin', '2025-10-17 17:14:18.734354', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650201, '凭证查询', 'databus:credential:query', 3, 1, 6502, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734352', 'admin', '2025-10-17 17:14:18.734352', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (6501, 'API 定义', 'databus:gateway:query', 2, 10, 6500, 'gateway', 'ep:list', 'databus/gateway/index', 'DatabusGateway', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.690394', 'admin', '2025-10-17 17:14:18.690394', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650110, 'API版本对比', 'databus:gateway:version:compare', 3, 10, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-30 14:37:51.432572', 'admin', '2025-10-30 14:37:51.432572', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650109, 'API版本回滚', 'databus:gateway:version:rollback', 3, 9, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-30 14:37:51.432571', 'admin', '2025-10-30 14:37:51.432571', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650108, 'API版本详情', 'databus:gateway:version:detail', 3, 8, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-30 14:37:51.432570', 'admin', '2025-10-30 14:37:51.432570', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650107, 'API版本历史', 'databus:gateway:version:query', 3, 7, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-30 14:37:51.432564', 'admin', '2025-10-30 14:37:51.432566', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650106, 'API 刷新', 'databus:gateway:refresh', 3, 6, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734350', 'admin', '2025-10-17 17:14:18.734351', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650105, 'API 调试', 'databus:gateway:invoke', 3, 5, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734349', 'admin', '2025-10-17 17:14:18.734349', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650104, 'API 删除', 'databus:gateway:delete', 3, 4, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734347', 'admin', '2025-10-17 17:14:18.734347', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650103, 'API 编辑', 'databus:gateway:update', 3, 3, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734345', 'admin', '2025-10-17 17:14:18.734345', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650102, 'API 新建', 'databus:gateway:create', 3, 2, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734343', 'admin', '2025-10-17 17:14:18.734344', 0); +insert into SYSTEM_MENU (ID, NAME, PERMISSION, TYPE, SORT, PARENT_ID, PATH, ICON, COMPONENT, COMPONENT_NAME, STATUS, VISIBLE, KEEP_ALIVE, ALWAYS_SHOW, CREATOR, CREATE_TIME, UPDATER, UPDATE_TIME, DELETED) values (650101, 'API 查询', 'databus:gateway:query', 3, 1, 6501, '', '', '', '', 0, 1, 1, 1, 'admin', '2025-10-17 17:14:18.734335', 'admin', '2025-10-17 17:14:18.734338', 0); + COMMIT; -- SET IDENTITY_INSERT system_menu OFF; -- @formatter:on @@ -3897,6 +4013,7 @@ CREATE TABLE infra_bsn_file ( file_id bigint NOT NULL, file_name varchar(500) DEFAULT '' NULL, src varchar(100) DEFAULT '' NULL, + status smallint DEFAULT 1 NOT NULL, creator varchar(64) DEFAULT '' NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, updater varchar(64) DEFAULT '' NULL, @@ -3911,13 +4028,14 @@ COMMENT ON COLUMN infra_bsn_file.bsn_cd IS '业务编码'; COMMENT ON COLUMN infra_bsn_file.file_id IS '附件fileId'; COMMENT ON COLUMN infra_bsn_file.file_name IS '附件名称'; COMMENT ON COLUMN infra_bsn_file.src IS '附件来源'; +COMMENT ON COLUMN infra_bsn_file.status IS '状态(1-正常,0-禁用)'; COMMENT ON COLUMN infra_bsn_file.creator IS '创建者'; COMMENT ON COLUMN infra_bsn_file.create_time IS '创建时间'; COMMENT ON COLUMN infra_bsn_file.updater IS '更新者'; COMMENT ON COLUMN infra_bsn_file.update_time IS '最后更新时间'; COMMENT ON COLUMN infra_bsn_file.deleted IS '是否删除'; COMMENT ON COLUMN infra_bsn_file.tenant_id IS '租户编号'; -COMMENT ON TABLE infra_bsn_file IS '业务附件表'; +COMMENT ON TABLE infra_bsn_file IS '业务附件关联表'; -- ---------------------------- -- Table structure for system_seq @@ -4004,3 +4122,192 @@ COMMENT ON COLUMN system_seq_rcd.updater IS '更新者'; COMMENT ON COLUMN system_seq_rcd.update_time IS '更新时间'; COMMENT ON COLUMN system_seq_rcd.deleted IS '是否删除'; COMMENT ON TABLE system_seq_rcd IS '系统序列号记录表'; + + +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '1948328245618204673', '业务附件关联管理', '', 2, 0, 1243, + 'business-file', '', 'infra/businessfile/index', 0, 'BusinessFile' + ); + +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1951092724040097793', '业务附件关联查询', 'infra:business-file:query', 3, 1, 1948328245618204673, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1951092724040097794', '业务附件关联创建', 'infra:business-file:create', 3, 2, 1948328245618204673, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1951092724040097795', '业务附件关联更新', 'infra:business-file:update', 3, 3, 1948328245618204673, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1951092724040097796', '业务附件关联删除', 'infra:business-file:delete', 3, 4, 1948328245618204673, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1951092724040097797', '业务附件关联导出', 'infra:business-file:export', 3, 5, 1948328245618204673, + '', '', '', 0 + ); + +-- 数据命名与简写标准菜单 +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '1947909810016006146', '数据命名与简写标准管理', '', 2, 0, 2, + 'standard-name', '', 'infra/standardname/index', 0, 'StandardName' + ); + +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953301310553645058', '数据命名与简写标准查询', 'infra:standard-name:query', 3, 1, 1947909810016006146, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953301310553645059', '数据命名与简写标准创建', 'infra:standard-name:create', 3, 2, 1947909810016006146, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953301310553645060', '数据命名与简写标准更新', 'infra:standard-name:update', 3, 3, 1947909810016006146, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953301310553645061', '数据命名与简写标准删除', 'infra:standard-name:delete', 3, 4, 1947909810016006146, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953301310553645062', '数据命名与简写标准导出', 'infra:standard-name:export', 3, 5, 1947909810016006146, + '', '', '', 0 + ); + +-- 系统序列号菜单 +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '1953701540574969857', '系统序列号管理', '', 2, 0, 1, + 'sequence', '', 'system/sequence/index', 0, 'Sequence' + ); + +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953702581324398594', '系统序列号查询', 'system:sequence:query', 3, 1, 1953701540574969857, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953702581324398595', '系统序列号创建', 'system:sequence:create', 3, 2, 1953701540574969857, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953702581324398596', '系统序列号更新', 'system:sequence:update', 3, 3, 1953701540574969857, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953702581324398597', '系统序列号删除', 'system:sequence:delete', 3, 4, 1953701540574969857, + '', '', '', 0 + ); +INSERT INTO system_menu( + id, name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '1953702581324398598', '系统序列号导出', 'system:sequence:export', 3, 5, 1953701540574969857, + '', '', '', 0 + ); + +-- 系统序列号相关字典数据初始化 +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) +VALUES (500, '系统序列号循环类型', 'system_sequence_cycle_type', 0, '系统序列号循环类型枚举', 'admin', SYSDATE, 'admin', SYSDATE, 0, NULL); + +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) +VALUES + (5001, 1, '年循环', 'Y', 'system_sequence_cycle_type', 0, 'primary', '', '年循环。示例: 2025', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5002, 2, '年-月循环', 'Y-M', 'system_sequence_cycle_type', 0, 'success', '', '年-月循环。示例: 2025-08', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5003, 3, '年月紧凑', 'YM', 'system_sequence_cycle_type', 0, 'info', '', '年月紧凑。示例: 202508', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5004, 4, '两位年+月', 'yM', 'system_sequence_cycle_type', 0, 'warning', '', '两位年+月。示例: 2508', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5005, 5, '年-月-日循环', 'Y-M-D', 'system_sequence_cycle_type', 0, 'primary', '', '年-月-日循环。示例: 2025-08-08', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5006, 6, '年月日紧凑', 'YMD', 'system_sequence_cycle_type', 0, 'success', '', '年月日紧凑。示例: 20250808', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5007, 7, '两位年+月日', 'yMD', 'system_sequence_cycle_type', 0, 'info', '', '两位年+月日。示例: 250808', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5008, 8, '自定义循环值', 'CUST', 'system_sequence_cycle_type', 0, 'warning', '', '自定义循环值;若未传 circulationValue,则默认用 seqId', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5009, 9, '仅前缀', 'PFX', 'system_sequence_cycle_type', 0, 'danger', '', '仅前缀,不需要时间循环值(不设置则不抛错)', 'admin', SYSDATE, 'admin', SYSDATE, 0); + +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) +VALUES (501, '系统序列号分段类型', 'system_sequence_detail_type', 0, '系统序列号分段类型枚举', 'admin', SYSDATE, 'admin', SYSDATE, 0, NULL); + +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) +VALUES + (5011, 1, '默认字符分段', 'STR', 'system_sequence_detail_type', 0, 'primary', '', '固定字符串分段', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5012, 2, '给定字符分段', 'INPUT', 'system_sequence_detail_type', 0, 'success', '', '根据输入参数动态生成的字符分段', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5013, 3, '日期分段', 'DATE', 'system_sequence_detail_type', 0, 'info', '', '基于日期格式的分段', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5014, 4, '流水号分段', 'SEQ', 'system_sequence_detail_type', 0, 'warning', '', '自增流水号分段', 'admin', SYSDATE, 'admin', SYSDATE, 0); + +INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) +VALUES (502, '系统序列号分段规则类型', 'system_sequence_detail_rule_type', 0, '系统序列号分段规则类型枚举', 'admin', SYSDATE, 'admin', SYSDATE, 0, NULL); + +INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) +VALUES + (5021, 1, '固定值', 'FIXED', 'system_sequence_detail_rule_type', 0, 'primary', '', '固定字符串值', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5022, 2, '日期格式', 'DATE', 'system_sequence_detail_rule_type', 0, 'success', '', '日期格式规则', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5023, 3, '数字格式', 'NUMBER', 'system_sequence_detail_rule_type', 0, 'info', '', '数字格式规则', 'admin', SYSDATE, 'admin', SYSDATE, 0), + (5024, 4, '自定义格式', 'CUSTOM', 'system_sequence_detail_rule_type', 0, 'warning', '', '自定义格式规则', 'admin', SYSDATE, 'admin', SYSDATE, 0); From 812e9727aed793a7fd6fa5911fa145a08b04283b Mon Sep 17 00:00:00 2001 From: hewencai <2357300448@qq.com> Date: Mon, 29 Dec 2025 16:16:06 +0800 Subject: [PATCH 42/48] =?UTF-8?q?fix:=E6=B7=BB=E5=8A=A0seata=E8=BE=BE?= =?UTF-8?q?=E6=A2=A6=E6=95=B0=E6=8D=AE=E5=BA=93=E5=85=BC=E5=AE=B9=E8=A1=A5?= =?UTF-8?q?=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-module-system/zt-module-system-server/pom.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/zt-module-system/zt-module-system-server/pom.xml b/zt-module-system/zt-module-system-server/pom.xml index 71cc87f0..b20de884 100644 --- a/zt-module-system/zt-module-system-server/pom.xml +++ b/zt-module-system/zt-module-system-server/pom.xml @@ -137,7 +137,12 @@ com.zt.plat zt-spring-boot-starter-monitor - + + + com.zt.plat + zt-spring-boot-starter-seata-dm + ${revision} + org.apache.seata @@ -190,6 +195,10 @@ com.zt.plat zt-spring-boot-starter-mq + + cn.hutool + hutool-all + From 179c22e4099144c7bbf8e2ccee53cd70c33c94d3 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 30 Dec 2025 10:32:30 +0800 Subject: [PATCH 43/48] =?UTF-8?q?1.=20=E5=9B=BA=E5=AE=9A=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E7=BD=91=E5=85=B3=E5=9C=B0=E5=9D=80=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E8=A2=AB=E4=BA=BA=E8=A6=86=E7=9B=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zt-gateway/src/main/resources/application.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zt-gateway/src/main/resources/application.yaml b/zt-gateway/src/main/resources/application.yaml index a9cfc07c..3426a39a 100644 --- a/zt-gateway/src/main/resources/application.yaml +++ b/zt-gateway/src/main/resources/application.yaml @@ -30,6 +30,8 @@ spring: username: ${config.username} # Nacos 账号 password: ${config.password} # Nacos 密码 discovery: # 【配置中心】配置项 + ip: 172.16.46.62 + port: 30092 namespace: ${config.namespace} # 命名空间。这里使用 maven Profile 资源过滤进行动态替换 group: ${config.group} # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP metadata: From b81e8c6df2824371fba35a4739d3b0da0b4501ac Mon Sep 17 00:00:00 2001 From: ranke <213539@qq.com> Date: Tue, 30 Dec 2025 18:07:58 +0800 Subject: [PATCH 44/48] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E7=AE=A1=E6=8E=A7=E6=8C=89=E9=92=AE=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E5=8F=AF=E7=94=A8=E9=85=8D=E7=BD=AE=E5=8A=9F=E8=83=BD?= =?UTF-8?q?.=20http://172.16.46.63:31560/index.php=3Fm=3Dtask&f=3Dview&tas?= =?UTF-8?q?kID=3D551?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 15 ++++++++++++++- sql/dm/bpm.sql | 2 ++ sql/dm/流程定义扩展信息表新增字段_20251230.sql | 10 ++++++++++ .../definition/vo/model/BpmModelMetaInfoVO.java | 4 ++++ .../admin/definition/vo/model/BpmModelRespVO.java | 1 + .../definition/vo/model/BpmModelSaveReqVO.java | 1 + .../convert/task/BpmProcessInstanceConvert.java | 13 ++++++++++--- .../definition/BpmProcessDefinitionInfoDO.java | 7 +++++++ 8 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 sql/dm/流程定义扩展信息表新增字段_20251230.sql diff --git a/pom.xml b/pom.xml index 7e0b370a..22c6cba2 100644 --- a/pom.xml +++ b/pom.xml @@ -219,7 +219,7 @@ ZT 中铜 ZStack 私服 - http://172.16.46.63:30708/repository/test/ + http://172.16.46.63:30708/repository/zt-cloud/ @@ -242,6 +242,19 @@ 1.0.0 + + klw-dev + + dev + + 172.16.46.63:30848 + klw + DEFAULT_GROUP + nacos + P@ssword25 + 1.0.0 + + env-prod diff --git a/sql/dm/bpm.sql b/sql/dm/bpm.sql index 04bc442b..a0501d50 100644 --- a/sql/dm/bpm.sql +++ b/sql/dm/bpm.sql @@ -120,6 +120,7 @@ CREATE TABLE bpm_process_definition_info ( simple_model text NULL, sort bigint DEFAULT 0 NULL, visible bit DEFAULT '1' NOT NULL, + restart bit DEFAULT '1' NOT NULL, start_user_ids varchar(256) DEFAULT NULL NULL, start_dept_ids varchar(256) DEFAULT NULL NULL, manager_user_ids varchar(256) DEFAULT NULL NULL, @@ -156,6 +157,7 @@ COMMENT ON COLUMN bpm_process_definition_info.form_custom_view_path IS '自定 COMMENT ON COLUMN bpm_process_definition_info.simple_model IS 'SIMPLE 设计器模型数据 JSON 格式'; COMMENT ON COLUMN bpm_process_definition_info.sort IS '排序值'; COMMENT ON COLUMN bpm_process_definition_info.visible IS '是否可见'; +COMMENT ON COLUMN bpm_process_definition_info.restart IS '是否允许重新发起'; COMMENT ON COLUMN bpm_process_definition_info.start_user_ids IS '可发起用户编号数组'; COMMENT ON COLUMN bpm_process_definition_info.start_dept_ids IS '可发起部门编号数组'; COMMENT ON COLUMN bpm_process_definition_info.manager_user_ids IS '可管理用户编号数组'; diff --git a/sql/dm/流程定义扩展信息表新增字段_20251230.sql b/sql/dm/流程定义扩展信息表新增字段_20251230.sql new file mode 100644 index 00000000..938b3946 --- /dev/null +++ b/sql/dm/流程定义扩展信息表新增字段_20251230.sql @@ -0,0 +1,10 @@ +-- 达梦8数据库DDL脚本 +-- 为 bpm_process_definition_info 表添加 restart 字段 + +-- 是否允许重新发起 +ALTER TABLE bpm_process_definition_info ADD COLUMN restart bit DEFAULT '1' NOT NULL; + +-- 添加字段注释 +COMMENT ON COLUMN bpm_process_definition_info.restart IS '是否允许重新发起'; + + diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java index cabc1fd1..dcc06fc9 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java @@ -56,6 +56,10 @@ public class BpmModelMetaInfoVO { @NotNull(message = "是否可见不能为空") private Boolean visible; + @Schema(description = "是否允许重新发起", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + @NotNull(message = "是否允许重新发起不能为空") + private Boolean restart; + @Schema(description = "可发起用户编号数组", example = "[1,2,3]") private List startUserIds; diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java index e0b32f3c..63ef57d5 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelRespVO.java @@ -5,6 +5,7 @@ import com.zt.plat.module.bpm.controller.admin.base.user.UserSimpleBaseVO; import com.zt.plat.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; import com.zt.plat.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; import lombok.Data; import java.time.LocalDateTime; diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java index 905e6166..6d573413 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java @@ -4,6 +4,7 @@ import com.zt.plat.module.bpm.controller.admin.definition.vo.model.simple.BpmSim import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; @Schema(description = "管理后台 - 流程模型的保存 Request VO") diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/convert/task/BpmProcessInstanceConvert.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/convert/task/BpmProcessInstanceConvert.java index 791e6949..87652f87 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -87,9 +87,16 @@ public interface BpmProcessInstanceConvert { }); } } - // 摘要 - respVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(respVO.getProcessDefinitionId()), - pageResult.getList().get(i).getProcessVariables())); + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionInfoMap.get(respVO.getProcessDefinitionId()); + if (processDefinitionInfo != null) { + // 摘要 + respVO.setSummary(FlowableUtils.getSummary(processDefinitionInfo, + pageResult.getList().get(i).getProcessVariables())); + // 是否可见 + respVO.getProcessDefinition().setVisible(processDefinitionInfo.getVisible()); + // 是否可以重新发起流程 + respVO.getProcessDefinition().setRestart(processDefinitionInfo.getRestart()); + } // 表单 respVO.setFormVariables(pageResult.getList().get(i).getProcessVariables()); } diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java index 0ebef4b0..349f4049 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java @@ -129,6 +129,13 @@ public class BpmProcessDefinitionInfoDO extends BaseDO { * 目的:如果 false 不可见,则不展示在“发起流程”的列表里 */ private Boolean visible; + + /** + * 是否允许重新发起 + * + * 目的:如果 false 则不可以重新发起流程 + */ + private Boolean restart; /** * 排序值 */ From 4579259973199a8e2758e6c2aa67a5740247f127 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 30 Dec 2025 18:27:47 +0800 Subject: [PATCH 45/48] =?UTF-8?q?1.=20=E6=81=A2=E5=A4=8D=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E7=A7=81=E6=9C=8D=E5=BA=93=E7=9A=84=E6=8C=87=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 22c6cba2..16bfa99f 100644 --- a/pom.xml +++ b/pom.xml @@ -219,7 +219,7 @@ ZT 中铜 ZStack 私服 - http://172.16.46.63:30708/repository/zt-cloud/ + http://172.16.46.63:30708/repository/test/ From 6ac75110191ec0d5eb6e5f9483be8b5a09da9b46 Mon Sep 17 00:00:00 2001 From: chenbowen Date: Tue, 30 Dec 2025 18:38:07 +0800 Subject: [PATCH 46/48] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BF=BD=E7=95=A5?= =?UTF-8?q?=E5=85=AC=E5=8F=B8=E4=BB=A5=E5=8F=8A=E9=83=A8=E9=97=A8=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=99=90=E7=9A=84=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/util/BusinessDeptHandleUtil.java | 4 + .../docs/数据权限忽略与上下文说明.md | 42 +++++++++++ .../ZtDataPermissionAutoConfiguration.java | 12 +++ .../CompanyDataPermissionIgnore.java | 21 ++++++ .../annotation/DeptDataPermissionIgnore.java | 21 ++++++ .../CompanyDataPermissionIgnoreAspect.java | 31 ++++++++ .../aop/DeptDataPermissionIgnoreAspect.java | 31 ++++++++ .../core/db/DataPermissionRuleHandler.java | 11 +++ .../company/CompanyDataPermissionRule.java | 5 ++ .../rule/dept/DeptDataPermissionRule.java | 21 ++++-- .../rule/dept/DeptDataPermissionRuleTest.java | 75 +++++++++++++++++-- 11 files changed, 261 insertions(+), 13 deletions(-) create mode 100644 zt-framework/zt-spring-boot-starter-biz-data-permission/docs/数据权限忽略与上下文说明.md create mode 100644 zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/CompanyDataPermissionIgnore.java create mode 100644 zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/DeptDataPermissionIgnore.java create mode 100644 zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/CompanyDataPermissionIgnoreAspect.java create mode 100644 zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/DeptDataPermissionIgnoreAspect.java diff --git a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/core/util/BusinessDeptHandleUtil.java b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/core/util/BusinessDeptHandleUtil.java index 03502d9c..0f18c4bb 100644 --- a/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/core/util/BusinessDeptHandleUtil.java +++ b/zt-framework/zt-spring-boot-starter-biz-business/src/main/java/com/zt/plat/framework/business/core/util/BusinessDeptHandleUtil.java @@ -8,6 +8,7 @@ import com.zt.plat.framework.common.util.json.JsonUtils; import com.zt.plat.framework.common.util.spring.SpringUtils; import com.zt.plat.framework.security.core.LoginUser; import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; +import com.zt.plat.framework.tenant.core.context.DeptContextHolder; import com.zt.plat.framework.web.core.util.WebFrameworkUtils; import com.zt.plat.module.system.api.dept.DeptApi; import com.zt.plat.module.system.api.dept.dto.CompanyDeptInfoRespDTO; @@ -197,6 +198,9 @@ public class BusinessDeptHandleUtil { } CompanyContextHolder.setIgnore(false); CompanyContextHolder.setCompanyId(Long.valueOf(info.getCompanyId())); + DeptContextHolder.setIgnore(false); + DeptContextHolder.setCompanyId(Long.valueOf(info.getCompanyId())); + DeptContextHolder.setDeptId(Long.valueOf(info.getDeptId())); return true; } } diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/docs/数据权限忽略与上下文说明.md b/zt-framework/zt-spring-boot-starter-biz-data-permission/docs/数据权限忽略与上下文说明.md new file mode 100644 index 00000000..669a0729 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/docs/数据权限忽略与上下文说明.md @@ -0,0 +1,42 @@ +# 数据权限忽略与上下文覆盖说明 + +本文说明新增的公司/部门数据权限忽略能力,以及部门上下文对数据权限的覆盖策略。 + +## 新增注解 + +- `@CompanyDataPermissionIgnore(enable = "true")` +- `@DeptDataPermissionIgnore(enable = "true")` + +用法: +- 可标记在类或方法上。 +- `enable` 支持 Spring EL,计算结果为 `true` 时生效,默认开启。 +- 生效后,在方法执行期间临时设置忽略标记,结束后自动恢复。 + +## 忽略生效范围 + +- 公司数据权限:切面在进入方法时将 `CompanyContextHolder.setIgnore(true)`,数据权限规则检测到后直接放行。 +- 部门数据权限:切面在进入方法时将 `DeptContextHolder.setIgnore(true)`,部门数据权限规则检测到后直接放行。 + +## 部门上下文覆盖策略 + +当未忽略部门数据权限且上下文存在有效部门 ID 时: +- 优先使用上下文中的单一部门作为过滤条件,避免因默认的 `ALL` 或“无部门且不可查看自己”导致放行或误判无权。 +- 上下文部门不会修改原有的数据权限 DTO,仅在当前计算中使用。 +- 若上下文公司与缓存公司不一致,会记录告警日志,但仍按上下文部门过滤。 + +## 典型场景 + +1) **任务/全局调用需要暂时关闭数据权限** + - 在方法上标记 `@DeptDataPermissionIgnore` 或 `@CompanyDataPermissionIgnore`。 + +2) **带部门上下文的接口调用** + - 请求预先设置 `DeptContextHolder.setContext(deptId, companyId)`。 + - 即便数据权限声明为 `all=true`,也会按该部门过滤,避免读出全量。 + +3) **无部门权限但指定了上下文部门** + - 即使 `deptIds` 为空且 `self=false`,只要上下文提供部门,也会使用该部门过滤,而非直接判定无权。 + +## 注意事项 + +- 忽略标记只作用于当前线程上下文,切面会在 `finally` 中恢复旧值,嵌套调用安全。 +- 若需要同时忽略公司与部门数据权限,可叠加两个注解或在业务代码中分别设置忽略标记。 diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/config/ZtDataPermissionAutoConfiguration.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/config/ZtDataPermissionAutoConfiguration.java index 0a1c5350..1c7d9e91 100644 --- a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/config/ZtDataPermissionAutoConfiguration.java +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/config/ZtDataPermissionAutoConfiguration.java @@ -1,6 +1,8 @@ package com.zt.plat.framework.datapermission.config; +import com.zt.plat.framework.datapermission.core.aop.CompanyDataPermissionIgnoreAspect; import com.zt.plat.framework.datapermission.core.aop.DataPermissionAnnotationAdvisor; +import com.zt.plat.framework.datapermission.core.aop.DeptDataPermissionIgnoreAspect; import com.zt.plat.framework.datapermission.core.db.DataPermissionRuleHandler; import com.zt.plat.framework.datapermission.core.rule.DataPermissionRule; import com.zt.plat.framework.datapermission.core.rule.DataPermissionRuleFactory; @@ -43,4 +45,14 @@ public class ZtDataPermissionAutoConfiguration { return new DataPermissionAnnotationAdvisor(); } + @Bean + public DeptDataPermissionIgnoreAspect deptDataPermissionIgnoreAspect() { + return new DeptDataPermissionIgnoreAspect(); + } + + @Bean + public CompanyDataPermissionIgnoreAspect companyDataPermissionIgnoreAspect() { + return new CompanyDataPermissionIgnoreAspect(); + } + } diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/CompanyDataPermissionIgnore.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/CompanyDataPermissionIgnore.java new file mode 100644 index 00000000..ecc4f1bb --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/CompanyDataPermissionIgnore.java @@ -0,0 +1,21 @@ +package com.zt.plat.framework.datapermission.core.annotation; + +import java.lang.annotation.*; + +/** + * 忽略公司数据权限的注解。 + *

+ * 标记在方法或类上时,匹配的调用会临时忽略公司类型的数据权限规则。 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface CompanyDataPermissionIgnore { + + /** + * 是否开启忽略,默认开启。 + * 支持 Spring EL 表达式,返回 true 时生效。 + */ + String enable() default "true"; +} \ No newline at end of file diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/DeptDataPermissionIgnore.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/DeptDataPermissionIgnore.java new file mode 100644 index 00000000..de80a7d1 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/annotation/DeptDataPermissionIgnore.java @@ -0,0 +1,21 @@ +package com.zt.plat.framework.datapermission.core.annotation; + +import java.lang.annotation.*; + +/** + * 忽略部门数据权限的注解。 + *

+ * 标记在方法或类上时,匹配的调用会临时忽略部门类型的数据权限规则。 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface DeptDataPermissionIgnore { + + /** + * 是否开启忽略,默认开启。 + * 支持 Spring EL 表达式,返回 true 时生效。 + */ + String enable() default "true"; +} \ No newline at end of file diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/CompanyDataPermissionIgnoreAspect.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/CompanyDataPermissionIgnoreAspect.java new file mode 100644 index 00000000..ae051a25 --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/CompanyDataPermissionIgnoreAspect.java @@ -0,0 +1,31 @@ +package com.zt.plat.framework.datapermission.core.aop; + +import com.zt.plat.framework.common.util.spring.SpringExpressionUtils; +import com.zt.plat.framework.datapermission.core.annotation.CompanyDataPermissionIgnore; +import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * 公司数据权限忽略切面,基于 {@link CompanyDataPermissionIgnore} 注解。 + */ +@Aspect +@Slf4j +public class CompanyDataPermissionIgnoreAspect { + + @Around("@within(companyDataPermissionIgnore) || @annotation(companyDataPermissionIgnore)") + public Object around(ProceedingJoinPoint joinPoint, CompanyDataPermissionIgnore companyDataPermissionIgnore) throws Throwable { + boolean oldIgnore = CompanyContextHolder.isIgnore(); + try { + Object enable = SpringExpressionUtils.parseExpression(companyDataPermissionIgnore.enable()); + if (Boolean.TRUE.equals(enable)) { + CompanyContextHolder.setIgnore(true); + } + return joinPoint.proceed(); + } finally { + CompanyContextHolder.setIgnore(oldIgnore); + } + } +} \ No newline at end of file diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/DeptDataPermissionIgnoreAspect.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/DeptDataPermissionIgnoreAspect.java new file mode 100644 index 00000000..4ee9054e --- /dev/null +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/aop/DeptDataPermissionIgnoreAspect.java @@ -0,0 +1,31 @@ +package com.zt.plat.framework.datapermission.core.aop; + +import com.zt.plat.framework.common.util.spring.SpringExpressionUtils; +import com.zt.plat.framework.datapermission.core.annotation.DeptDataPermissionIgnore; +import com.zt.plat.framework.tenant.core.context.DeptContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * 部门数据权限忽略切面,基于 {@link DeptDataPermissionIgnore} 注解。 + */ +@Aspect +@Slf4j +public class DeptDataPermissionIgnoreAspect { + + @Around("@within(deptDataPermissionIgnore) || @annotation(deptDataPermissionIgnore)") + public Object around(ProceedingJoinPoint joinPoint, DeptDataPermissionIgnore deptDataPermissionIgnore) throws Throwable { + boolean oldIgnore = DeptContextHolder.shouldIgnore(); + try { + Object enable = SpringExpressionUtils.parseExpression(deptDataPermissionIgnore.enable()); + if (Boolean.TRUE.equals(enable)) { + DeptContextHolder.setIgnore(true); + } + return joinPoint.proceed(); + } finally { + DeptContextHolder.setIgnore(oldIgnore); + } + } +} \ No newline at end of file diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/db/DataPermissionRuleHandler.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/db/DataPermissionRuleHandler.java index aa93b5fe..d23e9ac8 100644 --- a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/db/DataPermissionRuleHandler.java +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/db/DataPermissionRuleHandler.java @@ -10,7 +10,9 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.schema.Table; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static com.zt.plat.framework.security.core.util.SecurityFrameworkUtils.skipPermissionCheck; @@ -41,6 +43,7 @@ public class DataPermissionRuleHandler implements MultiDataPermissionHandler { } // 生成条件 + final Set processed = new HashSet<>(); Expression allExpression = null; for (DataPermissionRule rule : rules) { // 判断表名是否匹配 @@ -49,6 +52,14 @@ public class DataPermissionRuleHandler implements MultiDataPermissionHandler { continue; } + // 同一张表 + 同一别名 + 同一规则 在一次 SQL 解析内仅处理一次,避免重复拼接条件 + String aliasName = table.getAlias() == null ? "" : table.getAlias().getName(); + String key = tableName + "|" + aliasName + "|" + rule.getClass().getName(); + if (processed.contains(key)) { + continue; + } + processed.add(key); + // 单条规则的条件 Expression oneExpress = rule.getExpression(tableName, table.getAlias()); if (oneExpress == null) { diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/company/CompanyDataPermissionRule.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/company/CompanyDataPermissionRule.java index 5b46c28f..c02348c6 100644 --- a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/company/CompanyDataPermissionRule.java +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/company/CompanyDataPermissionRule.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil; import com.zt.plat.framework.common.util.collection.CollectionUtils; import com.zt.plat.framework.datapermission.core.rule.DataPermissionRule; import com.zt.plat.framework.mybatis.core.util.MyBatisUtils; +import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.*; @@ -46,6 +47,10 @@ public class CompanyDataPermissionRule implements DataPermissionRule { @Override public Expression getExpression(String tableName, Alias tableAlias) { + // 显式忽略公司数据权限时直接放行 + if (CompanyContextHolder.isIgnore()) { + return null; + } // 业务拼接 Company 的条件 if (getLoginUserCompanyId() == null) { // 如果没有登录用户的公司编号,则不需要拼接条件 diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java index e54a7f54..ea4a8a93 100644 --- a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/main/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java @@ -156,21 +156,28 @@ public class DeptDataPermissionRule implements DataPermissionRule { } } - // 情况一,如果是 ALL 可查看全部,则无需拼接条件 - if (deptDataPermission.getAll()) { + // 计算有效的部门与自查标记:当存在上下文部门且未被忽略时,强制仅使用该部门,以避免默认全量或空权限分支 + Set effectiveDeptIds = deptDataPermission.getDeptIds(); + Boolean effectiveSelf = deptDataPermission.getSelf(); + if (!DeptContextHolder.shouldIgnore() && ctxDeptId != null && ctxDeptId > 0L) { + effectiveDeptIds = CollUtil.newHashSet(ctxDeptId); + } + + // 情况一:仅当不存在上下文部门时,且 ALL 可查看全部,才无需拼接条件;若存在上下文部门则仍需基于该部门过滤 + if (ctxDeptId == null && deptDataPermission.getAll()) { return null; } - // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 - if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) - && Boolean.FALSE.equals(deptDataPermission.getSelf())) { + // 情况二:仅在有效部门集合为空且不可查看自己时,才认为无权限;若上下文提供部门,则跳过该兜底 + if (CollUtil.isEmpty(effectiveDeptIds) + && Boolean.FALSE.equals(effectiveSelf)) { return new EqualsTo(null, null); // WHERE null = null,可以保证返回的数据为空 } // 情况三,拼接 Dept 和 Company User 的条件,最后组合 - Expression deptExpression = buildDeptExpression(tableName, tableAlias, deptDataPermission.getDeptIds()); + Expression deptExpression = buildDeptExpression(tableName, tableAlias, effectiveDeptIds); // Expression deptExpression = buildDeptExpression(tableName, tableAlias, deptDataPermission.getDeptIds()); - Expression userExpression = buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId()); + Expression userExpression = buildUserExpression(tableName, tableAlias, effectiveSelf, loginUser.getId()); if (deptExpression == null && userExpression == null) { // TODO ZT:获得不到条件的时候,暂时不抛出异常,而是不返回数据 log.warn("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]", diff --git a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java index 77f194ce..e68941db 100644 --- a/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java +++ b/zt-framework/zt-spring-boot-starter-biz-data-permission/src/test/java/com/zt/plat/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java @@ -264,7 +264,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { } } - @Test // 上下文部门存在且公司一致时,清空原集合并覆盖为单一 deptId + @Test // 上下文部门存在且公司一致时,表达式按上下文 deptId 生效,但不修改原数据权限集合 void testGetExpression_deptContextOverride_companyMatch() { try (MockedStatic secMock = mockStatic(SecurityFrameworkUtils.class); MockedStatic deptCtxMock = mockStatic(DeptContextHolder.class); @@ -292,12 +292,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { Expression expression = rule.getExpression(tableName, tableAlias); assertEquals("u.dept_id IN (99)", expression.toString()); - assertEquals(CollUtil.newLinkedHashSet(99L), deptDataPermission.getDeptIds()); + // 原始权限对象不被修改,只是临时使用上下文 deptId 计算 + assertEquals(CollUtil.newLinkedHashSet(10L, 20L), deptDataPermission.getDeptIds()); assertEquals(1L, deptDataPermission.getCompanyId()); } } - @Test // 上下文部门存在但公司不一致时,记录告警并保持原逻辑(不覆盖) + @Test // 上下文部门存在但公司不一致时,仍按上下文 deptId 过滤,原数据权限保持不变 void testGetExpression_deptContextOverride_companyMismatch() { try (MockedStatic secMock = mockStatic(SecurityFrameworkUtils.class); MockedStatic deptCtxMock = mockStatic(DeptContextHolder.class); @@ -324,10 +325,72 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { Expression expression = rule.getExpression(tableName, tableAlias); - assertEquals("u.dept_id IN (10)", expression.toString()); - assertEquals(CollUtil.newLinkedHashSet(10L), deptDataPermission.getDeptIds()); - assertEquals(1L, deptDataPermission.getCompanyId()); + assertEquals("u.dept_id IN (99)", expression.toString()); + // 原始权限对象不被修改 + assertEquals(CollUtil.newLinkedHashSet(10L), deptDataPermission.getDeptIds()); + assertEquals(1L, deptDataPermission.getCompanyId()); } } + @Test // ALL 权限但存在上下文部门时,仍按上下文部门过滤 + void testGetExpression_allPermission_withCtxDept() { + try (MockedStatic secMock = mockStatic(SecurityFrameworkUtils.class); + MockedStatic deptCtxMock = mockStatic(DeptContextHolder.class); + MockedStatic companyCtxMock = mockStatic(CompanyContextHolder.class)) { + + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + secMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setAll(true) + .setDeptIds(CollUtil.newLinkedHashSet(10L)); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(success(deptDataPermission)); + + deptCtxMock.when(DeptContextHolder::shouldIgnore).thenReturn(false); + deptCtxMock.when(DeptContextHolder::getDeptId).thenReturn(99L); + deptCtxMock.when(DeptContextHolder::getCompanyId).thenReturn(1L); + companyCtxMock.when(CompanyContextHolder::getCompanyId).thenReturn(1L); + companyCtxMock.when(CompanyContextHolder::isIgnore).thenReturn(false); + + rule.addDeptColumn(tableName, "dept_id"); + + Expression expression = rule.getExpression(tableName, tableAlias); + + assertEquals("u.dept_id IN (99)", expression.toString()); + } + } + + @Test // 无部门且不可查看自己,但上下文提供部门时,应使用上下文部门而非判定无权限 + void testGetExpression_noDeptNoSelf_withCtxDept() { + try (MockedStatic secMock = mockStatic(SecurityFrameworkUtils.class); + MockedStatic deptCtxMock = mockStatic(DeptContextHolder.class); + MockedStatic companyCtxMock = mockStatic(CompanyContextHolder.class)) { + + String tableName = "t_user"; + Alias tableAlias = new Alias("u"); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); + secMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); + + DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() + .setSelf(false); + when(permissionApi.getDeptDataPermission(same(1L))).thenReturn(success(deptDataPermission)); + + deptCtxMock.when(DeptContextHolder::shouldIgnore).thenReturn(false); + deptCtxMock.when(DeptContextHolder::getDeptId).thenReturn(88L); + deptCtxMock.when(DeptContextHolder::getCompanyId).thenReturn(1L); + companyCtxMock.when(CompanyContextHolder::getCompanyId).thenReturn(1L); + companyCtxMock.when(CompanyContextHolder::isIgnore).thenReturn(false); + + rule.addDeptColumn(tableName, "dept_id"); + + Expression expression = rule.getExpression(tableName, tableAlias); + + assertEquals("u.dept_id IN (88)", expression.toString()); + } + } + } From 3573217507615d54c3c201f04ad39a5e6f63b1af Mon Sep 17 00:00:00 2001 From: maimaishu <14610861+maimaishu@user.noreply.gitee.com> Date: Wed, 31 Dec 2025 16:55:20 +0800 Subject: [PATCH 47/48] =?UTF-8?q?[+]=E5=A2=9E=E5=8A=A0=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E6=8E=A8=E5=8A=A8=E6=B6=88=E6=81=AF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zt/plat/module/system/api/esp/EspApi.java | 94 +++++++ .../module/system/api/esp/dto/EspDto.java | 27 ++ .../controller/admin/dept/EspController.java | 117 ++++++++ .../dept/vo/depexternalcode/EspPageReqVO.java | 25 ++ .../vo/depexternalcode/EspSaveRespVo.java | 28 ++ .../dal/dataobject/dept/DeptPushMsgDO.java | 58 ++++ .../system/dal/mysql/dept/EspMapper.java | 57 ++++ .../system/service/dept/EspServiceImpl.java | 256 ++++++++++++++++++ .../system/service/dept/IEspService.java | 79 ++++++ 9 files changed, 741 insertions(+) create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/EspApi.java create mode 100644 zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/dto/EspDto.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspPageReqVO.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspSaveRespVo.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/dataobject/dept/DeptPushMsgDO.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/EspServiceImpl.java create mode 100644 zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/IEspService.java diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/EspApi.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/EspApi.java new file mode 100644 index 00000000..a7c338a5 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/EspApi.java @@ -0,0 +1,94 @@ +package com.zt.plat.module.system.api.esp; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.util.collection.CollectionUtils; +import com.zt.plat.module.system.api.dept.dto.*; +import com.zt.plat.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@FeignClient(name = ApiConstants.NAME) +@Tag(name = "RPC 服务 - 部门") +public interface EspApi { + + String PREFIX = ApiConstants.PREFIX + "/dept"; + + // === 以下为补全的接口方法 === + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增部门") + CommonResult createDept(@RequestBody DeptSaveReqDTO createReqVO); + + @PutMapping(PREFIX + "/update") + @Operation(summary = "修改部门") + CommonResult updateDept(@RequestBody DeptSaveReqDTO updateReqVO); + + @DeleteMapping(PREFIX + "/delete") + @Operation(summary = "删除部门") + CommonResult deleteDept(@RequestParam("id") Long id); + + @PostMapping(PREFIX + "/list-all") + @Operation(summary = "获得部门列表") + CommonResult> getDeptList(@RequestBody DeptListReqDTO reqVO); + + @GetMapping(PREFIX + "/simple-list") + @Operation(summary = "获得部门精简信息列表") + CommonResult> getSimpleDeptList(); + + @GetMapping(PREFIX + "/simple-company-list") + @Operation(summary = "获得公司精简信息列表") + CommonResult> getSimpleCompanyList(); + + @GetMapping(PREFIX + "/all-company-list") + @Operation(summary = "获得所有公司精简信息列表") + CommonResult> getAllCompanyList(); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "获得部门信息") + @Parameter(name = "id", description = "部门编号", example = "1024", required = true) + CommonResult getDept(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/list") + @Operation(summary = "获得部门信息数组") + @Parameter(name = "ids", description = "部门编号数组", example = "1,2", required = true) + CommonResult> getDeptList(@RequestParam("ids") Collection ids); + + @GetMapping(PREFIX + "/valid") + @Operation(summary = "校验部门是否合法") + @Parameter(name = "ids", description = "部门编号数组", example = "1,2", required = true) + CommonResult validateDeptList(@RequestParam("ids") Collection ids); + + /** + * 获得指定编号的部门 Map + * + * @param ids 部门编号数组 + * @return 部门 Map + */ + default Map getDeptMap(Collection ids) { + List list = getDeptList(ids).getCheckedData(); + return CollectionUtils.convertMap(list, DeptRespDTO::getId); + } + + @GetMapping(PREFIX + "/list-child") + @Operation(summary = "获得指定部门的所有子部门") + @Parameter(name = "id", description = "部门编号", example = "1024", required = true) + CommonResult> getChildDeptList(@RequestParam("id") Long id); + + @GetMapping(PREFIX + "/company-dept-info") + @Operation(summary = "获得指定用户的公司部门信息") + @Parameter(name = "userId", description = "用户编号", example = "1", required = true) + CommonResult> getCompanyDeptInfoListByUserId(@RequestParam("userId") Long userId); + + // ========== 数据同步专用接口 ========== + + @PostMapping(PREFIX + "/sync") + @Operation(summary = "同步部门") + CommonResult syncDept(@RequestBody DeptSaveReqDTO syncReqDTO); + +} diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/dto/EspDto.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/dto/EspDto.java new file mode 100644 index 00000000..d69e1ab2 --- /dev/null +++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/api/esp/dto/EspDto.java @@ -0,0 +1,27 @@ +package com.zt.plat.module.system.api.esp.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.util.List; + +@Schema(description = "RPC 服务 - 推送外部系统配置信息 Response DTO") +@Data +public class EspDto { + + @Schema(description = "部门名称,模糊匹配", example = "ZT") + private String name; + + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") + private Integer status; + + @Schema(description = "是否公司", example = "false") + private Boolean isCompany; + + @Schema(description = "是否集团", example = "false") + private Boolean isGroup; + + @Schema(description = "部门编号集合,支持多部门查询", example = "[\"1001\", \"1002\"]") + private List ids; + + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java new file mode 100644 index 00000000..8ae5afa5 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java @@ -0,0 +1,117 @@ +package com.zt.plat.module.system.controller.admin.dept; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.pojo.PageResult; +import com.zt.plat.framework.common.util.object.BeanUtils; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspPageReqVO; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspSaveRespVo; +import com.zt.plat.module.system.dal.dataobject.dept.DeptDO; +import com.zt.plat.module.system.dal.dataobject.dept.DeptPushMsgDO; +import com.zt.plat.module.system.service.dept.DeptService; +import com.zt.plat.module.system.service.dept.IEspService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import static com.zt.plat.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 部门推送消息") +@RestController +@RequestMapping("/system/esp") +@Validated +public class EspController +{ + + @Resource + private IEspService espService; + @Resource + private DeptService deptService; + + @PostMapping("/create") + @Operation(summary = "创建部门推送消息") + @PreAuthorize("@ss.hasPermission('system:esp-external-code:create')") + public CommonResult create(@Valid @RequestBody EspSaveRespVo createReqVO) { + Long id = espService.createDeptPushMsg(createReqVO); + return success(id); + } + + @PutMapping("/update") + @Operation(summary = "修改部门推送消息") + @PreAuthorize("@ss.hasPermission('system:esp-external-code:update')") + public CommonResult update(@Valid @RequestBody EspSaveRespVo updateReqVO) { + espService.updateDeptPushMsg(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除部门推送消息") + @PreAuthorize("@ss.hasPermission('system:esp-external-code:delete')") + public CommonResult delete(@RequestParam("id") Long id) { + espService.deleteDeptPushMsg(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获取部门推送消息详情") + @PreAuthorize("@ss.hasPermission('system:esp-external-code:query')") + public CommonResult get(@RequestParam("id") Long id) { + DeptPushMsgDO entity = espService.getDeptPushMsgDetails(id); + EspSaveRespVo respVO = BeanUtils.toBean(entity, EspSaveRespVo.class); + fillDeptInfo(List.of(respVO)); + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "分页查询部门推送消息") + @PreAuthorize("@ss.hasPermission('system:esp-external-code:query')") + public CommonResult> page(@Valid EspPageReqVO reqVO) { + PageResult pageResult = espService.getDeptExternalCodePage(reqVO); + PageResult result = BeanUtils.toBean(pageResult, EspSaveRespVo.class); + fillDeptInfo(result.getList()); + return success(result); + } + + @GetMapping("/list-by-dept") + @Operation(summary = "根据部门部门推送消息") + @Parameter(name = "deptId", description = "部门编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:esp-external-code:query')") + public CommonResult> listByDept(@RequestParam("deptId") Long deptId) { + List list = espService.getPushMsgByDeptId(deptId); + List respList = BeanUtils.toBean(list, EspSaveRespVo.class); + fillDeptInfo(respList); + return success(respList); + } + + + + private void fillDeptInfo(List list) { + if (list == null || list.isEmpty()) { + return; + } + Set deptIds = list.stream() + .map(EspSaveRespVo::getDeptId) + .collect(Collectors.toCollection(HashSet::new)); + if (deptIds == null || deptIds.isEmpty()) { + return; + } + Map deptMap = deptService.getDeptList(deptIds).stream() + .collect(Collectors.toMap(DeptDO::getId, dept -> dept, (left, right) -> left)); + list.forEach(item -> { + DeptDO dept = deptMap.get(item.getDeptId()); + if (dept != null) { + item.setDeptName(dept.getName()); + item.setDeptCode(dept.getCode()); + } + }); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspPageReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspPageReqVO.java new file mode 100644 index 00000000..10e0ab8b --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspPageReqVO.java @@ -0,0 +1,25 @@ +package com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode; + +import com.zt.plat.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Schema(description = "管理后台 - 部门外部组织编码映射分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class EspPageReqVO extends PageParam { + + @Schema(description = "部门编号", example = "1024") + private Long deptId; + + @Schema(description = "外部系统标识", example = "ERP") + private String systemCode; + + @Schema(description = "外部组织编码", example = "100200") + private String externalDeptCode; + + @Schema(description = "状态", example = "0") + private Integer status; + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspSaveRespVo.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspSaveRespVo.java new file mode 100644 index 00000000..859ba772 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/vo/depexternalcode/EspSaveRespVo.java @@ -0,0 +1,28 @@ +package com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 部门外消息推送创建/修改 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class EspSaveRespVo extends DeptExternalCodeBaseVO { + + @Schema(description = "映射编号", example = "1024") + private Long id; + + @Schema(description = "所属部门名称", example = "技术部") + private String deptName; + + @Schema(description = "所属部门编码", example = "DEPT_001") + private String deptCode; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "最后更新时间") + private LocalDateTime updateTime; + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/dataobject/dept/DeptPushMsgDO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/dataobject/dept/DeptPushMsgDO.java new file mode 100644 index 00000000..237c28bc --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/dataobject/dept/DeptPushMsgDO.java @@ -0,0 +1,58 @@ +package com.zt.plat.module.system.dal.dataobject.dept; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.zt.plat.framework.common.enums.CommonStatusEnum; +import com.zt.plat.framework.tenant.core.db.TenantBaseDO; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 部门推送消息 DO + */ +@TableName("system_dept_push_msg") +@KeySequence("system_dept_push_msg_seq") +@Data +@EqualsAndHashCode(callSuper = true) +public class DeptPushMsgDO extends TenantBaseDO { + + /** + * 主键编号 + */ + @TableId(type = IdType.ASSIGN_ID) + private Long id; + + /** + * 本系统部门 ID + */ + private Long deptId; + + /** + * 外部系统标识 + */ + private String systemCode; + + /** + * 外部系统组织编码 + */ + private String externalDeptCode; + + /** + * 外部系统组织名称 + */ + private String externalDeptName; + + /** + * 映射状态 + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java new file mode 100644 index 00000000..7f4cc147 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java @@ -0,0 +1,57 @@ +package com.zt.plat.module.system.dal.mysql.dept; + +import com.zt.plat.framework.common.pojo.PageResult; +import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX; +import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspPageReqVO; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspSaveRespVo; +import com.zt.plat.module.system.dal.dataobject.dept.DeptPushMsgDO; +import org.apache.ibatis.annotations.Mapper; +import java.util.List; +/** + * 部门推送消息接口Mapper + */ +@Mapper +public interface EspMapper extends BaseMapperX { + + + /** + * 分页查询 + * @param reqVO 消息推送VO + * @return PageResult + */ + default PageResult selectPage(EspPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(DeptPushMsgDO::getDeptId,reqVO.getDeptId()) + .eqIfPresent(DeptPushMsgDO::getSystemCode, reqVO.getSystemCode()) + .likeIfPresent(DeptPushMsgDO::getExternalDeptCode, reqVO.getExternalDeptCode()) + .eqIfPresent(DeptPushMsgDO::getStatus, reqVO.getStatus()) + .orderByDesc(DeptPushMsgDO::getId)); + } + + + default DeptPushMsgDO selectBySystemCodeAndDeptId(String systemCode, Long deptId) { + return selectOne(new LambdaQueryWrapperX() + .eq(DeptPushMsgDO::getSystemCode, systemCode) + .eq(DeptPushMsgDO::getDeptId, deptId)); + } + + default DeptPushMsgDO selectBySystemCodeAndExternalCode(String systemCode, String externalDeptCode) { + return selectOne(new LambdaQueryWrapperX() + .eq(DeptPushMsgDO::getSystemCode, systemCode) + .eq(DeptPushMsgDO::getExternalDeptCode, externalDeptCode)); + } + + default List selectListByDeptId(Long deptId) { + return selectList(DeptPushMsgDO::getDeptId, deptId); + } + + default int deleteByDeptId(Long deptId) { + return delete(DeptPushMsgDO::getDeptId, deptId); + } + + default List selectListBySystemCode(String systemCode) { + return selectList(DeptPushMsgDO::getSystemCode, systemCode); + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/EspServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/EspServiceImpl.java new file mode 100644 index 00000000..bd746bfb --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/EspServiceImpl.java @@ -0,0 +1,256 @@ +package com.zt.plat.module.system.service.dept; + +import cn.hutool.core.util.StrUtil; +import com.zt.plat.framework.common.enums.CommonStatusEnum; +import com.zt.plat.framework.common.pojo.PageResult; +import com.zt.plat.framework.common.util.object.BeanUtils; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspPageReqVO; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspSaveRespVo; +import com.zt.plat.module.system.dal.dataobject.dept.DeptDO; +import com.zt.plat.module.system.dal.dataobject.dept.DeptPushMsgDO; +import com.zt.plat.module.system.dal.mysql.dept.DeptMapper; +import com.zt.plat.module.system.dal.mysql.dept.EspMapper; +import com.zt.plat.module.system.dal.redis.RedisKeyConstants; +import jakarta.annotation.Resource; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import java.util.List; +import java.util.Objects; +import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.zt.plat.module.system.enums.ErrorCodeConstants.*; + +/** + * 部门推送消息接口ServiceImpl实现类 + */ +@Service +@Validated +public class EspServiceImpl implements IEspService { + + @Resource + private EspMapper espMapper; + @Resource + private DeptMapper deptMapper; + @Resource + private CacheManager cacheManager; + + @Override + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_EXTERNAL_CODE_LIST, key = "#createReqVO.deptId", beforeInvocation = false) + public Long createDeptPushMsg(EspSaveRespVo createReqVO) { + + //请求校验 + normalizeRequest(createReqVO); + //冲突禁用-映射 + disableActiveMappingIfConflict(createReqVO.getDeptId(), createReqVO.getSystemCode(), createReqVO.getExternalDeptCode()); + validateForCreateOrUpdate(null, createReqVO.getDeptId(), createReqVO.getSystemCode(), + createReqVO.getExternalDeptCode()); + + DeptPushMsgDO entity = BeanUtils.toBean(createReqVO, DeptPushMsgDO.class); + if (entity.getStatus() == null) { + entity.setStatus(CommonStatusEnum.ENABLE.getStatus()); + } + espMapper.insert(entity); + return entity.getId(); + } + + @Override + public void updateDeptPushMsg(EspSaveRespVo updateReqVO) { + normalizeRequest(updateReqVO); + DeptPushMsgDO exists = validateExists(updateReqVO.getId()); + disableActiveMappingIfConflict(updateReqVO.getDeptId(), updateReqVO.getSystemCode(), updateReqVO.getExternalDeptCode()); + validateForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getDeptId(), updateReqVO.getSystemCode(), + updateReqVO.getExternalDeptCode()); + + DeptPushMsgDO updateObj = BeanUtils.toBean(updateReqVO, DeptPushMsgDO.class); + // 保持原有的状态默认值逻辑 + if (updateObj.getStatus() == null) { + updateObj.setStatus(exists.getStatus() == null ? CommonStatusEnum.ENABLE.getStatus() : exists.getStatus()); + } + espMapper.updateById(updateObj); + evictCacheSafely(exists.getDeptId()); + evictCacheSafely(updateObj.getDeptId()); + } + + @Override + public void deleteDeptPushMsg(Long id) { + DeptPushMsgDO exists = validateExists(id); + espMapper.deleteById(id); + evictCacheSafely(exists.getDeptId()); + } + + @Override + public DeptPushMsgDO getDeptPushMsgDetails(Long id) { + return espMapper.selectById(id); + } + + @Override + public PageResult getDeptExternalCodePage(EspPageReqVO reqVO) { + + return espMapper.selectPage(reqVO); + } + + @Override + @Cacheable(cacheNames = RedisKeyConstants.DEPT_EXTERNAL_CODE_LIST, key = "#deptId") + public List getPushMsgByDeptId(Long deptId) { + return espMapper.selectListByDeptId(deptId); + } + +/* @Override + public DeptExternalCodeDO getBySystemCodeAndExternalCode(String systemCode, String externalDeptCode) { + if (StrUtil.hasEmpty(systemCode, externalDeptCode)) { + return null; + } + return espMapper.selectBySystemCodeAndExternalCode(systemCode.trim(), externalDeptCode.trim()); + }*/ + +/* @Override + public DeptExternalCodeDO getBySystemCodeAndDeptId(String systemCode, Long deptId) { + if (StrUtil.isBlank(systemCode) || deptId == null) { + return null; + } + return espMapper.selectBySystemCodeAndDeptId(systemCode.trim(), deptId); + }*/ + +/* @Override + public Long getDeptPushMsgDetails(Long deptId, String systemCode, String externalDeptCode, + String externalDeptName, Integer status) { + + if (StrUtil.hasEmpty(systemCode, externalDeptCode) || deptId == null) { + return null; + } + String normalizedSystemCode = systemCode.trim(); + String normalizedExternalCode = externalDeptCode.trim(); + String normalizedExternalName = StrUtil.blankToDefault(StrUtil.trimToNull(externalDeptName), null); + + disableActiveMappingIfConflict(deptId, normalizedSystemCode, normalizedExternalCode); + + // 如果存在则更新,否则创建 + DeptExternalCodeDO exists = espMapper.selectBySystemCodeAndDeptId(normalizedSystemCode, deptId); + if (exists != null) { + DeptExternalCodeSaveReqVO updateReqVO = new DeptExternalCodeSaveReqVO(); + updateReqVO.setId(exists.getId()); + updateReqVO.setDeptId(deptId); + updateReqVO.setSystemCode(normalizedSystemCode); + updateReqVO.setExternalDeptCode(normalizedExternalCode); + updateReqVO.setExternalDeptName(normalizedExternalName); + updateReqVO.setStatus(status == null ? exists.getStatus() : status); + + //TODO + //getDeptPushMsgDetails(updateReqVO); + return exists.getId(); + } + + DeptExternalCodeSaveReqVO createReqVO = new DeptExternalCodeSaveReqVO(); + createReqVO.setDeptId(deptId); + createReqVO.setSystemCode(normalizedSystemCode); + createReqVO.setExternalDeptCode(normalizedExternalCode); + createReqVO.setExternalDeptName(normalizedExternalName); + createReqVO.setStatus(status == null ? CommonStatusEnum.ENABLE.getStatus() : status); + return getDeptPushMsgDetails(createReqVO); + }*/ + +/* @Override + public void deleteDeptExternalCodesByDeptId(Long deptId) { + if (deptId == null) { + return; + } + espMapper.deleteByDeptId(deptId); + evictCacheSafely(deptId); + }*/ + + private DeptPushMsgDO validateExists(Long id) { + if (id == null) { + throw exception(DEPT_EXTERNAL_RELATION_NOT_EXISTS); + } + DeptPushMsgDO entity = espMapper.selectById(id); + if (entity == null) { + throw exception(DEPT_EXTERNAL_RELATION_NOT_EXISTS); + } + return entity; + } + + private void validateForCreateOrUpdate(Long id, Long deptId, String systemCode, String externalDeptCode) { + + // 校验部门存在 + DeptDO dept = deptMapper.selectById(deptId); + if (dept == null) { + throw exception(DEPT_NOT_FOUND); + } + String normalizedSystemCode = StrUtil.blankToDefault(systemCode, null); + String normalizedExternalCode = StrUtil.blankToDefault(externalDeptCode, null); + + // 校验同一系统下部门唯一 + if (StrUtil.isNotBlank(normalizedSystemCode)) { + DeptPushMsgDO sameDept = espMapper + .selectBySystemCodeAndDeptId(normalizedSystemCode, deptId); + if (sameDept != null && (id == null || !sameDept.getId().equals(id))) { + throw exception(DEPT_EXTERNAL_RELATION_EXISTS, normalizedSystemCode); + } + } + // 校验同一系统下外部编码唯一 + if (StrUtil.isNotBlank(normalizedSystemCode) && StrUtil.isNotBlank(normalizedExternalCode)) { + DeptPushMsgDO sameExternal = espMapper + .selectBySystemCodeAndExternalCode(normalizedSystemCode, normalizedExternalCode); + if (sameExternal != null && (id == null || !sameExternal.getId().equals(id))) { + boolean sameDept = Objects.equals(deptId, sameExternal.getDeptId()); + boolean activeConflict = !sameDept && CommonStatusEnum.isEnable(sameExternal.getStatus()); + if (activeConflict) { + throw exception(DEPT_EXTERNAL_CODE_DUPLICATE, normalizedSystemCode, normalizedExternalCode); + } + } + } + } + + private void normalizeRequest(EspSaveRespVo reqVO) { + if (reqVO == null) { + return; + } + if (StrUtil.isNotBlank(reqVO.getSystemCode())) { + reqVO.setSystemCode(reqVO.getSystemCode().trim()); + } + if (StrUtil.isNotBlank(reqVO.getExternalDeptCode())) { + reqVO.setExternalDeptCode(reqVO.getExternalDeptCode().trim()); + } + if (reqVO.getStatus() == null) { + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + } + } + + private void disableActiveMappingIfConflict(Long targetDeptId, String systemCode, String externalDeptCode) { + String normalizedSystem = StrUtil.trimToNull(systemCode); + String normalizedExternal = StrUtil.trimToNull(externalDeptCode); + if (StrUtil.hasEmpty(normalizedSystem, normalizedExternal) || targetDeptId == null) { + return; + } + DeptPushMsgDO existing = espMapper.selectBySystemCodeAndExternalCode(normalizedSystem, normalizedExternal); + if (existing == null) { + return; + } + if (Objects.equals(existing.getDeptId(), targetDeptId)) { + return; + } + if (CommonStatusEnum.isEnable(existing.getStatus())) { + DeptPushMsgDO update = new DeptPushMsgDO(); + update.setId(existing.getId()); + update.setStatus(CommonStatusEnum.DISABLE.getStatus()); + espMapper.updateById(update); + evictCacheSafely(existing.getDeptId()); + } + } + + private void evictCacheSafely(Long deptId) { + + if (deptId == null || cacheManager == null) { + return; + } + try { + if (cacheManager.getCache(RedisKeyConstants.DEPT_EXTERNAL_CODE_LIST) != null) { + cacheManager.getCache(RedisKeyConstants.DEPT_EXTERNAL_CODE_LIST).evict(deptId); + } + } catch (Exception ignore) { + // 缓存失效失败不影响主流程 + } + } +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/IEspService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/IEspService.java new file mode 100644 index 00000000..97c83454 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/dept/IEspService.java @@ -0,0 +1,79 @@ +package com.zt.plat.module.system.service.dept; + +import com.zt.plat.framework.common.pojo.PageResult; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspPageReqVO; +import com.zt.plat.module.system.controller.admin.dept.vo.depexternalcode.EspSaveRespVo; +import com.zt.plat.module.system.dal.dataobject.dept.DeptPushMsgDO; + +import java.util.List; + +/** + * 部门推送消息 Service 接口 + */ +public interface IEspService { + + /** + * 创建映射关系 + * @param createReqVO 创建请求 + * @return 新增记录编号 + */ + Long createDeptPushMsg(EspSaveRespVo createReqVO); + + /** + * 更新映射关系 + * @param updateReqVO 更新请求 + */ + void updateDeptPushMsg(EspSaveRespVo updateReqVO); + + /** + * 删除映射关系 + * + * @param id 记录编号 + */ + void deleteDeptPushMsg(Long id); + + /** + * 获取映射详情 + */ + DeptPushMsgDO getDeptPushMsgDetails(Long id); + + /** + * 分页查询映射 + */ + PageResult getDeptExternalCodePage(EspPageReqVO reqVO); + + /** + * 根据部门推送消息 + */ + List getPushMsgByDeptId(Long deptId); + + /** + * 根据部门与外部系统保存/更新映射(存在则更新,不存在则创建) + * @param deptId 本系统部门 ID + * @param systemCode 外部系统标识 + * @param externalDeptCode 外部系统组织编码 + * @param externalDeptName 外部系统组织名称(可选) + * @param status 状态,默认启用 + * @return 映射记录 ID + */ + /* Long getDeptPushMsgDetails(Long deptId, String systemCode, String externalDeptCode, String externalDeptName, + Integer status);*/ + + /** + * 根据部门删除全部外部编码映射 + * + * @param deptId 部门编号 + */ + //void deleteDeptExternalCodesByDeptId(Long deptId); + + /** + * 根据外部系统与外部组织编码查询映射 + */ + //DeptExternalCodeDO getBySystemCodeAndExternalCode(String systemCode, String externalDeptCode); + + /** + * 根据外部系统与部门编号查询映射 + */ + //DeptExternalCodeDO getBySystemCodeAndDeptId(String systemCode, Long deptId); + +} From 7bd44ffca9b800bcdb093f2e14881d8b2bff4f53 Mon Sep 17 00:00:00 2001 From: ranke <213539@qq.com> Date: Wed, 31 Dec 2025 17:06:51 +0800 Subject: [PATCH 48/48] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=AE=9E=E4=BE=8BID=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=8A=84=E9=80=81=E8=AE=B0=E5=BD=95=E7=9A=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?,=E7=94=A8=E4=BA=8E=E5=BE=85=E5=8A=9E=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E4=B8=AD=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceController.java | 35 ++++++++ .../vo/instance/BpmProcessInstanceCopyVO.java | 88 +++++++++++++++++++ .../task/BpmProcessInstanceCopyMapper.java | 6 ++ .../task/BpmProcessInstanceCopyService.java | 9 ++ .../BpmProcessInstanceCopyServiceImpl.java | 5 ++ .../src/main/resources/logback-spring.xml | 4 + 6 files changed, 147 insertions(+) create mode 100644 zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyVO.java diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/BpmProcessInstanceController.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/BpmProcessInstanceController.java index 53ea6faf..d55f27a0 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/BpmProcessInstanceController.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/BpmProcessInstanceController.java @@ -1,5 +1,6 @@ package com.zt.plat.module.bpm.controller.admin.task; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.zt.plat.framework.business.core.util.DeptUtil; @@ -11,8 +12,10 @@ import com.zt.plat.module.bpm.controller.admin.task.vo.instance.*; import com.zt.plat.module.bpm.convert.task.BpmProcessInstanceConvert; import com.zt.plat.module.bpm.dal.dataobject.definition.BpmCategoryDO; import com.zt.plat.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import com.zt.plat.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; import com.zt.plat.module.bpm.service.definition.BpmCategoryService; import com.zt.plat.module.bpm.service.definition.BpmProcessDefinitionService; +import com.zt.plat.module.bpm.service.task.BpmProcessInstanceCopyService; import com.zt.plat.module.bpm.service.task.BpmProcessInstanceService; import com.zt.plat.module.bpm.service.task.BpmTaskService; import com.zt.plat.module.system.api.dept.DeptApi; @@ -24,6 +27,8 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.list.SetUniqueList; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.task.api.Task; @@ -31,6 +36,8 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -53,6 +60,8 @@ public class BpmProcessInstanceController { private BpmProcessDefinitionService processDefinitionService; @Resource private BpmCategoryService categoryService; + @Resource + private BpmProcessInstanceCopyService processInstanceCopyService; @Resource private AdminUserApi adminUserApi; @@ -181,6 +190,32 @@ public class BpmProcessInstanceController { return success(processInstanceService.getApprovalDetail(getLoginUserId(), reqVO)); } + @GetMapping("/copy-list-by-process-instance-id") + @Operation(summary = "根据流程实例编号获取抄送列表") + @Parameter(name = "id", description = "流程实例的编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") + public CommonResult> getCopyListByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) { + List copyDOList = processInstanceCopyService.getByProcessInstanceId(processInstanceId); + if (CollectionUtils.isEmpty(copyDOList)) { + return success(new ArrayList<>(0)); + } + List copyVOList = new ArrayList<>(copyDOList.size()); + SetUniqueList userIdList = SetUniqueList.setUniqueList(new ArrayList<>()); + for (BpmProcessInstanceCopyDO copyDO : copyDOList) { + BpmProcessInstanceCopyVO copyVO = new BpmProcessInstanceCopyVO(); + BeanUtil.copyProperties(copyDO, copyVO); + copyVOList.add(copyVO); + userIdList.add(copyDO.getStartUserId()); + userIdList.add(copyDO.getUserId()); + } + Map userMap = adminUserApi.getUserMap(userIdList); + for (BpmProcessInstanceCopyVO copyVO : copyVOList) { + copyVO.setStartUserName(userMap.get(copyVO.getStartUserId()).getNickname()); + copyVO.setUserName(userMap.get(copyVO.getUserId()).getNickname()); + } + return success(copyVOList); + } + @GetMapping("/get-next-approval-nodes") @Operation(summary = "获取下一个执行的流程节点") @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyVO.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyVO.java new file mode 100644 index 00000000..0012c190 --- /dev/null +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyVO.java @@ -0,0 +1,88 @@ +package com.zt.plat.module.bpm.controller.admin.task.vo.instance; + +import com.zt.plat.framework.mybatis.core.dataobject.BaseDO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 流程抄送 VO + * + * @author kr + * @since 2025-12-31 + */ +@Data +@NoArgsConstructor +public class BpmProcessInstanceCopyVO extends BaseDO { + + /** + * 编号 + */ + private Long id; + + /** + * 发起人 Id + */ + @Schema(description ="发起人 Id") + private Long startUserId; + + /** + * 发起人 姓名 + */ + @Schema(description ="发起人 姓名") + private String startUserName; + /** + * 流程名 + */ + @Schema(description ="流程名") + private String processInstanceName; + /** + * 流程实例的编号 + */ + @Schema(description ="流程实例的编号") + private String processInstanceId; + /** + * 流程实例的流程定义编号 + */ + @Schema(description ="流程实例的流程定义编号") + private String processDefinitionId; + /** + * 流程分类 + */ + @Schema(description ="流程分类") + private String category; + /** + * 流程活动的编号 + */ + @Schema(description ="流程活动的编号") + private String activityId; + /** + * 流程活动的名字 + */ + @Schema(description ="流程活动的名字") + private String activityName; + /** + * 流程活动的编号 + */ + @Schema(description ="流程活动的编号") + private String taskId; + + /** + * 用户编号(被抄送的用户编号) + */ + @Schema(description ="用户编号(被抄送的用户编号)") + private Long userId; + + /** + * 用户姓名(被抄送的用户姓名) + */ + @Schema(description ="用户姓名(被抄送的用户姓名)") + private String userName; + + /** + * 抄送意见 + */ + @Schema(description ="抄送意见") + private String reason; + +} diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java index 61a73c3c..b35d217d 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/dal/mysql/task/BpmProcessInstanceCopyMapper.java @@ -7,6 +7,8 @@ import com.zt.plat.module.bpm.controller.admin.task.vo.instance.BpmProcessInstan import com.zt.plat.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + @Mapper public interface BpmProcessInstanceCopyMapper extends BaseMapperX { @@ -22,4 +24,8 @@ public interface BpmProcessInstanceCopyMapper extends BaseMapperX getByProcessInstanceId(String processInstanceId) { + return selectList(BpmProcessInstanceCopyDO::getProcessInstanceId, processInstanceId); + } + } diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyService.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyService.java index e5f06b6f..76350bc8 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyService.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyService.java @@ -7,6 +7,7 @@ import jakarta.validation.constraints.NotEmpty; import org.flowable.bpmn.model.FlowNode; import java.util.Collection; +import java.util.List; /** * 流程抄送 Service 接口 @@ -57,4 +58,12 @@ public interface BpmProcessInstanceCopyService { */ void deleteProcessInstanceCopy(String processInstanceId); + /** + * 获得流程的抄送列表 + * + * @param processInstanceId 流程实例 ID + * @return 抄送流程列表 + */ + List getByProcessInstanceId(String processInstanceId); + } diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java index dd842b9f..5fec3947 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java +++ b/zt-module-bpm/zt-module-bpm-server/src/main/java/com/zt/plat/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java @@ -93,4 +93,9 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy processInstanceCopyMapper.deleteByProcessInstanceId(processInstanceId); } + @Override + public List getByProcessInstanceId(String processInstanceId) { + return processInstanceCopyMapper.getByProcessInstanceId(processInstanceId); + } + } diff --git a/zt-module-bpm/zt-module-bpm-server/src/main/resources/logback-spring.xml b/zt-module-bpm/zt-module-bpm-server/src/main/resources/logback-spring.xml index 0e551414..51a9a489 100644 --- a/zt-module-bpm/zt-module-bpm-server/src/main/resources/logback-spring.xml +++ b/zt-module-bpm/zt-module-bpm-server/src/main/resources/logback-spring.xml @@ -73,4 +73,8 @@ + + + +