This commit is contained in:
DKJ 2026-02-12 22:22:28 +08:00
commit 394cb3cc18
3 changed files with 554 additions and 1 deletions

View File

@ -0,0 +1,553 @@
节点权限设计说明(支持两棵树 + 子节点操作 + 全局 tree 规则)
本说明基于当前的权限表设计约束:
- 有两棵树:`standards` 和 `projects`
- 只有 **Allow**(允许)权限,没有 Deny也没有继承。
- 使用一张表 `node_permission` 管理权限,支持 6 类主体:
- 用户:`user`
- 用户组:`group`
- 角色:`role`
- 所有人:`everyone`
- 父节点的 owner`parent_owner`
- 子树根节点的 owner`root_owner`
---
### 一、`node_permission` 表字段定义
```sql
CREATE TABLE node_permission (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
-- 树维度:
-- 'standards' : 只对 standards 生效
-- 'projects' : 只对 projects 生效
-- NULL : 两棵树都生效(全局规则)
tree VARCHAR(32) NULL,
-- 节点维度:
-- NULL : 默认权限(作用范围由 tree 决定)
-- > 0 : 某个具体节点的专属权限
node_id BIGINT NULL,
-- 主体类型:
-- user : 用户user.id
-- group : 用户组group.id
-- role : 角色(如 super/sAdmin/pAdmin
-- everyone : 所有人
-- parent_owner : 父节点的 owner
-- root_owner : 当前子树根节点的 owner
principal_type ENUM(
'user',
'group',
'role',
'everyone',
'parent_owner',
'root_owner'
) NOT NULL,
-- 主体标识:
-- user/group : 对应 id 的字符串
-- role : 角色 code
-- everyone / parent_owner / root_owner : 固定为 NULL
principal_key VARCHAR(64) NULL,
-- 节点自身权限
can_list_children TINYINT(1) NOT NULL DEFAULT 0,
can_add_child_folder TINYINT(1) NOT NULL DEFAULT 0,
can_add_child_doc TINYINT(1) NOT NULL DEFAULT 0,
can_delete_node TINYINT(1) NOT NULL DEFAULT 0,
can_edit_node TINYINT(1) NOT NULL DEFAULT 0,
-- 文档内容权限
can_read_doc TINYINT(1) NOT NULL DEFAULT 0,
can_edit_doc TINYINT(1) NOT NULL DEFAULT 0,
can_delete_doc TINYINT(1) NOT NULL DEFAULT 0,
-- 子节点操作权限
can_delete_child_node TINYINT(1) NOT NULL DEFAULT 0,
can_edit_child_node TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-- 同一 (tree, node_id, principal_type, principal_key) 只允许一条
UNIQUE KEY uk_tree_node_principal (tree, node_id, principal_type, principal_key),
KEY idx_node (node_id),
KEY idx_principal (principal_type, principal_key)
);
```
---
## 二、`node_permission` 关键字段语义
这里只说明与鉴权相关的字段
- **节点维度**
- `node_id`
- `NULL`:表示“**默认权限**”,作用范围由 `tree` 决定:
- `tree = 'standards'`:只对 standards 全部节点生效;
- `tree = 'projects'`:只对 projects 全部节点生效;
- `tree IS NULL`:对两棵树全部节点生效。
- `> 0`:表示“**某个具体节点的专属权限**”,此时 `tree` 应等于该节点所属树。
- **主体Principal维度**
- `principal_type``'user' | 'group' | 'role' | 'everyone' | 'parent_owner' | 'root_owner'`
- `principal_key`根据principal_type确定其含义
- `user`:对应用户表 `user.id` 的字符串形式(如 `'12'`
- `group`:对应用户组表 `group.id` 的字符串形式
- `role`:角色编码(如 `'super'`、`'sAdmin'`、`'pAdmin'`
- `everyone`:固定为 `NULL`
- `parent_owner`:固定为 `NULL`
- `root_owner`:固定为 `NULL`
- **节点自身权限字段**
- `can_list_children`:是否可展开节点、列出子节点。
- `can_add_child_folder`:是否可在该节点下新增文件夹(`node_type='folder'`)。
- `can_add_child_doc`:是否可在该节点下新增文档(`node_type='doc'`)。
- `can_delete_node`:是否可删除该节点本身。
- `can_edit_node`是否可修改该节点本身的元数据名称、排序、owner 等)。
- **文档内容权限字段**
- `can_read_doc`:是否可读取文档内容。
- `can_edit_doc`:是否可编辑文档内容。
- `can_delete_doc`:是否可删除文档节点。
- **对子节点操作权限字段**
- `can_delete_child_node`:是否有权删除“该节点的直接子节点”。
- `can_edit_child_node`:是否有权修改“该节点的直接子节点”的元数据(如 name、owner
**唯一约束建议:**
- `(tree, node_id, principal_type, principal_key)` 唯一。这样:
- 对于某棵树上的某个节点 + 某个主体,只会有一条“节点专属”权限记录;
- 对于某棵树上的某个主体,只会有一条“默认”规则;
- `tree IS NULL AND node_id IS NULL` 的记录则是“两棵树共用的唯一全局默认”。
---
## 三、主体集合Principals的构造
鉴权的第一步是,把“当前用户在权限系统里是谁”表达成一个**主体集合**,集合中的每个元素是一个 `(principal_type, principal_key)`
设:
- 当前用户 id 为 `U`
- 当前操作的节点 id 为 `N`
- 当前节点所属的树为 `T``'standards'` 或 `'projects'`,可以从 `nodes` 表的字段`tree_type`获得 。
### 3.1 主体集合的组成
主体集合 `P` 至少包含以下几类元素:
1. **用户本身user**
- 元素:`('user', U.toString())`
2. **用户所属的所有组group**
- 从 `groupUser` 中查询:`WHERE user_id = U` 得到所有 `group_id`
- 每个组生成一个主体:`('group', groupId.toString())`。
3. **用户的角色role**
- `users` 表有一个 `role` 字段(值为 `'super'` / `'sAdmin'` / `'pAdmin'`),可获取到角色。
- 生成主体:`('role', roleCode)`。
4. **everyone所有人**
- 固定加入:`('everyone', NULL)`。
5. **parent_owner父节点 owner**
- 先在 `nodes` 表中拿到当前节点的父节点 id`parentId`。
- 若 `parentId` 大于 0则再从 `node` 表读出该父节点的 `owner` 字段:
- 若 `owner == U`,说明当前用户是父节点的 owner则加入`('parent_owner', NULL)`。
- 否则不加入 `parent_owner`
6. **root_owner子树根节点 owner**
- 定义一个函数 `isSubtreeRootOwner(N, U)`
- 输入:当前节点 `N`、当前用户 `U`
- 算法:根据节点的`code``nodes`表的字段`code`形如`001003002008`,表示该节点的祖先节点的`code`为`001`、`001003`、`001003002`从数据库select出所有祖先节点的`owner`的`id`,判断当前用户`U`是否其中一员
- 输出true或false。
- 在主体构造过程中:
- 若`isSubtreeRootOwner(N, U)` 返回`true`,说明当前用户是该子树根节点的 `owner`,则加入:`('root_owner', NULL)`
- 否则不加入 `root_owner`
最终,`P` 是一组主体元素(可能包含 user / group / role / everyone / parent_owner / root_owner
---
## 四、权限记录的分类:默认 vs 节点专属
`node_permission` 中,根据 `tree``node_id` 组合,可以区分三类规则:
1. **全局默认规则(对两棵树都生效)**
- 条件:`tree IS NULL AND node_id IS NULL`。
- 语义:对 standards 和 projects 的所有节点都生效。
2. **按树的默认规则**
- 条件:`tree = T AND node_id IS NULL`。
- 语义:只对树 `T` 的所有节点生效。
3. **节点专属规则**
- 条件:`tree = T AND node_id = N`。
- 语义:只对树 `T` 上的节点 `N` 生效,用来覆盖默认设置。
> 说明:当存在`node_id > 0` 的规则时,**不使用 `tree IS NULL` 以及`node_id IS NULL` 的记录**,这两个规则仅用于默认规则。
**优先级规则(同一主体维度):**
对给定树 `T`、节点 `N`、主体 `(principal_type, principal_key)`,从最具体到最泛化依次为:
1. 节点专属规则:`tree = T AND node_id = N`
2. 树级默认规则:`tree = T AND node_id IS NULL`
3. 全局默认规则:`tree IS NULL AND node_id IS NULL`
4. 如果以上三类都不存在,则该主体对该节点“没有任何配置”,视为该主体不给任何权限。
---
### 五、典型场景下的 `INSERT` 示例
#### 1. 全局默认 everyone所有人只能展开树结构
**两棵树所有节点** 生效(`tree IS NULL AND node_id IS NULL`
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
NULL, NULL, 'everyone', NULL,
1,
0, 0,
0, 0,
0, 0, 0,
0, 0
);
```
#### 2. 全局默认 parent_owner父节点 owner 管理直接子节点
对两棵树所有节点生效,表达“父节点 owner 默认可以管理直接子节点”和“看子列表”:
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
NULL, NULL, 'parent_owner', NULL,
1,
1, 1,
0, 0,
0, 0, 0,
1, 1 -- 修改直接子节点
);
```
#### 3. 全局默认 root_owner子树根节点 owner 管理整棵子树
比如项目负责人(子树根的 owner对整棵子树有较大权限
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
NULL, NULL, 'root_owner', NULL,
1,
1, 1,
1, 1,
1, 1, 1,
1, 1
);
```
4. standards 专用默认:技术标准管理员(角色 sAdmin全权管理 standards
只对 standards 生效projects 不受影响):
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
'standards', NULL, 'role', 'sAdmin',
1,
1, 1,
1, 1,
1, 1, 1,
1, 1
);
```
#### 5. projects 专用默认:项目管理员(角色 pAdmin管理 projects
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
'projects', NULL, 'role', 'pAdmin',
1,
1, 1,
1, 1,
1, 1, 1,
1, 1
);
```
#### 6. 超级管理员专用默认:
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
NULL, NULL, 'role', 'super',
1,
1, 1,
1, 1,
1, 1, 1,
1, 1
);
```
#### 7. 某个敏感节点对 everyone 做节点专属覆盖
假设节点 id = 123是一个敏感目录希望 **everyone 在这个节点上完全没有权限(连展开都不行)**,但其它节点仍按默认规则:
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
'standards', 123, 'everyone', NULL,
0,
0, 0,
0, 0,
0, 0, 0,
0, 0
);
```
由于这是 `tree='standards' AND node_id=123 AND principal_type='everyone'` 的节点专属记录,会**覆盖**对全局默认 `everyone` 的配置。
#### 8. 针对某个用户在单节点上授予完全权限
例如用户 id = 42在节点 500 上拥有完全权限(不依赖角色/owner
```sql
INSERT INTO node_permission (
tree, node_id, principal_type, principal_key,
can_list_children,
can_add_child_folder, can_add_child_doc,
can_delete_node, can_edit_node,
can_read_doc, can_edit_doc, can_delete_doc,
can_delete_child_node, can_edit_child_node
) VALUES (
'projects', 500, 'user', '42',
1,
1, 1,
1, 1,
1, 1, 1,
1, 1
);
```
## 六、计算“对某个节点的有效权限”的通用算法
我们定义一个抽象的“有效权限对象”,包含所有布尔权限字段:
- `can_list_children`
- `can_add_child_folder`
- `can_add_child_doc`
- `can_delete_node`
- `can_edit_node`
- `can_read_doc`
- `can_edit_doc`
- `can_delete_doc`
- `can_delete_child_node`
- `can_edit_child_node`
记这个对象为 `R`,初始时这十个值全部为 `false`
### 6.1 输入
计算函数需要的输入信息:
- 用户 id`U`
- 节点 id`N`
- 树标识:`T ∈ {'standards', 'projects'}`
### 6.2 步骤 1构造主体集合 `P`
按照第二节“主体集合的构造”的规则,从 `U`、`N`、`node`/`groupUser`/`user` 表中计算出主体集合 `P`
结果是若干个 `(principal_type, principal_key)` 的集合,例如:
- `('user', '12')`
- `('group', '3')`
- `('role', 'sAdmin')`
- `('everyone', NULL)`如果有一个全局everyone的配置以及对N节点的everyone配置则只保留N节点自己的everyone配置
- `('parent_owner', NULL)`(如果满足条件)
- `('root_owner', NULL)`(如果满足条件)
### 6.3 步骤 2读取节点专属权限记录
`node_permission` 表中,查询**当前树 + 当前节点**的所有权限记录:
- 条件:`tree = T AND node_id = N`
结果是一组行,每行包含:
- `principal_type`
- `principal_key`
- 十个 `can_*` 布尔字段
这组记录可以在内存中按 `(principal_type, principal_key)` 组织成一个映射结构,后面用来快速查找:
- 键:某个主体 `(principal_type, principal_key)`
- 值:对应的一行权限记录。
### 6.4 步骤 3读取默认权限记录树级 + 全局)
`node_permission` 表中,查询**当前树相关的所有默认权限记录**
- 条件:`(tree = T OR tree IS NULL) AND node_id IS NULL`
这些记录中:
- `tree = T` 的记录是“树级默认规则”;
- `tree IS NULL` 的记录是“全局默认规则”。
在内存中同样按 `(principal_type, principal_key, tree)` 或类似结构组织,以便后续对同一主体区分“树级默认”和“全局默认”。
### 6.5 步骤 4按主体合并权限带 tree 优先级)
对主体集合中的每一个主体 `p = (ptype, pkey)` 执行如下逻辑:
1. **查找节点专属记录**
- 在“节点专属映射”中查找键 `(ptype, pkey)` 对应的记录。
- 若存在,则记为 `row_node`
2. **查找树级默认记录**
- 在“默认映射”中查找满足:
- `principal_type = ptype`
- `principal_key = pkey`
- `tree = T`
- 若存在,则记为 `row_tree_default`
3. **查找全局默认记录**
- 在“默认映射”中查:
- `principal_type = ptype`
- `principal_key = pkey`
- `tree IS NULL`
- 若存在,则记为 `row_global_default`
4. **确定权限**
- 如果 `row_node`存在用户`U` 的记录:使用 `row_node`中用户`U`的特定权限配置,其它配置全部忽略;
- 否则将`row_node`、 `row_tree_default`、`row_global_default`中的所有权限做并集即只要其中一个赋予了权限就有该权限相应地给权限对象R赋值。
---
## 七、针对具体操作的鉴权规则
### 7.1 展开节点 / 查看子节点列表
**操作:** 展开节点 `N`,列出其直接子节点。
- 判断方法:
- 根据 `U, N, T` 计算一次有效权限 `R`
- 若 `R.can_list_children == true`,则允许展开;否则禁止。
### 7.2 在节点下创建子文件夹 / 子文档
**操作:** 在节点 `N` 下创建子节点:
- 创建文件夹:新子节点 `node_type = 'folder'`
- 创建文档:新子节点 `node_type = 'doc'`
**判断方法:**
- 先对父节点 `N` 计算有效权限 `R`
- 创建文件夹时:
- 允许条件:`R.can_add_child_folder == true`。
- 创建文档时:
- 允许条件:`R.can_add_child_doc == true`。
### 7.3 修改节点自身(重命名、改 owner 等)
**操作:** 修改节点 `N` 本身的元数据名称、owner、排序等
**判断方法:**
- 对节点 `N` 计算有效权限 `R`
- 允许条件:`R.can_edit_node == true`。
### 7.4 删除节点自身
**操作:** 删除节点 `N` 本身。
**判断方法:**
- 对节点 `N` 计算有效权限 `R`
- 允许条件:`R.can_delete_node == true`。
### 7.5 文档内容的读取 / 编辑 / 删除
假设节点 `N` 是一个文档节点(`node_type = 'doc'`)。
- **读取文档内容:**
- 对节点 `N` 计算有效权限 `R`
- 允许条件:`R.can_read_doc == true`。
- **编辑文档内容:**
- 对节点 `N` 计算有效权限 `R`
- 允许条件:`R.can_edit_doc == true`。
- **删除文档文档节点:**
- 对节点 `N` 计算有效权限 `R`
- 允许条件:`R.can_delete_doc == true` 。
### 7.6 删除子节点
**操作:** 在父节点 `P` 下,删除一个直接子节点 `C``C.parent = P`)。
- 允许条件:父节点 `P` 上的 `can_delete_child_node== true`
### 7.7 修改子节点name / owner 等)
**操作:** 在父节点 `P` 下,修改直接子节点 `C` 的元数据名称、owner 等)。
- 允许条件:父节点 `P` 上的`can_edit_child_node== true`

View File

@ -1,8 +1,139 @@
设计文档
树形结构:
表结构
node:节点表:
1、表结构
departments部门表
字段名
含义
类型
说明
id
int
自增、主键
name
部门名称
varchar(50)
head
部门领导id
int
外键用户表id可为空
reviewer
部门审核负责人id
int
外键用户表id可为空
parent
父节点ID
int
为0表示1级节点。外键本表id
sort_order
排序权重
int
越小越靠前
create_time
创建时间
time
departMember部门人员表
字段名
含义
类型
说明
id
int
自增、主键
department
部门id
int
外键部门表的id
member
人员id
int
外键用户表id
users用户表
字段名
含义
类型
说明
id
int
自增、主键
username
登录账号
varchar(40)
password
登录密码
varchar(255)
密码通过Argon2算法hash的结果
number
工号
varchar(50)
name
姓名
varchar(20)
phone
电话号码
varchar(20)
email
电子邮箱
varchar(40)
department
部门
int
外键部门表的id
role
角色
varchar(30)
super超级管理员拥有所有权限、
sAdmin技术标准管理员可以管理standards树
pAdmin项目管理员可以管理projects树
user:普通管理员。
groups用户组表
字段名
含义
类型
说明
id
int
自增、主键
groupname
组名
varchar(40)
description
描述
varchar(1000)
groupUser组用户表
字段名
含义
类型
说明
id
int
自增、主键
group_id
组id
int
外键
user_id
用户id
int
外键
nodes:节点表:
字段名
含义
类型
@ -23,21 +154,25 @@ node_type
类型
VARCHAR(10)
以下之一folder、docfolder下允许添加folder和doc节点doc节点只能作为文档编辑其下不能添加节点
owner_id
owner
所有者id
int
外键用户表id
reviewer
评审人
int
外键用户表id
title
标题
varchar(50)
parent_id
parent
父节点ID
int
为0表示1级节点
为0表示1级节点。外键本表id
sort_order
排序权重
int
越小越靠前
create_time
创建时间
@ -46,17 +181,22 @@ time
hierarchy
层次
int
product scenario及子树1
product definition及子树2
product target及子树3
attribute, function及子树4
system及子树5
component及子树6
product scenario及子树10
product definition及子树20
product target及子树30
attribute及子树40
function及子树41
system及子树50
component及子树60
projects及创建的子树不包括branch的子树0
content
内容
varchar(10000)
存储富文本文档的内容
version
版本
varchar(50)
文档的当前版本
last_change
最后修改时间
time
@ -69,18 +209,17 @@ ref_id
引用的文档节点id
外键本表的id
task_type
分工类型
varchar(15)
以下之一:project、standards。MainTree下的结点均为standardsProjects下的结点均为project
tree_type
所述树
varchar(30)
以下之一:standards、projects
source_type
文档来源类型
varchar(10)
enum
如果ref_id不为空则为以下之一map, clone
map_version
map的版本id
int
外键docVersion表的id如果source_type为map才有值
说明:
1、预先创建树形结构一级节点product scenario, product definition, product target, attribute, function, system, component赋好层次的值hierarchy。projects的层次值为0。
2、sort_order的作用每个节点下的所有n个子节点的sort_order为从1到n的值。支持调整显示顺序sort_order小的显示在前。在界面上允许拖拽调整顺序拖拽的目的地不能改变父节点。
docVersion文档版本表
字段名
@ -91,65 +230,340 @@ id
int
自增、主键
doc_id
doc
文档节点id
int
外键node表的id
version
版本号
varchar(20)
xxx.yyy.zzz形式xxx为public的大版本、yyy为release的小版本、zzz为review的微版本分别从1开始编号
xxx.yyy形式xxx为release的大版本、yyy为review的小版本
owner
所有者id
int
外键用户表id
title
标题
varchar(50)
create_time
创建时间
time
创建该版本的时间
content
内容
varchar(10000)
last_change
最后修改时间
time
last_change_by
最后修改人id
int
type
版本类型
enum
包含review、release两种
docReviewRequest文档审核请求表
字段名
含义
类型
说明
id
int
自增、主键
doc
源文档节点id
int
外键node表的id
version
review针对的版本
int
外键, docVersion 表的id
submitter
提交人id
int
外键user表的id
submit_comment
提交时附言
varchar(3000)
submitted_at
提交时间
time
reviewer
审核人id
int
外键user表的id
review_comment
审核意见
varchar(3000)
review_at
审核时间
time
status
状态
varchar(30)
包含: Pending、Approved、Rejected
docMap文档map表
字段名
含义
类型
说明
id
int
自增、主键
src_doc
源文档节点id
int
外键node表的id
dest_folder
目标文件夹节点id
int
外键node表的id
dest_doc
目标文档节点id
int
外键node表的id
version
map所使用的版本
int
外键, docVersion 表的id
create_time
创建时间
time
current_status
当前状态
varchar(32)
包含:
pendingReceive : 已发起,等待接收方处理
received : 接收方处理中
pendingReview : 接收方已提交给其领导评审
pendingApprove : 接收方领导已 review 通过,等待部门领导 approve
accepted : 部门领导 approve 完成
rejected : 驳回
cancelled : 撤回
update_time
最后一次更新时间
time
next_op_user
待处理人
int
外键user表的id
docMapHandshake文档map握手记录表
字段名
含义
类型
说明
id
int
自增、主键
map_id
docMap的记录id
int
外键docMap表的id
action
操作
varchar(32)
本步骤所做的处理,包括:
map : 发起 map
receive : 接收方确认接收
reject : 接收方驳回
submitReview : 接收方提交领导审核
ReviewPass: 接收方领导 review 通过
ReviewReject: 接收方领导驳回
ApprovePass : 接收方部门领导 approve通过
ApproveReject : 接收方部门领导驳回
from_status
变更前状态
varchar(32)
第一次创建时为 NULL
to_status
变更后状态
varchar(32)
op_user
操作人
int
外键user表的id
comments
备注
varchar(3000)
op_time
创建时间
time
due_time
截止时间
time
如果状态是receiveddue_time是本方承诺的处理时间如果状态是rejecteddue_time是希望对方处理的截止时间
node_permission节点访问权限表
字段名
含义
类型
说明
id
int
自增、主键
tree
VARCHAR(32)
standards : 只对standards生效
projects : 只对 projects 生效
NULL : 两棵树都生效(全局规则)
node
节点id
int
NULL : 默认权限(作用范围由 tree 决定)
> 0 : 某个具体节点的专属权限
principal_type
主体类型
varchar(30)
以下之一: user, group, role, everyone, parent_owner, root_owner
principal_key
主体标识
varchar(30)
根据principal_type不同具有不同的值user : 用户user.id
group : 用户组group.id
role : 角色(如 super/sAdmin/pAdmin
everyone/parent_owner/root_owner:固定为 NULL
can_list_children
查看子节点列表
TINYINT(1)
DEFAULT 0,
can_add_child_folder
在节点下创建文件夹
TINYINT(1)
DEFAULT 0,
can_add_child_doc
在节点下创建文档
TINYINT(1)
DEFAULT 0,
can_delete_node
删除节点
TINYINT(1)
DEFAULT 0,
can_edit_node
修改节点元数据
TINYINT(1)
DEFAULT 0,
can_read_doc
读取文档内容
TINYINT(1)
DEFAULT 0,
can_edit_doc
修改文档内容
TINYINT(1)
DEFAULT 0,
can_delete_doc
删除文档
TINYINT(1)
DEFAULT 0,
can_delete_child_node
删除子节点
TINYINT(1)
DEFAULT 0,
can_edit_child_node
修改子节点元数据
TINYINT(1)
DEFAULT 0,
update_time
修改时间
time
操作:
1、预先创建树形结构一级节点product scenario, product definition, product target, attribute, function, system, component赋好层次的值hierarchy。projects的层次值为0。
2、sort_order的作用每个节点下的所有n个子节点的sort_order为从1到n的值。支持调整显示顺序sort_order小的显示在前。在界面上允许拖拽调整顺序拖拽的目的地不能改变父节点。
3、节点的右键菜单
2、系统功能
2.1 管理员功能
系统预先创建超级管理员超级管理员具有全部权限技术标准管理员可以管理部门、用户和standards树项目管理员可以管理部门、用户和projects树。
2.1.1 管理部门
界面分为左右两部分。
界面左部为部门,显示为一个树形结构,树根为公司名称,可在树形节点上操作:添加下级部门、添加同级部门、修改。
添加新部门时,需要输入部门名称,部门领导、审核负责人可暂时不选择。
选中某个部门时,在界面右部显示部门名称、领导及审核负责人,其下为一个表格,显示部门成员。
如果一个部门有下级部门,则不能有部门成员,有部门成员则不能有下级部门。
2.1.2 创建用户
创建用户界面需要输入用户名、密码、工号、姓名、电话号码、email、部门、角色其中工号、电话号码、email、部门可为空密码默认为ABC123.com。
如果操作人是超级管理员,角色单选按钮三选一:技术标准管理员、项目管理员、普通管理员。
如果操作人是技术标准管理员或项目管理员,角色按钮隐藏,只能为普通管理员。
使用 Argon2 进行密码哈希。
2.1.3 用户管理
可以通过输入工号、姓名、部门进行联合模糊查询,使用表格显示查询结果,表格头可以点击排序(排序时要求从数据库重新查询,不能仅针对该页排序),默认按姓名升序排列。
表格第一列为复选框,可以多选进行删除。表格每一行有两个按钮:编辑、删除。
2.1.4 用户组管理
界面分为左右两部分。
界面左部为用户组列表,在列表的上部能根据名称进行查询,有添加、删除、编辑按钮。可以在列表中多选以删除。
界面右部为用户列表包含序号、工号、姓名、电话、email共5列。在用户组列表里选择一行时右部用户列表显示该组的所有成员。对组里的成员有添加、删除按钮。
2.2 树节点管理
2.2.1 树结构介绍:
hierarchy=0
hierarchy>0
hierarchy>0
总共包含4棵树Inbox收件箱Outbox(发件箱)、Standards技术标准、Projects项目
1根节点没有"添加同级节点"
2node_type为doc的节点没有"添加下级节点"(文档下不能添加子节点)
3ref_id不为空的节点没有"edit"(即不能编辑引用自其它文档的文档)
4node_type为folder的节点没有"copy to"、"clone to"和"map to"这三个操作仅针对文档。task_type为standards的节点没有"map to"projects树下的文档才可map
5hierarchy为0的节点以及node_type为doc的节点没有"branch to"(hierarchy大于0的节点包括maintree里的节点或者从maintree里branch到projects的节点)
4、创建节点添加同级节点、添加下级节点界面如下
4node_type为folder的节点没有"copy to"、"clone to"和"map to"(这三个操作仅针对文档)。字段tree为standards的节点没有"map to"projects树下的文档才可map
5hierarchy为0的节点以及node_type为doc的节点没有"branch to"(hierarchy大于0的节点包括standards树里的节点或者从standards里branch到projects的节点)
2.2.2 创建节点(添加同级节点、添加下级节点)界面如下:
界面上输入title、node_type、owner从用户列表里选择在保存时自动生成id、uuid、sort_order、create_time获取parent_id、继承父节点的hierarchy、task_type。
界面上输入title、node_type、owner从用户列表里选择、reviewerdocument类型才有reviewer从用户列表里选择在保存时自动生成id、uuid、sort_order、create_time获取parent、继承父节点的hierarchy、task_type。content、last_change、last_change_by、ref_id、source_type为空。
code生成方法按照节点级别编号一级节点的编号为000,001,002,003,004;二级节点的编号为001000,001001,001002,001003这4个编号表明节点都是编号001的子节点。001的二级节点的编号从001000到001999如果中间某些code被删除而导致缺失则在添加了001999后绕回到001000及之后的缺失编号。说明000到999不要求连续删除后可以缺失不要求排序大编号在小编号之前也可以
sort_order生成方法如果是添加下级节点则新节点的sort_order为已有下级节点最大sort_order加1。如果是添加同级节点则新节点的sort_order为操作节点的sort_order加1即添加到操作节点的后面同一父节点的后面的所有节点sort_order都需要加1。
5、edit菜单只能修改title和owner
6、delete菜单
2.2.3 edit菜单
只能修改title、owner和reviewer。
2.2.4 delete菜单
node_type为doc的节点如果有其它节点的ref_id指向自己则提示"有其它文档由本文档clone或map不能删除"。如果存在外键指向自己,则提示"存在外键约束,不能删除"。
node_type为folder的节点如果以该节点为根的子树上存在文档则提示"请先删除子树上的文档,才能删除本文件夹"。
7、copy to菜单复制节点
选中一个doc节点点击copy to时弹出界面要求选择maintree或projects里的一个folder节点需要检查操作人员是否对该节点有write权限点击确认即执行copy操作。
node_type为folder的节点如果以该节点为根的子树上存在文档则提示"请先删除子树上的文档,才能删除本文件夹"。删除文件夹时,需要删除整棵子树。
2.2.5 copy to/from菜单(复制节点):
选中一个doc节点要求对该节点有can_read_doc权限点击右键菜单copy to时弹出界面要求选择standards或projects里的一个folder节点要求对该节点有can_add_child_doc权限输入owner默认是所选folder节点的owner和reviewer点击确认即执行copy操作。
copy将在数据库中添加新记录其中
parent_id为目标folder节点的id。
parent为目标folder节点的id。
code根据parent folder的code添加3位生成规则见"创建新节点"。
owner_id、task_type、hierarchy与parent folder的owner_id、task_type、hierarchy相同
task_type、hierarchy与parent folder的task_type、hierarchy相同
id、uuid、sort_order添加为最后一个节点、create_time为当前时间根据规则生成。
字段node_type、title、content、last_change、last_change_by、ref_id、source_type、map_version从选中的doc节点复制。
8、clone to菜单对节点添加引用
选中一个doc节点点击clone to时弹出界面要求选择maintree或projects里的一个folder节点需要检查操作人员是否对该节点有write权限点击确认即执行clone操作。
字段node_type、title、content、last_change、last_change_by、ref_id、source_type从选中的doc节点复制。
相应有个copy from菜单选中一个folder节点要求对该节点有can_add_child_doc权限点击右键菜单copy from时弹出界面要求选择standards或projects里的一个doc节点要求对该节点有can_read_doc权限输入owner默认是所选folder节点的owner和reviewer点击确认即执行copy操作。
2.2.6 clone to/from菜单对节点添加引用
选中一个doc节点要求对该节点有can_read_doc权限点击clone to时弹出界面要求选择standards或projects里的一个folder节点要求对该节点有can_add_child_doc权限输入owner默认是所选folder节点的owner无需reviewer点击确认即执行clone操作。
clone将在数据库中添加新记录其中
parent_id为目标folder节点的id。
parent为目标folder节点的id。
code根据parent folder的code添加3位生成规则见"创建新节点"。
owner_id、task_type、hierarchy与parent folder的owner_id、task_type、hierarchy相同
task_type、hierarchy与parent folder的task_type、hierarchy相同
id、uuid、sort_order添加为最后一个节点根据规则生成。
如果选中doc节点的ref_id为空则新记录的ref_id为该doc的idsource_type为clonemap_version为空如果选中doc节点的ref_id不为空则新记录的ref_id复制该doc的ref_idsource_type为clonemap_version为空
title、content、last_change、last_change_by为空在select检索时根据ref_id获取。
如果选中doc节点的ref_id为空则新记录的ref_id为该doc的idsource_type为clone如果选中doc节点的ref_id不为空则新记录的ref_id复制该doc的ref_idsource_type为clone
reviewer、title、content、last_change、last_change_by为空在select检索时根据ref_id获取。
字段node_type、create_time从选中的doc节点复制。
疑问map的节点能否被copy和clone
9、branch to菜单复制子树
选中一个folder节点点击branch to时弹出界面要求选择projects里hierarchy为0的一个folder节点需要检查操作人员是否对该节点有write权限点击确认即执行复制操作。
相应有个clone from菜单选中一个folder节点要求对该节点有can_add_child_doc权限点击右键菜单clone from时弹出界面要求选择standards或projects里的一个doc节点要求对该节点有can_read_doc权限输入owner默认是所选folder节点的owner无需reviewer点击确认即执行copy操作。
2.2.7 branch from菜单(复制子树):
选中projects树里hierarchy为0的一个folder节点要求对该节点有can_add_child_doc和can_add_child_folder权限点击branch from时弹出界面在界面左部显示standards和projects树standards树里的所有节点以及projects里hierarchy>0的所有节点前都有一个复选框可以选择若干节点为每个选择的节点指定owner、为每个ref_id为空的文档节点指定reviewer,点击确认,即执行复制操作。
复制将在数据库中添加新记录,需要逐层添加,先添加被复制子树的根节点,再添加它的子孙节点。
其中根节点复制到目标folder的下面。对于根节点
parent_id为目标folder节点的id。
parent为目标folder节点的id。
code根据parent folder的code添加3位生成规则见"创建新节点"。
owner_id、task_type与parent folder的owner_id、task_type相同
task_type与parent folder的task_type相同。
owner、reviewer由界面上获取。
id、uuid、sort_order添加为最后一个节点、create_time为当前时间根据规则生成。
字段node_type、hierarchy、title、content、last_change、last_change_by、ref_id、source_type、map_version从选中的doc节点复制。
字段node_type、hierarchy、title、content、last_change、last_change_by、ref_id、source_type从选中的doc节点复制。
以下每层节点在复制时注意它的parent folder为复制过来的那个parentid为新创建的。code也根据新的parent folder的code添加3位。其它复制规则同上。
8、map to菜单
2.2.8 map to菜单

View File

@ -947,7 +947,7 @@ const handleAddSibling = () => {
console.log('parentNode found:', parentNode)
//
// Main Tree使parentNodeId
// 使parentNodeId
addNodeDialog.value = {
show: true,
mode: 'sibling',