接口调整

This commit is contained in:
2026-03-26 16:14:46 +08:00
parent ddd5c5a493
commit 875e2598e5
2 changed files with 3 additions and 556 deletions

View File

@@ -1,5 +1,7 @@
package com.njcn.rdms.module.system.dal.dataobject.user; package com.njcn.rdms.module.system.dal.dataobject.user;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum; import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
@@ -68,6 +70,7 @@ public class AdminUserDO extends BaseDO {
/** /**
* 离职时间 * 离职时间
*/ */
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private LocalDateTime resignedAt; private LocalDateTime resignedAt;
/** /**

View File

@@ -1,556 +0,0 @@
# 表结构调整建议
## 1. 先说结论
这个项目按“新项目、严格对齐设计文档”落地,不考虑历史兼容、降级或兜底。要满足《权限设计方案》,至少要做这 4 类调整:
1. `system_dept` 从“普通部门表”升级成“可表达多层组织树的组织节点表”。
2. 把“组织负责人”“直接管理关系”“特殊可见范围”从主表字段里拆出去,改成独立关系表。
3.`system_users` 的“多岗位逗号字段”改成“主岗位单字段”,否则和设计文档的“一人一岗”冲突。
4. `system_role` 只保留 RBAC 角色能力,不引入设计文档中没有的 `data_scope` 一类字段,避免混淆数据范围模型。
其中 `system_dept.leader_user_id` 的最终处理原则是:
- 不保留在最终模型中
- 直接从 `system_dept` 删除
- 组织负责人统一改由 `system_org_leader_relation` 维护
- 后续所有权限判断都不再读取 `leader_user_id`
---
## 2. 现有表和设计文档的主要冲突
### 2.1 `system_dept` 的问题
现状:[`system_dept.sql`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/system_dept.sql) 第 24 行开始的 `system_dept` 只有 `parent_id`,没有物化路径、组织类型;并且用 `leader_user_id` 单字段存负责人。
对应设计文档:
- 组织树需要 `path` 物化路径,见 [`权限设计方案.md`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/权限设计方案.md#L93)
- 负责人要独立成 `system_org_leader_relation`,支持一人负责多个节点、一个节点多个负责人、且支持生效失效时间,见 [`权限设计方案.md`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/权限设计方案.md#L104) 和 [`权限设计方案.md`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/权限设计方案.md#L218)
结论:
- `leader_user_id` 不应出现在最终模型中,需要从 `system_dept` 直接删除,组织负责人统一改由 `system_org_leader_relation` 维护。
- 后续所有权限判断都不再读取 `leader_user_id`
- `system_dept` 至少要补 `path``org_type``code`
- `org_type` 是“组织节点类型”,不是“研发专属方向类型”。
### 2.2 `system_users` 的问题
现状:[`system_dept.sql`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/system_dept.sql#L161) 的 `system_users` 里有:
- `dept_id`
- `post_ids`
同时还有 [`system_user_post`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/system_dept.sql#L129) 关联表。
对应设计文档:
- 用户主组织归属只有一个:`department_id`
- 岗位是单值:`users.position_id`
- 岗位不等于负责人身份,见 [`权限设计方案.md`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/权限设计方案.md#L118) 和 [`权限设计方案.md`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/权限设计方案.md#L188)
结论:
- `dept_id` 可以保留,但语义要改成“主组织归属”。
- `post_ids``system_user_post` 与当前设计冲突,最终模型中应删除。
- 用户岗位的唯一事实来源改成 `position_id`
### 2.3 `system_role` 的问题
现状:[`system_role`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/system_dept.sql#L91) 是通用 RBAC 角色表。
对应设计文档:
- RBAC 角色只决定“能不能进模块”
- 数据范围由“自己参与项目 + 组织负责人关系 + 特殊可见性配置”决定
- 角色与数据范围无直接绑定,见 [`权限设计方案.md`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/权限设计方案.md#L301) 和 [`权限设计方案.md`](/C:/code/gitee/rdms-requirements-compilation/04-设计阶段/权限设计/权限设计方案.md#L1132)
结论:
- `system_role` 在本项目中只承担 RBAC 角色定义。
- 设计文档中没有的 `data_scope``data_scope_dept_ids` 不进入最终模型。
- 数据范围全部由 `system_project_member``system_org_leader_relation``system_user_visibility_config` 体系计算。
### 2.4 缺失的核心表
设计文档明确依赖但当前 SQL 中没有、且最终落库应统一使用 `system_` 前缀的表:
- `system_org_leader_relation`
- `system_user_management_relation`
- `system_user_visibility_config`
- `system_project_member`
这 4 张表是本方案真正的核心。
---
## 3. 推荐的目标模型
最终落库表名统一使用 `system_*` 前缀;设计文档中的无前缀名称仅作为业务别名理解,不作为最终建表名称。
### 3.1 保留并改造
- `system_dept`
- `system_users`
- `system_post`
- `system_role`
- `system_user_role`
- `system_menu`
- `system_role_menu`
### 3.2 新增
- `system_org_leader_relation`
- `system_user_management_relation`
- `system_user_visibility_config`
- `system_project_member`
---
## 4. 建议如何改表
## 4.1 `system_dept`
### 建议保留字段
- `id`
- `name`
- `parent_id`
- `sort`
- `status`
- 审计字段
### 建议新增字段
```sql
ALTER TABLE system_dept
ADD COLUMN org_type VARCHAR(20) NOT NULL DEFAULT 'dept' COMMENT '组织节点类型: company/dept/direction/team',
ADD COLUMN path VARCHAR(1024) CHARACTER SET ascii NOT NULL DEFAULT '/' COMMENT '物化路径,如 /1/3/6/适配雪花ID场景',
ADD COLUMN level INT NOT NULL DEFAULT 1 COMMENT '层级从1开始',
ADD COLUMN code VARCHAR(64) NULL COMMENT '组织编码,可选,用于标识具体方向或组织节点',
ADD KEY idx_parent_id (parent_id),
ADD KEY idx_org_type (org_type),
ADD KEY idx_path (path(191)),
ADD UNIQUE KEY uk_dept_code (code);
```
### 字段口径
- `org_type` 必填,默认值建议为 `dept`
- `code` 非必填
- `code` 如果填写,必须唯一
### `org_type` 如何理解
`org_type` 表示“组织树中的节点层级”,不是“研发部专属分类”。
推荐枚举:
- `company`:公司
- `dept`:部门,例如研发部、工程部、财务部
- `direction`:部门下的业务/专业方向,例如系统方向、嵌入式方向、电气方向、结构方向
- `team`:更细的小组,例如前端组、后端组、技术支持组
这意味着:
- 研发部下面可以有 `direction`
- 工程部下面也可以有 `direction`
- 财务部如果没有方向层,直接挂在 `dept` 即可
### 如何区分“系统方向 / 嵌入式方向 / 电力电子方向”
区分方式不是只靠 `org_type`,而是三者一起看:
- `org_type`:说明它是一个方向节点
- `name`:说明它叫“系统方向”还是“嵌入式方向”
- `code`:提供更稳定的程序识别标识
例如:
```text
研发部 org_type=dept code=NULL
系统方向 org_type=direction code=RD_SYS
嵌入式方向 org_type=direction code=RD_EMBEDDED
电力电子方向 org_type=direction code=RD_POWER_ELEC
工程部 org_type=dept code=NULL
电气方向 org_type=direction code=ENG_ELEC
```
结论:
- `org_type` 负责表达层级
- `code` 负责表达“具体是谁”
- 对没有稳定编码需求的普通部门,`code` 可以为空
### `path` 为什么仍然建议使用 ID
- 即使当前主键使用雪花 ID组织树层级通常也不会太深`VARCHAR(1024)` 足够承载
- `path` 使用主键 ID 最稳定,不受名称修改、编码调整影响
- `path` 只包含数字和 `/`,建议使用 `ascii` 字符集即可
### 建议删除字段
- `leader_user_id`
原因:
- 一个节点可能有多个负责人。
- 负责人需要带时效。
- 负责人关系不应写死在组织节点表中。
最终要求:
- `system_dept` 不再保存负责人字段。
- 负责人全部通过 `system_org_leader_relation` 表达。
---
## 4.2 `system_users`
### 建议保留字段
- `id`
- `username`
- `password`
- `nickname`
- `dept_id`
- `email`
- `mobile`
- `status`
- 审计字段
### 建议新增字段
```sql
ALTER TABLE system_users
ADD COLUMN position_id BIGINT NULL COMMENT '主岗位ID',
ADD COLUMN resigned_at DATETIME NULL COMMENT '离职时间',
ADD KEY idx_user_dept (dept_id),
ADD KEY idx_user_position (position_id);
```
### 建议调整语义
- `dept_id`从“部门ID”调整为“主组织归属ID”
- `status`:继续表示账号可用性
- `resigned_at`:表示内部员工离职时间
这样可以区分:
- 账号被禁用
- 人员已离职(通过 `resigned_at` 标识)
### 用户状态判断建议
- `status`:手工控制是否停用
- `resigned_at`:只表示“是否离职”
建议判定口径:
```text
账号可用 =
status = 正常
且 (resigned_at 为空 或 resigned_at > 当前时间)
```
离职状态判断建议:
- 如果 `resigned_at` 为空:未离职
- 如果 `resigned_at` 大于当前时间:未离职,但表示未来计划离职
- 如果 `resigned_at` 小于等于当前时间:已离职
说明:
- 可以通过定时任务在 `resigned_at <= 当前时间` 时自动把 `status` 更新为停用
- `resigned_at` 不再承担临时账号到期语义
### 建议删除字段
- `post_ids`
原因:
- 设计文档明确是一人一岗。
- 逗号字段无法做约束,也不利于查询和迁移。
### `system_user_post` 怎么处理
按设计文档,直接删除,不进入最终模型。
原因:
- 设计文档定义的是“一人一岗”。
- 岗位是正式职位,不是可叠加的临时职责。
- 组织负责人、项目负责人、产品经理等身份,分别由:
- `system_org_leader_relation`
- `system_project_member.project_role`
来表达,不应复用岗位表。
---
## 4.3 `system_post`
当前 `system_post` 可以保留,但建议补齐岗位属性,便于表达文档里的“岗位体系”和职级。
```sql
ALTER TABLE system_post
ADD COLUMN post_type VARCHAR(20) NULL COMMENT '岗位类型: management/technical',
ADD COLUMN level_rank INT NULL COMMENT '职级,如 4/5/6/7/8/9/10';
```
说明:
- 岗位仍然只表达正式职位。
- 不表达“某方向 Leader”这类组织负责关系。
---
## 4.4 `system_role`
`system_role` 继续保留给 RBAC 使用,但职责要收敛:
- `system_role` 负责菜单、接口、模块访问权限
- 不再负责 RDMS 项目数据范围计算
最终要求:
- `system_role` 只保留 RBAC 必需字段
- `data_scope` 直接删除
- `data_scope_dept_ids` 直接删除
- 字段裁剪如有需要,后续根据部门或角色做展示层/查询层控制,不混入 RBAC 主模型
---
## 5. 建议新增的关系表
## 5.1 `system_org_leader_relation`
用于替代 `system_dept.leader_user_id`
```sql
CREATE TABLE system_org_leader_relation (
id BIGINT NOT NULL COMMENT '主键',
dept_id BIGINT NOT NULL COMMENT '组织节点ID',
user_id BIGINT NOT NULL COMMENT '负责人用户ID',
effective_from DATETIME NULL COMMENT '生效时间',
effective_until DATETIME NULL COMMENT '失效时间',
remark VARCHAR(500) NULL COMMENT '备注',
creator VARCHAR(64) NULL DEFAULT '' COMMENT '创建者',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updater VARCHAR(64) NULL DEFAULT '' COMMENT '更新者',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (id),
KEY idx_org_leader_user (user_id, deleted, effective_from, effective_until),
KEY idx_org_leader_dept (dept_id, deleted, effective_from, effective_until),
UNIQUE KEY uk_org_leader_once (dept_id, user_id, effective_from)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='组织负责人关系表';
```
说明:
- 支持一个人负责多个组织节点。
- 支持一个组织节点多个负责人。
- 权限计算时只取当前有效记录。
---
## 5.2 `system_user_management_relation`
用于“直接管理谁”,只支撑“看人”视图,不支撑项目可见范围反推。
```sql
CREATE TABLE system_user_management_relation (
id BIGINT NOT NULL COMMENT '主键',
manager_user_id BIGINT NOT NULL COMMENT '直接管理者',
subordinate_user_id BIGINT NOT NULL COMMENT '被管理者',
effective_from DATETIME NULL COMMENT '生效时间',
effective_until DATETIME NULL COMMENT '失效时间',
remark VARCHAR(500) NULL COMMENT '备注',
creator VARCHAR(64) NULL DEFAULT '' COMMENT '创建者',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updater VARCHAR(64) NULL DEFAULT '' COMMENT '更新者',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (id),
KEY idx_mgr_user (manager_user_id, deleted, effective_from, effective_until),
KEY idx_sub_user (subordinate_user_id, deleted, effective_from, effective_until),
UNIQUE KEY uk_mgr_sub_once (manager_user_id, subordinate_user_id, effective_from)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户直接管理关系表';
```
---
## 5.3 `system_user_visibility_config`
这里应严格对齐设计文档,不再拆成主表+明细表,直接使用单表配置模型。
```sql
CREATE TABLE system_user_visibility_config (
id BIGINT NOT NULL COMMENT '主键',
user_id BIGINT NOT NULL COMMENT '用户ID',
visibility_type VARCHAR(20) NOT NULL COMMENT 'all/directions/projects',
visible_direction_ids JSON NULL COMMENT '补充可见方向ID列表',
visible_project_ids JSON NULL COMMENT '补充可见项目ID列表',
remark VARCHAR(500) NULL COMMENT '配置原因说明',
creator VARCHAR(64) NULL DEFAULT '' COMMENT '创建者',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updater VARCHAR(64) NULL DEFAULT '' COMMENT '更新者',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (id),
UNIQUE KEY uk_visibility_user (user_id),
KEY idx_visibility_type (visibility_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户补充可见范围配置表';
```
### 字段口径
- `visibility_type = 'all'`
- 表示补充全部项目可见范围
- `visible_direction_ids``visible_project_ids` 应为空
- `visibility_type = 'directions'`
- 表示补充指定方向可见范围
- `visible_direction_ids` 必填
- `visible_project_ids` 应为空
- `visibility_type = 'projects'`
- 表示补充指定项目可见范围
- `visible_project_ids` 必填
- `visible_direction_ids` 应为空
### 约束原则
- 一人一条配置记录
- 只做补充,不做减权
- 不用这张表表达组织负责人关系
- 不用这张表表达项目内操作权限
- 已经通过 `system_project_member``system_org_leader_relation` 默认可见的项目,不再重复写入 `visible_project_ids`
- `visibility_type = 'projects'` 只用于补充“默认权限链路拿不到,但业务上需要额外查看”的项目
### JSON 规模判断
- `visibility_type = 'all'` 时不使用 JSON 列表
- `visibility_type = 'directions'` 时,方向数量通常很少
- `visibility_type = 'projects'` 时,只记录补充项目,不记录项目成员或组织负责人本来就可见的项目
因此在当前设计下,`visible_direction_ids``visible_project_ids` 的规模通常都会比较小,当前阶段没有必要为了低概率的大规模列表场景提前拆表。
---
## 5.4 `system_project_member`
这张表是项目权限的事实来源,必须单独建。
```sql
CREATE TABLE system_project_member (
id BIGINT NOT NULL COMMENT '主键',
project_id BIGINT NOT NULL COMMENT '项目ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
project_role VARCHAR(20) NOT NULL COMMENT 'pm/product/developer/tester/viewer',
member_type VARCHAR(20) NOT NULL DEFAULT 'core' COMMENT 'core/support',
joined_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间',
left_at DATETIME NULL COMMENT '离开时间NULL表示当前成员',
remark VARCHAR(500) NULL COMMENT '备注',
creator VARCHAR(64) NULL DEFAULT '' COMMENT '创建者',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updater VARCHAR(64) NULL DEFAULT '' COMMENT '更新者',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
active_user_id BIGINT GENERATED ALWAYS AS (
CASE WHEN left_at IS NULL THEN user_id ELSE NULL END
) STORED,
active_pm_project_id BIGINT GENERATED ALWAYS AS (
CASE WHEN project_role = 'pm' AND left_at IS NULL THEN project_id ELSE NULL END
) STORED,
PRIMARY KEY (id),
UNIQUE KEY uk_project_active_member (project_id, active_user_id),
UNIQUE KEY uk_project_active_pm (active_pm_project_id),
KEY idx_pm_user_active (user_id, left_at),
KEY idx_pm_project_role_active (project_id, project_role, left_at),
CONSTRAINT chk_project_role CHECK (project_role IN ('pm', 'product', 'developer', 'tester', 'viewer')),
CONSTRAINT chk_member_type CHECK (member_type IN ('core', 'support'))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='项目成员表';
```
### 这里有一个关键点
设计文档中的这段 SQL
```sql
CREATE UNIQUE INDEX uk_one_pm_per_project
ON system_project_member(project_id)
WHERE project_role = 'pm' AND left_at IS NULL;
```
在 MySQL 8 里不能直接这样写,因为 MySQL 不支持带 `WHERE` 的部分唯一索引。
所以推荐用上面的“生成列 + 唯一索引”实现:
- `active_pm_project_id`
- `UNIQUE KEY uk_project_active_pm (active_pm_project_id)`
这是这份设计文档里最需要提前修正的一个点。
---
## 6. 最终建议的职责边界
### 6.1 组织与人员
- `system_dept`:组织树节点
- `system_users.dept_id`:用户主组织归属
- `system_users.position_id`:用户主岗位
- `system_org_leader_relation`:组织负责人关系
- `system_user_management_relation`:直接管理关系
### 6.2 功能权限
- `system_role`
- `system_user_role`
- `system_menu`
- `system_role_menu`
只管“能不能访问模块/菜单/接口”。
### 6.3 数据范围
- `system_project_member`
- `system_org_leader_relation`
- `system_user_visibility_config`
只管“能看哪些项目/哪些人的数据”。
---
## 7. 推荐迁移顺序
### 第一阶段:建立正确主模型
1.`system_dept` 增加 `org_type``path``level`
2.`system_users` 增加 `position_id``employment_status``resigned_at`
3.`system_post` 增加 `post_type``level_rank`
### 第二阶段:建立关系表
1. 新建 `system_org_leader_relation`
2.`system_dept.leader_user_id` 迁移进去
3. 新建 `system_user_management_relation`
4. 新建 `system_user_visibility_config`
### 第三阶段:建立项目权限模型
1. 新建 `system_project_member`
2. 所有项目角色改从 `system_project_member` 读取
3. 所有项目可见范围改从“自己参与 + 组织负责人 + 特殊配置”计算
### 第四阶段:按最终模型收口
1. 删除 `system_dept.leader_user_id`
2. 删除 `system_users.post_ids`
3. 删除 `system_user_post`
4. 保持 `system_role` 仅承载 RBAC 角色定义
---
## 8. 你这次最应该优先改的地方
如果你想最小成本先把模型拉正,我建议优先级按下面来:
1. `system_dept``path``org_type``code`,删除 `leader_user_id`
2. `system_users` 增加 `position_id`,删除 `post_ids`
3. 新建 `system_org_leader_relation`
4. 新建 `system_project_member`
5. 新建 `system_user_visibility_config` 体系
6. 删除 `system_user_post`,并让岗位只保留单一事实来源
7. 保持 `system_role` 精简,只保留设计文档需要的 RBAC 能力
这 7 步做完,表结构才算真正和当前权限设计文档一致。