diff --git a/pom.xml b/pom.xml
index 5d3aaae6..ec3a433d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,9 +16,7 @@
yudao-module-system
yudao-module-infra
-
yudao-module-bpm
-
yudao-module-report
yudao-module-mp
diff --git a/sql/dm/e 办同步信息日志表结构.sql b/sql/dm/e 办同步信息日志表结构.sql
new file mode 100644
index 00000000..985ac26c
--- /dev/null
+++ b/sql/dm/e 办同步信息日志表结构.sql
@@ -0,0 +1,83 @@
+/*
+ Yudao Database Transfer Tool
+
+ Source Server Type : MySQL
+
+ Target Server Type : DM8
+
+ Date: 2025-08-28 14:12:23
+*/
+
+
+-- ----------------------------
+-- Table structure for system_sync_log
+-- ----------------------------
+CREATE TABLE system_sync_log (
+ id bigint NOT NULL PRIMARY KEY,
+ bim_request_id varchar(64) DEFAULT '' NULL,
+ service_name varchar(100) NOT NULL,
+ request_method varchar(16) DEFAULT 'POST' NOT NULL,
+ request_url varchar(500) NOT NULL,
+ client_ip varchar(50) NOT NULL,
+ user_agent varchar(512) DEFAULT NULL NULL,
+ request_time datetime NOT NULL,
+ response_time datetime DEFAULT NULL NULL,
+ duration bigint DEFAULT NULL NULL,
+ encrypted_request text NOT NULL,
+ decrypted_request text NULL,
+ status smallint DEFAULT 0 NOT NULL,
+ error_code varchar(100) DEFAULT NULL NULL,
+ error_message varchar(1000) DEFAULT NULL NULL,
+ exception_stack text NULL,
+ response_data text NULL,
+ encrypted_response text NULL,
+ auth_user varchar(100) DEFAULT NULL NULL,
+ decrypt_status smallint DEFAULT 0 NOT NULL,
+ signature_verify_status smallint DEFAULT 0 NOT NULL,
+ auth_status smallint DEFAULT 0 NOT NULL,
+ business_result varchar(100) DEFAULT NULL NULL,
+ extra text NULL,
+ creator varchar(64) DEFAULT '' NULL,
+ create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updater varchar(64) DEFAULT '' NULL,
+ update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ deleted bit DEFAULT '0' NOT NULL
+);
+
+CREATE INDEX idx_system_sync_log_01 ON system_sync_log (bim_request_id);
+CREATE INDEX idx_system_sync_log_02 ON system_sync_log (service_name);
+CREATE INDEX idx_system_sync_log_03 ON system_sync_log (request_time);
+CREATE INDEX idx_system_sync_log_04 ON system_sync_log (status);
+CREATE INDEX idx_system_sync_log_05 ON system_sync_log (client_ip);
+CREATE INDEX idx_system_sync_log_06 ON system_sync_log (auth_user);
+
+COMMENT ON COLUMN system_sync_log.id IS '日志主键';
+COMMENT ON COLUMN system_sync_log.bim_request_id IS '外部请求ID';
+COMMENT ON COLUMN system_sync_log.service_name IS '接口名称/服务名称';
+COMMENT ON COLUMN system_sync_log.request_method IS '请求方法';
+COMMENT ON COLUMN system_sync_log.request_url IS '请求URL';
+COMMENT ON COLUMN system_sync_log.client_ip IS '客户端IP地址';
+COMMENT ON COLUMN system_sync_log.user_agent IS '用户代理字符串';
+COMMENT ON COLUMN system_sync_log.request_time IS '请求开始时间';
+COMMENT ON COLUMN system_sync_log.response_time IS '请求结束时间';
+COMMENT ON COLUMN system_sync_log.duration IS '请求处理耗时(毫秒)';
+COMMENT ON COLUMN system_sync_log.encrypted_request IS '原始加密请求体';
+COMMENT ON COLUMN system_sync_log.decrypted_request IS '解密后的请求体';
+COMMENT ON COLUMN system_sync_log.status IS '响应状态 0-成功 1-解密失败 2-签名验证失败 3-认证失败 4-业务处理失败 5-系统异常';
+COMMENT ON COLUMN system_sync_log.error_code IS '错误码';
+COMMENT ON COLUMN system_sync_log.error_message IS '错误信息';
+COMMENT ON COLUMN system_sync_log.exception_stack IS '异常堆栈';
+COMMENT ON COLUMN system_sync_log.response_data IS '响应数据(加密前)';
+COMMENT ON COLUMN system_sync_log.encrypted_response IS '加密后的响应数据';
+COMMENT ON COLUMN system_sync_log.auth_user IS '认证用户';
+COMMENT ON COLUMN system_sync_log.decrypt_status IS '解密状态 0-成功 1-失败';
+COMMENT ON COLUMN system_sync_log.signature_verify_status IS '签名验证状态 0-成功 1-失败';
+COMMENT ON COLUMN system_sync_log.auth_status IS '认证状态 0-成功 1-失败';
+COMMENT ON COLUMN system_sync_log.business_result IS '业务处理结果';
+COMMENT ON COLUMN system_sync_log.extra IS '额外信息';
+COMMENT ON COLUMN system_sync_log.creator IS '创建者';
+COMMENT ON COLUMN system_sync_log.create_time IS '创建时间';
+COMMENT ON COLUMN system_sync_log.updater IS '更新者';
+COMMENT ON COLUMN system_sync_log.update_time IS '更新时间';
+COMMENT ON COLUMN system_sync_log.deleted IS '是否删除';
+COMMENT ON TABLE system_sync_log IS '同步接口调用日志表';
diff --git a/sql/dm/在线文档管理菜单.sql b/sql/dm/在线文档管理菜单.sql
new file mode 100644
index 00000000..ec698c8b
--- /dev/null
+++ b/sql/dm/在线文档管理菜单.sql
@@ -0,0 +1,39 @@
+-- 在线文档管理功能菜单数据(DM 格式)
+-- 说明:达梦脚本使用与 patch.sql 相同的精简列形式,省略布尔列与时间列,使用默认值。
+
+-- 清理旧数据,保持可重复执行
+DELETE FROM system_menu WHERE id IN (6000,6001,6002,600101,600102,600103,600104,600105,600106,600107,600108,600109,600110);
+
+-- 顶级目录(父级假定已存在 id=2 的“基础设施/Infra”或同级目录)
+INSERT INTO system_menu (
+ id, name, permission, type, sort, parent_id,
+ path, icon, component, status, component_name
+) VALUES (
+ 6000, '在线文档', '', 1, 15, 2,
+ 'doc', 'fa:file-text-o', '', 0, NULL
+);
+
+-- 文档管理主页面
+INSERT INTO system_menu (
+ id, name, permission, type, sort, parent_id,
+ path, icon, component, status, component_name
+) VALUES (
+ 6001, '文档管理', 'infra:doc:query', 2, 1, 6000,
+ 'doc-file', 'fa:file-text', 'infra/doc/index', 0, 'DocFile'
+);
+
+-- 按钮权限(操作项)
+INSERT INTO system_menu (
+ id, name, permission, type, sort, parent_id,
+ path, icon, component, status
+) VALUES
+ (600101,'文档查询','infra:doc:query',3,1,6001,'','','',0),
+ (600102,'文档创建','infra:doc:create',3,2,6001,'','','',0),
+ (600103,'文档更新','infra:doc:update',3,3,6001,'','','',0),
+ (600104,'文档删除','infra:doc:delete',3,4,6001,'','','',0),
+ (600105,'文档导出','infra:doc:export',3,5,6001,'','','',0),
+ (600106,'文档上传','infra:doc:upload',3,6,6001,'','','',0),
+ (600107,'文档编辑','infra:doc:edit',3,7,6001,'','','',0),
+ (600108,'文档预览','infra:doc:preview',3,8,6001,'','','',0),
+ (600109,'文档下载','infra:doc:download',3,9,6001,'','','',0),
+ (600110,'权限管理','infra:doc:permission',3,10,6001,'','','',0);
diff --git a/sql/dm/在线文档管理表结构.sql b/sql/dm/在线文档管理表结构.sql
new file mode 100644
index 00000000..5dbde549
--- /dev/null
+++ b/sql/dm/在线文档管理表结构.sql
@@ -0,0 +1,144 @@
+/*
+ Yudao Database Transfer Tool
+
+ Source Server Type : MySQL
+
+ Target Server Type : DM8
+
+ Date: 2025-08-29 10:32:27
+*/
+
+
+-- ----------------------------
+-- Table structure for infra_doc_file
+-- ----------------------------
+CREATE TABLE infra_doc_file (
+ id bigint NOT NULL PRIMARY KEY,
+ title varchar(255) NOT NULL,
+ file_id bigint DEFAULT NULL NULL,
+ file_type varchar(10) NOT NULL,
+ space_type smallint DEFAULT '1' NOT NULL,
+ description varchar(500) DEFAULT NULL NULL,
+ latest_version_id bigint DEFAULT NULL NULL,
+ owner_user_id bigint NOT 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,
+ update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ deleted bit DEFAULT '0' NOT NULL,
+ tenant_id bigint DEFAULT '0' NOT NULL
+);
+
+CREATE INDEX idx_infra_doc_file_01 ON infra_doc_file (owner_user_id);
+CREATE INDEX idx_infra_doc_file_02 ON infra_doc_file (space_type);
+CREATE INDEX idx_infra_doc_file_03 ON infra_doc_file (file_type);
+
+COMMENT ON COLUMN infra_doc_file.id IS '文档编号';
+COMMENT ON COLUMN infra_doc_file.title IS '文档标题';
+COMMENT ON COLUMN infra_doc_file.file_id IS '文件编号';
+COMMENT ON COLUMN infra_doc_file.file_type IS '文件类型(docx/xlsx/pptx/pdf)';
+COMMENT ON COLUMN infra_doc_file.space_type IS '空间类型(1-个人空间 2-团队空间)';
+COMMENT ON COLUMN infra_doc_file.description IS '文档描述';
+COMMENT ON COLUMN infra_doc_file.latest_version_id IS '最新版本编号';
+COMMENT ON COLUMN infra_doc_file.owner_user_id IS '所有者用户编号';
+COMMENT ON COLUMN infra_doc_file.status IS '状态(0-禁用 1-启用)';
+COMMENT ON COLUMN infra_doc_file.creator IS '创建者';
+COMMENT ON COLUMN infra_doc_file.create_time IS '创建时间';
+COMMENT ON COLUMN infra_doc_file.updater IS '更新者';
+COMMENT ON COLUMN infra_doc_file.update_time IS '更新时间';
+COMMENT ON COLUMN infra_doc_file.deleted IS '是否删除';
+COMMENT ON COLUMN infra_doc_file.tenant_id IS '租户编号';
+COMMENT ON TABLE infra_doc_file IS '在线文档表';
+
+-- ----------------------------
+-- Table structure for infra_doc_file_version
+-- ----------------------------
+CREATE TABLE infra_doc_file_version (
+ id bigint NOT NULL PRIMARY KEY,
+ doc_file_id bigint NOT NULL,
+ version_no varchar(50) NOT NULL,
+ file_id bigint NOT NULL,
+ change_description varchar(500) DEFAULT NULL NULL,
+ creator varchar(64) DEFAULT '' NULL,
+ create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updater varchar(64) DEFAULT '' NULL,
+ update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ deleted bit DEFAULT '0' NOT NULL,
+ tenant_id bigint DEFAULT '0' NOT NULL
+);
+
+CREATE INDEX idx_infra_doc_file_version_01 ON infra_doc_file_version (doc_file_id);
+CREATE INDEX idx_infra_doc_file_version_02 ON infra_doc_file_version (version_no);
+
+COMMENT ON COLUMN infra_doc_file_version.id IS '版本编号';
+COMMENT ON COLUMN infra_doc_file_version.doc_file_id IS '文档编号';
+COMMENT ON COLUMN infra_doc_file_version.version_no IS '版本号';
+COMMENT ON COLUMN infra_doc_file_version.file_id IS '文件编号';
+COMMENT ON COLUMN infra_doc_file_version.change_description IS '变更说明';
+COMMENT ON COLUMN infra_doc_file_version.creator IS '创建者';
+COMMENT ON COLUMN infra_doc_file_version.create_time IS '创建时间';
+COMMENT ON COLUMN infra_doc_file_version.updater IS '更新者';
+COMMENT ON COLUMN infra_doc_file_version.update_time IS '更新时间';
+COMMENT ON COLUMN infra_doc_file_version.deleted IS '是否删除';
+COMMENT ON COLUMN infra_doc_file_version.tenant_id IS '租户编号';
+COMMENT ON TABLE infra_doc_file_version IS '文档版本表';
+
+-- ----------------------------
+-- Table structure for infra_doc_file_permission
+-- ----------------------------
+CREATE TABLE infra_doc_file_permission (
+ id bigint NOT NULL PRIMARY KEY,
+ doc_file_id bigint NOT NULL,
+ role_id bigint NOT NULL,
+ permission_type smallint DEFAULT '1' NOT NULL,
+ expire_time datetime DEFAULT NULL NULL,
+ creator varchar(64) DEFAULT '' NULL,
+ create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ updater varchar(64) DEFAULT '' NULL,
+ update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ deleted bit DEFAULT '0' NOT NULL,
+ tenant_id bigint DEFAULT '0' NOT NULL
+);
+
+CREATE INDEX idx_infra_doc_file_permission_01 ON infra_doc_file_permission (role_id);
+
+COMMENT ON COLUMN infra_doc_file_permission.id IS '权限编号';
+COMMENT ON COLUMN infra_doc_file_permission.doc_file_id IS '文档编号';
+COMMENT ON COLUMN infra_doc_file_permission.role_id IS '角色编号';
+COMMENT ON COLUMN infra_doc_file_permission.permission_type IS '权限类型(1-只读 2-编辑 3-管理)';
+COMMENT ON COLUMN infra_doc_file_permission.expire_time IS '过期时间';
+COMMENT ON COLUMN infra_doc_file_permission.creator IS '创建者';
+COMMENT ON COLUMN infra_doc_file_permission.create_time IS '创建时间';
+COMMENT ON COLUMN infra_doc_file_permission.updater IS '更新者';
+COMMENT ON COLUMN infra_doc_file_permission.update_time IS '更新时间';
+COMMENT ON COLUMN infra_doc_file_permission.deleted IS '是否删除';
+COMMENT ON COLUMN infra_doc_file_permission.tenant_id IS '租户编号';
+COMMENT ON TABLE infra_doc_file_permission IS '文档权限表';
+
+-- ----------------------------
+-- Table structure for infra_doc_edit_history
+-- ----------------------------
+CREATE TABLE infra_doc_edit_history (
+ id bigint NOT NULL PRIMARY KEY,
+ doc_file_id bigint NOT NULL,
+ user_id bigint NOT NULL,
+ user_name varchar(100) NOT NULL,
+ edit_type smallint DEFAULT '1' NOT NULL,
+ description varchar(500) DEFAULT NULL NULL,
+ create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ tenant_id bigint DEFAULT '0' NOT NULL
+);
+
+CREATE INDEX idx_infra_doc_edit_history_01 ON infra_doc_edit_history (doc_file_id);
+CREATE INDEX idx_infra_doc_edit_history_02 ON infra_doc_edit_history (user_id);
+
+COMMENT ON COLUMN infra_doc_edit_history.id IS '历史编号';
+COMMENT ON COLUMN infra_doc_edit_history.doc_file_id IS '文档编号';
+COMMENT ON COLUMN infra_doc_edit_history.user_id IS '编辑用户编号';
+COMMENT ON COLUMN infra_doc_edit_history.user_name IS '编辑用户名称';
+COMMENT ON COLUMN infra_doc_edit_history.edit_type IS '编辑类型(1-创建 2-编辑 3-删除 4-重命名)';
+COMMENT ON COLUMN infra_doc_edit_history.description IS '操作描述';
+COMMENT ON COLUMN infra_doc_edit_history.create_time IS '创建时间';
+COMMENT ON COLUMN infra_doc_edit_history.tenant_id IS '租户编号';
+COMMENT ON TABLE infra_doc_edit_history IS '文档编辑历史表';
diff --git a/sql/dm/新增用户、组织机构源表结构并迁移.sql b/sql/dm/新增用户、组织机构源表结构并迁移.sql
new file mode 100644
index 00000000..d3dc16fb
--- /dev/null
+++ b/sql/dm/新增用户、组织机构源表结构并迁移.sql
@@ -0,0 +1,42 @@
+-- ================================================
+-- 用户来源类型功能 - 数据库表结构修改脚本
+-- 创建时间: 2025-09-16
+-- 作者: ZT
+-- 功能描述: 为 system_users 表添加 user_source 字段,用于区分用户来源
+-- ================================================
+
+-- 为 system_users 表添加 user_source 字段
+ALTER TABLE system_users
+ADD user_source TINYINT DEFAULT 1;
+
+-- 添加字段注释
+COMMENT ON COLUMN system_users.user_source IS '用户来源: 1-外部用户, 2-同步用户';
+
+-- 数据迁移:将所有现有用户设置为同步用户(类型为2)
+UPDATE system_users
+SET user_source = 2
+WHERE user_source IS NULL OR user_source = 1;
+
+COMMIT;
+
+
+-- ================================================
+-- 部门来源类型功能 - 数据库表结构修改脚本
+-- 创建时间: 2025-09-16
+-- 作者: ZT
+-- 功能描述: 为 system_dept 表添加 dept_source 字段,用于区分部门来源
+-- ================================================
+
+-- 1. 为 system_dept 表添加 dept_source 字段
+ALTER TABLE system_dept
+ADD dept_source TINYINT DEFAULT 1;
+
+-- 2. 添加字段注释
+COMMENT ON COLUMN system_dept.dept_source IS '部门来源: 1-外部部门, 2-同步部门';
+
+-- 3. 数据迁移:将所有现有部门设置为同步部门(类型为2)
+UPDATE system_dept
+SET dept_source = 2
+WHERE dept_source IS NULL OR dept_source = 1;
+
+COMMIT;
\ No newline at end of file
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java
index bfce9368..e0ceae16 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import java.util.List;
+import java.util.Set;
import java.util.function.Consumer;
/**
@@ -44,6 +45,21 @@ public class BeanUtils {
return list;
}
+ public static Set toBean(Set source, Class targetType) {
+ if (source == null) {
+ return null;
+ }
+ return CollectionUtils.convertSet(source, s -> toBean(s, targetType));
+ }
+
+ public static Set toBean(Set source, Class targetType, Consumer peek) {
+ Set set = toBean(source, targetType);
+ if (set != null) {
+ set.forEach(peek);
+ }
+ return set;
+ }
+
public static PageResult toBean(PageResult source, Class targetType) {
return toBean(source, targetType, null);
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java
index c894bc73..a75cd26c 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/handler/DefaultDBFieldHandler.java
@@ -20,8 +20,6 @@ import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.*;
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.USER_NOT_SET_DEPT;
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
/**
@@ -160,10 +158,11 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
Set postIds = new HashSet<>(JSONUtil.parseArray(
loginUser.getInfo().getOrDefault(LoginUser.INFO_KEY_POST_IDS, "[]")
).toList(Long.class));
+ // 阻碍部分场景的使用,不强制校验
// 如果 visitCompanyId 不存在,不能进行业务办理
- if (Objects.isNull(visitCompanyId) || Objects.isNull(visitDeptId)) {
- throw exception(USER_NOT_SET_DEPT);
- }
+// if (Objects.isNull(visitCompanyId) || Objects.isNull(visitDeptId)) {
+// throw exception(USER_NOT_SET_DEPT);
+// }
businessBaseDO.setCompanyId(visitCompanyId);
businessBaseDO.setCompanyName(loginUser.getVisitCompanyName());
businessBaseDO.setDeptId(visitDeptId);
diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEventListener.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEventListener.java
index 199f47fd..4bd73b82 100644
--- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEventListener.java
+++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEventListener.java
@@ -1,8 +1,9 @@
package cn.iocoder.yudao.module.bpm.api.event;
-import cn.hutool.core.util.StrUtil;
import org.springframework.context.ApplicationListener;
+import java.util.List;
+
/**
* {@link BpmProcessInstanceStatusEvent} 的监听器
*
@@ -13,15 +14,15 @@ public abstract class BpmProcessInstanceStatusEventListener
@Override
public final void onApplicationEvent(BpmProcessInstanceStatusEvent event) {
- if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey())) {
- return;
+ if (getProcessDefinitionKey().contains(event.getProcessDefinitionKey())){
+ onEvent(event);
}
}
/**
* @return 返回监听的流程定义 Key
*/
- protected abstract String getProcessDefinitionKey();
+ protected abstract List getProcessDefinitionKey();
/**
* 处理事件
diff --git a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java
index 42ac23ee..e73ba3be 100644
--- a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java
+++ b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveStatusListener.java
@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
+import java.util.List;
+
/**
* OA 请假单的结果的监听器实现类
*
@@ -19,8 +21,8 @@ public class BpmOALeaveStatusListener extends BpmProcessInstanceStatusEventListe
private BpmOALeaveService leaveService;
@Override
- protected String getProcessDefinitionKey() {
- return BpmOALeaveServiceImpl.PROCESS_KEY;
+ protected List getProcessDefinitionKey() {
+ return List.of(BpmOALeaveServiceImpl.PROCESS_KEY);
}
@Override
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
index 2e3671ec..8ec28735 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
@@ -34,9 +34,9 @@ public interface DeptApi {
@Operation(summary = "删除部门")
CommonResult deleteDept(@RequestParam("id") Long id);
- @GetMapping(PREFIX + "/list-all")
+ @PostMapping(PREFIX + "/list-all")
@Operation(summary = "获得部门列表")
- CommonResult> getDeptList(@RequestParam DeptListReqDTO reqVO);
+ CommonResult> getDeptList(@RequestBody DeptListReqDTO reqVO);
@GetMapping(PREFIX + "/simple-list")
@Operation(summary = "获得部门精简信息列表")
@@ -77,4 +77,9 @@ public interface DeptApi {
@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);
+
}
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/CompanyDeptInfoRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/CompanyDeptInfoRespDTO.java
new file mode 100644
index 00000000..196cd9fe
--- /dev/null
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/CompanyDeptInfoRespDTO.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.system.api.dept.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 公司部门信息 Response DTO
+ *
+ * @author ZT
+ */
+@Schema(description = "RPC 服务 - 公司部门信息 Response DTO")
+@Data
+public class CompanyDeptInfoRespDTO {
+
+ @Schema(description = "公司编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long companyId;
+
+ @Schema(description = "公司名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
+ private String companyName;
+
+ @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long deptId;
+
+ @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部")
+ private String deptName;
+
+}
\ No newline at end of file
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java
index 0d7888e9..b4d90e30 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java
@@ -9,8 +9,8 @@ import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.cloud.openfeign.SpringQueryMap;
-import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
@Tag(name = "RPC 服务 - 操作日志")
@@ -18,8 +18,8 @@ public interface OperateLogApi extends OperateLogCommonApi {
String PREFIX = ApiConstants.PREFIX + "/operate-log";
- @GetMapping(PREFIX + "/page")
+ @PostMapping(PREFIX + "/page")
@Operation(summary = "获取指定模块的指定数据的操作日志分页")
- CommonResult> getOperateLogPage(@SpringQueryMap OperateLogPageReqDTO pageReqDTO);
+ CommonResult> getOperateLogPage(@RequestBody OperateLogPageReqDTO pageReqDTO);
}
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApi.java
index dec970bd..e0e1d2fb 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/sms/SmsCodeApi.java
@@ -1,20 +1,18 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
+import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
-import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
-import jakarta.validation.Valid;
-
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
@Tag(name = "RPC 服务 - 短信验证码")
public interface SmsCodeApi {
@@ -29,7 +27,7 @@ public interface SmsCodeApi {
@Operation(summary = "验证短信验证码,并进行使用")
CommonResult useSmsCode(@Valid @RequestBody SmsCodeUseReqDTO reqDTO);
- @GetMapping(PREFIX + "/validate")
+ @PostMapping(PREFIX + "/validate")
@Operation(summary = "检查验证码是否有效")
CommonResult validateSmsCode(@Valid @RequestBody SmsCodeValidateReqDTO reqDTO);
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
index 5eeadadb..bc099115 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java
@@ -9,7 +9,6 @@ import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -52,9 +51,9 @@ public interface SocialClientApi {
CommonResult getWxMaPhoneNumberInfo(@RequestParam("userType") Integer userType,
@RequestParam("phoneCode") String phoneCode);
- @GetMapping(PREFIX + "/get-wxa-qrcode")
+ @PostMapping(PREFIX + "/get-wxa-qrcode")
@Operation(summary = "获得小程序二维码")
- CommonResult getWxaQrcode(@SpringQueryMap SocialWxQrcodeReqDTO reqVO);
+ CommonResult getWxaQrcode(@RequestBody SocialWxQrcodeReqDTO reqVO);
@GetMapping(PREFIX + "/get-wxa-subscribe-template-list")
@Operation(summary = "获得微信小程订阅模板")
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
index 29e136c3..0ade83b1 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
@@ -2,18 +2,20 @@ package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.CompanyDeptInfo;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.*;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
+import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
-import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -88,4 +90,10 @@ public class DeptApiImpl implements DeptApi {
return success(BeanUtils.toBean(depts, DeptRespDTO.class));
}
+ @Override
+ public CommonResult> getCompanyDeptInfoListByUserId(Long userId) {
+ Set companyDeptInfos = deptService.getCompanyDeptInfoListByUserId(userId);
+ return success(BeanUtils.toBean(companyDeptInfos, CompanyDeptInfoRespDTO.class));
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java
index 58bca55a..7d764c0e 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java
@@ -84,6 +84,23 @@ public class DeptController {
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
}
+ @GetMapping("/top-level-list")
+ @Operation(summary = "获取顶级部门列表", description = "用于懒加载,只返回没有父部门的顶级部门")
+ @PreAuthorize("@ss.hasPermission('system:dept:query')")
+ public CommonResult> getTopLevelDeptList() {
+ List list = deptService.getTopLevelDeptList();
+ return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
+ }
+
+ @GetMapping("/children")
+ @Operation(summary = "根据父部门ID获取子部门列表", description = "用于懒加载,根据父部门ID返回直接子部门")
+ @Parameter(name = "parentId", description = "父部门ID", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('system:dept:query')")
+ public CommonResult> getChildrenDeptList(@RequestParam("parentId") Long parentId) {
+ List list = deptService.getDirectChildDeptList(parentId);
+ return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
+ }
+
@GetMapping("/get")
@Operation(summary = "获得部门信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sync/SyncLogController.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sync/SyncLogController.java
index 2a21be8a..2bf7c52e 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sync/SyncLogController.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sync/SyncLogController.java
@@ -49,4 +49,13 @@ public class SyncLogController {
return success(BeanUtils.toBean(pageResult, SyncLogRespVO.class));
}
+ @PostMapping("/rerun")
+ @Operation(summary = "重新执行异常的同步接口")
+ @Parameter(name = "id", description = "日志编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('system:sync-log:rerun')")
+ public CommonResult rerunSyncLog(@RequestParam("id") Long id) {
+ boolean success = syncLogService.rerunSyncLog(id);
+ return success(success);
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java
index 8b9d1135..b30459f3 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java
@@ -58,6 +58,34 @@ public interface DeptMapper extends BaseMapperX {
UpdateWrapper wrapper = new UpdateWrapper<>();
wrapper.in("id", ids).set("tenant_id", tenantId);
update(null, wrapper);
- };
+ }
+
+ /**
+ * 根据父部门ID和状态查询部门列表
+ *
+ * @param parentId 父部门ID
+ * @param status 状态
+ * @return 部门列表
+ */
+ default List selectList(Long parentId, Integer status) {
+ return selectList(new LambdaQueryWrapperX()
+ .eqIfPresent(DeptDO::getParentId, parentId)
+ .eqIfPresent(DeptDO::getStatus, status)
+ );
+ }
+
+ /**
+ * 根据父部门ID和状态查询子部门列表
+ *
+ * @param parentId 父部门ID
+ * @param status 状态
+ * @return 子部门列表
+ */
+ default List selectListByParentId(Long parentId, Integer status) {
+ return selectList(new LambdaQueryWrapperX()
+ .eq(DeptDO::getParentId, parentId)
+ .eqIfPresent(DeptDO::getStatus, status)
+ );
+ }
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java
index fdac4c2a..0641c18b 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java
@@ -118,4 +118,21 @@ public interface DeptService {
List getUserCompanyList();
Set getCompanyDeptInfoListByUserId(Long userId);
+
+ /**
+ * 获取顶级部门列表
+ * 用于懒加载,只返回没有父部门的顶级部门
+ *
+ * @return 顶级部门列表
+ */
+ List getTopLevelDeptList();
+
+ /**
+ * 根据父部门ID获取直接子部门列表
+ * 用于懒加载,只返回指定父部门的直接子部门
+ *
+ * @param parentId 父部门ID
+ * @return 直接子部门列表
+ */
+ List getDirectChildDeptList(Long parentId);
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
index 3b6c9164..78f31449 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
@@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.userdept.UserDeptDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
import cn.iocoder.yudao.module.system.dal.mysql.userdept.UserDeptMapper;
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
+import cn.iocoder.yudao.module.system.enums.dept.DeptSourceEnum;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -30,8 +31,6 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
-import cn.iocoder.yudao.module.system.enums.dept.DeptSourceEnum;
-
/**
* 部门 Service 实现类
*
@@ -311,4 +310,19 @@ public class DeptServiceImpl implements DeptService {
return result;
}
+ @Override
+ public List getTopLevelDeptList() {
+ // 获取顶级部门:没有父部门的部门(parentId为null或0)
+ return deptMapper.selectList(DeptDO.PARENT_ID_ROOT, CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public List getDirectChildDeptList(Long parentId) {
+ if (parentId == null) {
+ return Collections.emptyList();
+ }
+ // 根据父部门ID获取直接子部门,只返回启用状态的部门
+ return deptMapper.selectListByParentId(parentId, CommonStatusEnum.ENABLE.getStatus());
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogService.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogService.java
index a0c882c1..900c076e 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogService.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogService.java
@@ -99,4 +99,12 @@ public interface SyncLogService {
String exceptionStack, String responseData, String encryptedResponse,
String businessResult);
+ /**
+ * 重新执行异常的同步接口
+ *
+ * @param logId 日志ID
+ * @return 重跑是否成功
+ */
+ boolean rerunSyncLog(Long logId);
+
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogServiceImpl.java
index 3ac16602..8f1fd4d1 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/SyncLogServiceImpl.java
@@ -2,19 +2,33 @@ package cn.iocoder.yudao.module.system.service.sync;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.sync.vo.SyncLogPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.sync.vo.org.OrgCreateRequestVO;
+import cn.iocoder.yudao.module.system.controller.admin.sync.vo.org.OrgDeleteRequestVO;
+import cn.iocoder.yudao.module.system.controller.admin.sync.vo.org.OrgUpdateRequestVO;
+import cn.iocoder.yudao.module.system.controller.admin.sync.vo.user.UserCreateRequestVO;
+import cn.iocoder.yudao.module.system.controller.admin.sync.vo.user.UserDeleteRequestVO;
+import cn.iocoder.yudao.module.system.controller.admin.sync.vo.user.UserUpdateRequestVO;
import cn.iocoder.yudao.module.system.dal.dataobject.sync.SyncLogDO;
import cn.iocoder.yudao.module.system.dal.mysql.sync.SyncLogMapper;
import cn.iocoder.yudao.module.system.enums.sync.SyncLogStatusEnum;
+import com.alibaba.fastjson.JSON;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.time.LocalDateTime;
/**
* 同步接口日志 Service 实现类
*
+ * 注意:系统现已调整为允许用户名重复,相关影响如下:
+ * 1. 移除了用户创建和更新时的用户名唯一性校验
+ * 2. 用户删除操作改为通过用户ID进行,而非用户名
+ * 3. 登录认证仍使用用户名,但可能需要额外的区分机制(如租户ID)
+ *
* @author ZT
*/
@Service
@@ -24,6 +38,10 @@ public class SyncLogServiceImpl implements SyncLogService {
@Resource
private SyncLogMapper syncLogMapper;
+ @Resource
+ private OrgSyncService orgSyncService;
+ @Resource
+ private UserSyncService userSyncService;
@Override
public Long createSyncLog(SyncLogDO syncLog) {
@@ -145,4 +163,145 @@ public class SyncLogServiceImpl implements SyncLogService {
updateSyncLog(syncLog);
}
+ @Override
+ public boolean rerunSyncLog(Long logId) {
+ // 获取原始日志
+ SyncLogDO originalLog = getSyncLog(logId);
+ if (originalLog == null) {
+ log.warn("同步日志不存在,无法重跑,logId: {}", logId);
+ return false;
+ }
+
+ // 检查是否是失败的日志
+ if (SyncLogStatusEnum.SUCCESS.getStatus().equals(originalLog.getStatus())) {
+ log.warn("同步日志状态为成功,无需重跑,logId: {}", logId);
+ return false;
+ }
+
+ // 检查是否有解密后的请求数据
+ if (originalLog.getDecryptedRequest() == null || originalLog.getDecryptedRequest().trim().isEmpty()) {
+ log.warn("同步日志缺少解密后的请求数据,无法重跑,logId: {}", logId);
+ return false;
+ }
+
+ try {
+ // 重置相关状态,准备重新执行
+ SyncLogDO updateLog = new SyncLogDO();
+ updateLog.setId(logId);
+ updateLog.setResponseTime(LocalDateTime.now());
+ updateLog.setErrorCode(null);
+ updateLog.setErrorMessage(null);
+ updateLog.setExceptionStack(null);
+ updateLog.setResponseData(null);
+ updateLog.setEncryptedResponse(null);
+ updateLog.setBusinessResult(null);
+
+ // 根据服务名称重新执行业务逻辑
+ boolean success = rerunBusinessLogic(originalLog.getServiceName(),
+ originalLog.getDecryptedRequest(), logId);
+
+ if (success) {
+ log.info("同步接口重跑成功,logId: {}", logId);
+ } else {
+ log.error("同步接口重跑失败,logId: {}", logId);
+ }
+
+ return success;
+ } catch (Exception e) {
+ log.error("重跑同步接口异常,logId: {}", logId, e);
+ // 记录重跑异常
+ logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
+ "RERUN_ERROR", "重跑过程中发生异常: " + e.getMessage(), getStackTrace(e), null, null, "500");
+ return false;
+ }
+ }
+
+ /**
+ * 根据服务名称重新执行业务逻辑
+ */
+ private boolean rerunBusinessLogic(String serviceName, String decryptedRequest, Long logId) {
+ try {
+ switch (serviceName) {
+ // 只支持写操作(创建、更新、删除)的重跑,查询操作通常是幂等的不需要重跑
+ case "OrgCreateService":
+ OrgCreateRequestVO orgCreateReq = JSON.parseObject(decryptedRequest, OrgCreateRequestVO.class);
+ var orgCreateResp = orgSyncService.createOrg(orgCreateReq);
+ logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
+ null, null, null, JSON.toJSONString(orgCreateResp), null, orgCreateResp.getResultCode());
+ return true;
+
+ case "OrgDeleteService":
+ OrgDeleteRequestVO orgDeleteReq = JSON.parseObject(decryptedRequest, OrgDeleteRequestVO.class);
+ var orgDeleteResp = orgSyncService.deleteOrg(orgDeleteReq);
+ logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
+ null, null, null, JSON.toJSONString(orgDeleteResp), null, orgDeleteResp.getResultCode());
+ return true;
+
+ case "OrgUpdateService":
+ OrgUpdateRequestVO orgUpdateReq = JSON.parseObject(decryptedRequest, OrgUpdateRequestVO.class);
+ var orgUpdateResp = orgSyncService.updateOrg(orgUpdateReq);
+ logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
+ null, null, null, JSON.toJSONString(orgUpdateResp), null, orgUpdateResp.getResultCode());
+ return true;
+
+ case "UserCreateService":
+ UserCreateRequestVO userCreateReq = JSON.parseObject(decryptedRequest, UserCreateRequestVO.class);
+ var userCreateResp = userSyncService.createUser(userCreateReq);
+ logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
+ null, null, null, JSON.toJSONString(userCreateResp), null, userCreateResp.getResultCode());
+ return true;
+
+ case "UserDeleteService":
+ UserDeleteRequestVO userDeleteReq = JSON.parseObject(decryptedRequest, UserDeleteRequestVO.class);
+ var userDeleteResp = userSyncService.deleteUser(userDeleteReq);
+ logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
+ null, null, null, JSON.toJSONString(userDeleteResp), null, userDeleteResp.getResultCode());
+ return true;
+
+ case "UserUpdateService":
+ UserUpdateRequestVO userUpdateReq = JSON.parseObject(decryptedRequest, UserUpdateRequestVO.class);
+ var userUpdateResp = userSyncService.updateUser(userUpdateReq);
+ logRequestComplete(logId, SyncLogStatusEnum.SUCCESS.getStatus(),
+ null, null, null, JSON.toJSONString(userUpdateResp), null, userUpdateResp.getResultCode());
+ return true;
+
+ // 查询类服务不支持重跑,因为它们通常是幂等的且没有副作用
+ case "SchemaService":
+ case "QueryOrgByIdService":
+ case "QueryAllOrgIdsService":
+ case "QueryUserByIdService":
+ case "QueryAllUserIdsService":
+ log.warn("查询类服务不支持重跑: {}", serviceName);
+ logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
+ "QUERY_SERVICE_NOT_RERUNABLE", "查询类服务不支持重跑", null, null, null, "400");
+ return false;
+
+ default:
+ log.warn("不支持的服务类型重跑: {}", serviceName);
+ logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
+ "UNSUPPORTED_SERVICE", "不支持的服务类型重跑", null, null, null, "500");
+ return false;
+ }
+ } catch (Exception e) {
+ log.error("重跑业务逻辑异常,serviceName: {}", serviceName, e);
+ logRequestComplete(logId, SyncLogStatusEnum.SYSTEM_ERROR.getStatus(),
+ "RERUN_ERROR", e.getMessage(), getStackTrace(e), null, null, "500");
+ return false;
+ }
+ }
+
+ /**
+ * 获取异常堆栈信息
+ */
+ private String getStackTrace(Exception e) {
+ try {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ return sw.toString();
+ } catch (Exception ex) {
+ return e.getMessage();
+ }
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/UserSyncServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/UserSyncServiceImpl.java
index d0925d30..fa69be23 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/UserSyncServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/sync/UserSyncServiceImpl.java
@@ -10,11 +10,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.userdept.UserDeptDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
+import cn.iocoder.yudao.module.system.enums.user.UserSourceEnum;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.service.userdept.UserDeptService;
import cn.iocoder.yudao.module.system.util.sync.SyncVerifyUtil;
-import cn.iocoder.yudao.module.system.enums.user.UserSourceEnum;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -24,6 +24,15 @@ import java.util.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
+/**
+ * 用户同步服务实现类
+ *
+ * 注意:系统现已调整为允许用户名重复,相关调整:
+ * 1. deleteUser 方法改为通过用户ID直接查找和删除用户,而非通过用户名
+ * 2. 用户创建时不再校验用户名唯一性
+ *
+ * @author ZT
+ */
@Service
public class UserSyncServiceImpl implements UserSyncService {
@Resource
@@ -60,7 +69,8 @@ public class UserSyncServiceImpl implements UserSyncService {
@Override
public UserDeleteResponseVO deleteUser(UserDeleteRequestVO requestVO) {
- AdminUserDO user = adminUserService.getUserByUsername(requestVO.getBimRemoteUser());
+ // 由于用户名可能重复,直接通过 ID 查找和删除用户
+ AdminUserDO user = adminUserService.getUser(requestVO.getBimUid());
UserDeleteResponseVO resp = new UserDeleteResponseVO();
resp.setBimRequestId(requestVO.getBimRequestId());
if (user != null) {
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
index 467a3166..86b9ad04 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
@@ -23,12 +23,12 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.userdept.UserDeptDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
+import cn.iocoder.yudao.module.system.enums.user.UserSourceEnum;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import cn.iocoder.yudao.module.system.service.userdept.UserDeptService;
-import cn.iocoder.yudao.module.system.enums.user.UserSourceEnum;
import com.google.common.annotations.VisibleForTesting;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
@@ -52,6 +52,12 @@ import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;
/**
* 后台用户 Service 实现类
+ *
+ * 注意:系统现已调整为允许用户名重复,已移除用户名唯一性校验。
+ * 这意味着:
+ * 1. 用户创建和更新时不再检查用户名是否重复
+ * 2. 通过用户名查询可能返回多个用户中的第一个
+ * 3. 建议在需要精确查找时使用用户ID或其他唯一标识
*
* @author ZT
*/
@@ -416,8 +422,8 @@ public class AdminUserServiceImpl implements AdminUserService {
return DataPermissionUtils.executeIgnore(() -> {
// 校验用户存在
AdminUserDO user = validateUserExists(id);
- // 校验用户名唯一
- validateUsernameUnique(id, username);
+ // 校验用户名唯一 - 注释掉,允许用户名重复
+ // validateUsernameUnique(id, username);
// 校验手机号唯一
validateMobileUnique(id, mobile);
// 校验邮箱唯一