团队管理
版本: v0.34.0+ | 组织架构管理 | 层级团队结构
概述
团队管理模块是 ChainlessChain 企业版权限体系的核心组件,负责组织内子团队的创建、成员管理和层级结构维护。它支持多级父子团队嵌套构建完整组织架构树,提供 lead/member/guest 三级角色体系和删除保护机制,通过 8 个 IPC 通道与权限引擎、企业审计模块深度集成。
核心特性
- 🏢 多级团队层次: 支持父子团队嵌套,构建完整组织架构树
- 👤 角色体系: lead(负责人)、member(成员)、guest(访客)三级角色划分
- 🔒 删除保护: 存在子团队时禁止删除,保障数据完整性
- 🔄 负责人变更: 自动完成角色升降级,确保数据一致性
- 📊 8 个 IPC 通道: 完整的团队 CRUD 和成员管理 API
- 🔗 深度集成: 与权限引擎、企业审计模块无缝联动
系统架构
┌──────────────┐
│ Renderer │
│ (Vue 页面) │
└──────┬───────┘
│ IPC (8 通道)
▼
┌──────────────────────────────────┐
│ permission-ipc.js │
│ (IPC 路由注册) │
└──────────────┬───────────────────┘
│
┌────────▼────────┐
│ TeamManager │
│ (Singleton) │
│ ┌────────────┐ │
│ │ 团队 CRUD │ │
│ │ 成员管理 │ │
│ │ 层级查询 │ │
│ └────────────┘ │
└────────┬────────┘
│
┌────────▼────────┐
│ SQLite │
│ org_teams │
│ org_team_members│
└─────────────────┘系统概述
团队管理模块(TeamManager)是 ChainlessChain 企业版权限体系的核心组件之一,负责组织内子团队的创建、成员管理以及层级结构维护。该模块基于 SQLite 数据库实现持久化存储,支持多级团队嵌套、团队负责人指定、成员角色划分等企业级组织架构功能。
核心特性:
- 支持多级团队层次结构(父子团队关系)
- 团队负责人自动注册为团队成员
- 成员角色体系:
lead(负责人)、member(成员)、guest(访客) - 团队名称唯一性约束(同一组织内不允许重名)
- 删除保护机制(存在子团队时禁止删除)
- 与权限引擎(Permission Engine)、企业审计(Audit)等模块深度集成
源码位置: desktop-app-vue/src/main/permission/team-manager.js
IPC 注册位置: desktop-app-vue/src/main/permission/permission-ipc.js
核心功能
团队创建与管理
创建团队
通过 createTeam(teamData) 方法创建新团队。系统会自动生成 UUID 作为团队 ID,并记录创建时间戳。如果指定了团队负责人(leadDid),系统会自动将其添加为团队成员,角色设置为 lead。
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
orgId | String | 是 | 所属组织 ID |
name | String | 是 | 团队名称(同一组织内唯一) |
description | String | 否 | 团队描述 |
parentTeamId | String | 否 | 父团队 ID(用于构建层级结构) |
leadDid | String | 否 | 团队负责人 DID |
leadName | String | 否 | 团队负责人名称 |
avatar | String | 否 | 团队头像 |
settings | Object | 否 | 团队自定义设置(JSON 序列化存储) |
createdBy | String | 否 | 创建者标识(用于记录邀请人) |
返回值:
- 成功:
{ success: true, teamId: '<uuid>' } - 团队名重复:
{ success: false, error: 'TEAM_NAME_EXISTS' }
更新团队
通过 updateTeam(teamId, updates) 方法更新团队信息。系统会自动将 camelCase 字段名转换为 snake_case 数据库字段名,并过滤非法字段。
允许更新的字段:
name- 团队名称description- 团队描述parentTeamId- 父团队 IDleadDid- 负责人 DIDleadName- 负责人名称avatar- 团队头像settings- 团队设置(Object,自动 JSON 序列化)
返回值: { success: true }
删除团队
通过 deleteTeam(teamId) 方法删除团队。系统内置删除保护机制:如果团队下存在子团队,将拒绝删除并返回错误信息。
返回值:
- 成功:
{ success: true } - 存在子团队:
{ success: false, error: 'HAS_SUB_TEAMS', message: 'Team has N sub-teams. Delete them first.' }
设置团队负责人
通过 setLead(teamId, leadDid, leadName) 方法设置或变更团队负责人。该方法会同时完成以下操作:
- 更新
org_teams表中的lead_did和lead_name字段 - 将原负责人的成员角色降级为
member - 将新负责人的成员角色升级为
lead
返回值: { success: true }
成员管理
添加成员
通过 addMember(teamId, memberDid, memberName, role, invitedBy) 方法向团队添加成员。
参数说明:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
teamId | String | 是 | - | 目标团队 ID |
memberDid | String | 是 | - | 成员 DID 标识 |
memberName | String | 是 | - | 成员名称 |
role | String | 否 | 'member' | 成员角色:lead / member / guest |
invitedBy | String | 否 | null | 邀请人标识 |
返回值:
- 成功:
{ success: true, memberId: '<uuid>' } - 已是成员:
{ success: false, error: 'ALREADY_MEMBER' }
移除成员
通过 removeMember(teamId, memberDid) 方法从团队中移除指定成员。
返回值: { success: true }
查询团队成员
通过 getTeamMembers(teamId) 方法获取指定团队的所有成员列表。结果按角色降序排列(负责人在前),同角色按加入时间升序排列。
返回值:
{
success: true,
members: [
{
id: '<member-record-uuid>',
memberDid: 'did:example:alice',
memberName: 'Alice',
role: 'lead',
joinedAt: 1708900000000,
invitedBy: 'did:example:admin'
},
// ...
]
}层级结构(团队树)
查询团队列表
通过 getTeams(orgId, options) 方法获取组织下的团队列表。支持按父团队 ID 过滤,可用于逐层构建团队树形结构。
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
orgId | String | 是 | 组织 ID |
options.parentTeamId | String/null | 否 | 父团队 ID。传 null 获取顶级团队,传具体 ID 获取子团队,不传则获取所有团队 |
返回值:
{
success: true,
teams: [
{
id: '<team-uuid>',
name: '研发部',
description: '负责产品研发',
parentTeamId: null,
leadDid: 'did:example:lead1',
leadName: '张三',
avatar: null,
settings: { maxMembers: 50 },
memberCount: 12,
createdAt: 1708900000000,
updatedAt: 1708900000000
},
// ...
]
}构建团队层级树
虽然 TeamManager 本身不提供递归树构建方法,但可以通过 getTeams 的 parentTeamId 过滤参数逐层查询来构建完整的团队层级树:
// 获取顶级团队
const topLevel = await teamManager.getTeams(orgId, { parentTeamId: null });
// 递归获取子团队
async function buildTree(teams) {
for (const team of teams) {
const children = await teamManager.getTeams(orgId, {
parentTeamId: team.id,
});
team.children = children.teams;
if (team.children.length > 0) {
await buildTree(team.children);
}
}
}
await buildTree(topLevel.teams);配置参考
团队管理模块通过数据库进行数据持久化,无需额外配置文件。模块采用单例模式初始化:
const { getTeamManager } = require("./permission/team-manager");
// 传入 database 实例初始化(仅首次需要)
const manager = getTeamManager(database);
// 后续调用无需再传 database
const manager = getTeamManager();团队的自定义配置通过 settings 字段以 JSON 格式存储在数据库中,可用于存储团队级别的个性化设置,例如:
{
"maxMembers": 50,
"allowGuestAccess": true,
"notificationPreferences": {
"email": true,
"inApp": true
}
}API 参考
TeamManager 类方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
createTeam(teamData) | { orgId, name, description?, parentTeamId?, leadDid?, leadName?, avatar?, settings?, createdBy? } | { success, teamId } 或 { success: false, error: 'TEAM_NAME_EXISTS' } | 创建团队,自动添加负责人为成员 |
updateTeam(teamId, updates) | teamId: string, updates: object | { success: true } | 更新团队信息,自动 camelCase 转 snake_case |
deleteTeam(teamId) | teamId: string | { success } 或 { success: false, error: 'HAS_SUB_TEAMS' } | 删除团队(有子团队时拒绝) |
setLead(teamId, leadDid, leadName) | teamId: string, leadDid: string, leadName: string | { success: true } | 设置团队负责人并更新成员角色 |
addMember(teamId, did, name, role?, invitedBy?) | teamId: string, did: string, name: string, role?: string, invitedBy?: string | { success, memberId } 或 { success: false, error: 'ALREADY_MEMBER' } | 添加团队成员 |
removeMember(teamId, did) | teamId: string, did: string | { success: true } | 移除团队成员 |
getTeams(orgId, options?) | orgId: string, options?: { parentTeamId? } | { success, teams: [...] } | 查询团队列表,附带成员数量 |
getTeamMembers(teamId) | teamId: string | { success, members: [...] } | 查询团队成员列表 |
工厂函数
| 函数 | 参数 | 说明 |
|---|---|---|
getTeamManager(database?) | database?: Database | 获取 TeamManager 单例。首次调用需传入 database 实例 |
IPC 接口
团队管理模块通过 permission-ipc.js 注册了 8 个 IPC 通道,供渲染进程调用:
| IPC 通道 | 参数 | 说明 |
|---|---|---|
team:create-team | { orgId, name, description?, parentTeamId?, leadDid?, leadName?, avatar?, settings?, createdBy? } | 创建团队 |
team:update-team | { teamId, updates: { name?, description?, parentTeamId?, leadDid?, leadName?, avatar?, settings? } } | 更新团队 |
team:delete-team | { teamId } | 删除团队 |
team:add-member | { teamId, memberDid, memberName, role?, invitedBy? } | 添加成员 |
team:remove-member | { teamId, memberDid } | 移除成员 |
team:set-lead | { teamId, leadDid, leadName } | 设置团队负责人 |
team:get-teams | { orgId, options?: { parentTeamId? } } | 查询团队列表 |
team:get-team-members | { teamId } | 查询团队成员 |
渲染进程调用示例:
// 创建团队
const result = await window.electronAPI.invoke("team:create-team", {
orgId: "org-001",
name: "前端开发组",
description: "负责 Web 前端开发",
leadDid: "did:example:alice",
leadName: "Alice",
});
// 查询团队列表
const teams = await window.electronAPI.invoke("team:get-teams", {
orgId: "org-001",
options: { parentTeamId: null },
});数据库 Schema
org_teams 表
存储团队基本信息,支持通过 parent_team_id 自引用构建层级结构。
CREATE TABLE IF NOT EXISTS org_teams (
id TEXT PRIMARY KEY,
org_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
parent_team_id TEXT,
lead_did TEXT,
lead_name TEXT,
avatar TEXT,
settings TEXT, -- JSON 格式的自定义设置
team_type TEXT DEFAULT 'team', -- Phase 6 新增:团队类型(team/department)
created_at INTEGER NOT NULL, -- 时间戳(毫秒)
updated_at INTEGER NOT NULL, -- 时间戳(毫秒)
FOREIGN KEY (parent_team_id) REFERENCES org_teams(id) ON DELETE CASCADE,
UNIQUE(org_id, name) -- 同一组织内团队名称唯一
);org_team_members 表
存储团队成员关系,支持角色划分。
CREATE TABLE IF NOT EXISTS org_team_members (
id TEXT PRIMARY KEY,
team_id TEXT NOT NULL,
member_did TEXT NOT NULL,
member_name TEXT,
team_role TEXT DEFAULT 'member' CHECK(team_role IN ('lead', 'member', 'guest')),
joined_at INTEGER NOT NULL, -- 加入时间戳(毫秒)
invited_by TEXT, -- 邀请人标识
FOREIGN KEY (team_id) REFERENCES org_teams(id) ON DELETE CASCADE,
UNIQUE(team_id, member_did) -- 同一团队内成员唯一
);索引
CREATE INDEX IF NOT EXISTS idx_org_teams_org ON org_teams(org_id);
CREATE INDEX IF NOT EXISTS idx_org_teams_parent ON org_teams(parent_team_id);
CREATE INDEX IF NOT EXISTS idx_org_teams_lead ON org_teams(lead_did);
CREATE INDEX IF NOT EXISTS idx_org_team_members_team ON org_team_members(team_id);
CREATE INDEX IF NOT EXISTS idx_org_team_members_member ON org_team_members(member_did);使用示例
创建组织团队结构
const { getTeamManager } = require("./permission/team-manager");
const manager = getTeamManager(database);
// 1. 创建顶级团队(研发中心)
const devCenter = await manager.createTeam({
orgId: "org-001",
name: "研发中心",
description: "负责全部产品研发工作",
leadDid: "did:example:cto",
leadName: "王总监",
createdBy: "did:example:admin",
});
// => { success: true, teamId: 'abc-123-...' }
// 2. 创建子团队(前端组)
const frontendTeam = await manager.createTeam({
orgId: "org-001",
name: "前端开发组",
description: "Web & 移动端前端开发",
parentTeamId: devCenter.teamId,
leadDid: "did:example:fe-lead",
leadName: "李组长",
settings: { techStack: ["Vue3", "React", "TypeScript"] },
});
// 3. 创建子团队(后端组)
const backendTeam = await manager.createTeam({
orgId: "org-001",
name: "后端开发组",
parentTeamId: devCenter.teamId,
leadDid: "did:example:be-lead",
leadName: "陈组长",
});管理团队成员
// 添加普通成员
await manager.addMember(
frontendTeam.teamId,
"did:example:dev1",
"张工程师",
"member",
"did:example:fe-lead",
);
// 添加访客(只读权限)
await manager.addMember(
frontendTeam.teamId,
"did:example:designer1",
"刘设计师",
"guest",
"did:example:fe-lead",
);
// 查询团队成员
const members = await manager.getTeamMembers(frontendTeam.teamId);
console.log(members);
// => { success: true, members: [
// { memberDid: 'did:example:fe-lead', memberName: '李组长', role: 'lead', ... },
// { memberDid: 'did:example:dev1', memberName: '张工程师', role: 'member', ... },
// { memberDid: 'did:example:designer1', memberName: '刘设计师', role: 'guest', ... }
// ]}
// 移除成员
await manager.removeMember(frontendTeam.teamId, "did:example:designer1");变更团队负责人
// 将团队负责人从李组长变更为张工程师
await manager.setLead(frontendTeam.teamId, "did:example:dev1", "张工程师");
// 此操作会自动将李组长的角色降级为 member,张工程师的角色升级为 lead查询团队层级
// 获取所有顶级团队
const topTeams = await manager.getTeams("org-001", { parentTeamId: null });
// 获取研发中心下的子团队
const subTeams = await manager.getTeams("org-001", {
parentTeamId: devCenter.teamId,
});
// 获取组织下所有团队(不过滤层级)
const allTeams = await manager.getTeams("org-001");处理错误场景
// 创建重名团队
const duplicate = await manager.createTeam({
orgId: "org-001",
name: "前端开发组", // 已存在
leadDid: "did:example:someone",
});
// => { success: false, error: 'TEAM_NAME_EXISTS' }
// 删除含有子团队的团队
const deleteResult = await manager.deleteTeam(devCenter.teamId);
// => { success: false, error: 'HAS_SUB_TEAMS', message: 'Team has 2 sub-teams. Delete them first.' }
// 重复添加成员
const addResult = await manager.addMember(
frontendTeam.teamId,
"did:example:dev1",
"张工程师",
);
// => { success: false, error: 'ALREADY_MEMBER' }故障排除
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
TEAM_NAME_EXISTS | 同一组织内已存在同名团队 | 使用不同的团队名称,或先删除已有同名团队 |
HAS_SUB_TEAMS | 尝试删除的团队下还有子团队 | 先递归删除所有子团队,再删除父团队 |
ALREADY_MEMBER | 成员已在该团队中 | 无需重复添加,如需变更角色请使用 setLead 方法 |
| 团队列表为空 | orgId 不匹配或尚未创建团队 | 检查传入的 orgId 是否正确 |
settings 字段为 null | 创建时未传入 settings 参数 | 通过 updateTeam 方法补充设置 |
| 更新字段未生效 | 字段名不在允许列表中 | 检查字段名是否正确,仅支持 7 个可更新字段 |
调试日志
团队管理模块的日志标签为 [Team],可通过日志系统查看操作记录:
[Team] Created team abc-123-...
[Team] Added member did:example:dev1 to team abc-123-...
[Team] Removed member did:example:dev1 from team abc-123-...
[Team] Set lead did:example:dev1 for team abc-123-...
[Team] Deleted team abc-123-...数据一致性注意事项
- 删除团队时,
org_team_members表中的关联成员记录会通过外键ON DELETE CASCADE自动删除 setLead方法会同时更新org_teams表和org_team_members表,确保数据一致createTeam中自动添加负责人为成员的操作不在事务中,如果添加成员失败,团队已创建但负责人未加入成员列表
故障排查
常见问题
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 成员权限不同步 | 权限缓存未刷新或角色变更未传播 | 执行 org cache-flush,确认角色变更已保存 |
| 任务分配冲突 | 多人同时分配同一任务或锁机制失效 | 启用任务分配锁 team task-lock-enable,刷新任务列表 |
| 团队配额超限 | 成员数超出计划限制或存储配额用尽 | 查看配额使用 org quota-status,升级团队计划 |
| 邀请链接失效 | 链接过期或使用次数已达上限 | 重新生成邀请链接 org invite --regenerate |
| 成员离开后数据未迁移 | 数据所有权未转移 | 执行 team data-transfer --from <user> --to <user> |
常见错误修复
错误: PERMISSION_OUT_OF_SYNC 权限不同步
# 强制刷新权限缓存
chainlesschain org cache-flush --scope permissions
# 验证成员权限
chainlesschain auth check <user> "team:manage"错误: TASK_ASSIGNMENT_CONFLICT 任务分配冲突
# 查看任务分配状态
chainlesschain team task-status --task-id <id>
# 强制重新分配
chainlesschain team task-assign --task-id <id> --user <user> --force错误: TEAM_QUOTA_EXCEEDED 团队配额超限
# 查看配额使用详情
chainlesschain org quota-status --team-id <id>
# 清理非活跃成员释放配额
chainlesschain team prune-inactive --days 90性能指标
| 指标 | 目标 | 实际 | 说明 |
|---|---|---|---|
createTeam 响应时间 | <50ms | ~15ms | 含负责人自动注册为成员 |
addMember 响应时间 | <30ms | ~10ms | 单次插入,含唯一性检查 |
getTeams 响应时间 | <100ms | ~25ms | 含成员数量聚合查询,百团队级别 |
getTeamMembers 响应时间 | <50ms | ~12ms | 含角色排序,百成员级别 |
setLead 响应时间 | <80ms | ~20ms | 含两次 UPDATE(teams + members 表) |
deleteTeam 响应时间 | <50ms | ~15ms | 含子团队存在性检查 |
| 层级树构建(10 层) | <500ms | ~200ms | 递归 getTeams 逐层查询,已有索引加速 |
| SQLite WAL 并发写 | <30ms | ~8ms | 多写请求并发时通过 busy_timeout 自动重试 |
测量环境:本地 SQLite WAL 模式,1000 团队 / 5000 成员数据集,Intel i7 / 16GB RAM。
测试覆盖率
测试文件
| 文件 | 类型 | 用例数 | 说明 |
|---|---|---|---|
tests/unit/permission/team-manager.test.js | 单元测试 | 42 | 核心 CRUD、角色变更、错误路径 |
tests/unit/permission/team-manager-hierarchy.test.js | 单元测试 | 18 | 多级层次结构、递归删除场景 |
tests/integration/permission/team-ipc.test.js | 集成测试 | 16 | 8 个 IPC 通道端到端调用 |
tests/unit/permission/team-manager-edge-cases.test.js | 单元测试 | 12 | 边界条件、并发写入、事务一致性 |
总计: 88 个测试用例,覆盖率 ~94%
关键测试场景
// 1. 创建团队并自动注册负责人
it('should auto-register leadDid as lead member', async () => {
const { teamId } = await manager.createTeam({
orgId: 'org-001', name: '测试团队',
leadDid: 'did:example:lead', leadName: 'Alice',
});
const { members } = await manager.getTeamMembers(teamId);
expect(members[0]).toMatchObject({ memberDid: 'did:example:lead', role: 'lead' });
});
// 2. 删除含子团队时的保护机制
it('should reject deleteTeam when sub-teams exist', async () => {
const parent = await manager.createTeam({ orgId: 'org-001', name: '父团队' });
await manager.createTeam({ orgId: 'org-001', name: '子团队', parentTeamId: parent.teamId });
const result = await manager.deleteTeam(parent.teamId);
expect(result).toEqual({ success: false, error: 'HAS_SUB_TEAMS' });
});
// 3. setLead 角色自动升降级
it('should downgrade old lead and upgrade new lead', async () => {
const { teamId } = await manager.createTeam({
orgId: 'org-001', name: '变更团队',
leadDid: 'did:example:old-lead', leadName: 'OldLead',
});
await manager.addMember(teamId, 'did:example:new-lead', 'NewLead', 'member');
await manager.setLead(teamId, 'did:example:new-lead', 'NewLead');
const { members } = await manager.getTeamMembers(teamId);
const oldLead = members.find(m => m.memberDid === 'did:example:old-lead');
const newLead = members.find(m => m.memberDid === 'did:example:new-lead');
expect(oldLead.role).toBe('member');
expect(newLead.role).toBe('lead');
});
// 4. 同组织内团队重名校验
it('should return TEAM_NAME_EXISTS for duplicate name in same org', async () => {
await manager.createTeam({ orgId: 'org-001', name: '研发部' });
const result = await manager.createTeam({ orgId: 'org-001', name: '研发部' });
expect(result).toEqual({ success: false, error: 'TEAM_NAME_EXISTS' });
});运行测试
# 全量团队管理测试
cd desktop-app-vue && npx vitest run tests/unit/permission/team-manager
# 含 IPC 集成测试
cd desktop-app-vue && npx vitest run tests/unit/permission/ tests/integration/permission/
# 仅层级结构测试
cd desktop-app-vue && npx vitest run tests/unit/permission/team-manager-hierarchy安全考虑
数据完整性
- 删除团队时,子团队成员记录通过外键
ON DELETE CASCADE自动级联删除 - 团队名称在同一组织内强制唯一,防止命名混淆导致的权限错配
setLead方法原子性地完成负责人变更和角色升降级,保证数据一致性
权限控制
- 团队操作受 RBAC 权限引擎保护,仅组织管理员和部门主管可执行管理操作
- 成员角色分级(lead/member/guest)控制不同级别的访问权限
- 团队权限自动继承到团队成员,成员离开团队后权限立即失效
审计追踪
- 所有团队创建、删除、成员变更操作自动记录在企业审计日志中
- 审计日志标签
[Team]记录操作详情,支持按操作者和时间范围查询 - 负责人变更等高风险操作可配置为需要审批工作流确认
防滥用机制
- 删除保护机制阻止删除含有子团队的团队,防止误操作导致数据丢失
- 重复添加成员返回
ALREADY_MEMBER错误,避免数据冗余 - 团队设置(
settings)以 JSON 格式存储,应用层应校验设置内容合法性
故障深度排查
成员权限异常
- 角色检查: 使用
team:get-team-members确认成员当前角色(lead/member/guest),权限与角色直接关联 - 权限继承: 团队权限自动继承到成员,若上级团队权限变更需确认子团队成员权限是否同步更新
- 角色降级未生效:
setLead变更负责人时自动降级原负责人为member,若降级未生效检查org_team_members表中该成员记录 - 跨团队权限: 成员同时属于多个团队时权限取并集,使用
auth:check验证具体权限是否生效
任务分配失败
| 现象 | 排查步骤 |
|---|---|
| 分配任务时提示无权限 | 确认当前操作者角色为 lead 或组织管理员;guest 角色无任务分配权限 |
| 团队成员列表为空 | 检查 orgId 是否正确;确认 addMember 调用时未返回 ALREADY_MEMBER 错误 |
| 子团队成员看不到父团队任务 | 团队层级不自动共享任务,需在父团队中显式添加子团队成员或配置跨团队可见性 |
安全深度说明
权限隔离
- 不同团队的数据通过
team_id严格隔离,跨团队数据访问需要显式授权 guest角色仅拥有只读权限,无法修改团队数据或邀请新成员- 团队负责人变更(
setLead)同时更新org_teams和org_team_members两张表,确保权限一致性
审计追踪
- 所有团队操作(创建/删除/成员变更/负责人变更)自动记录到企业审计日志,日志标签为
[Team] - 审计日志支持按操作者 DID、时间范围、操作类型(如
member:add/member:remove)过滤查询 - 高风险操作(如删除团队、移除负责人)可在
settings中配置为需要审批工作流确认后才执行
相关文档
关键文件
| 文件 | 职责 | 行数 |
|---|---|---|
src/main/permission/team-manager.js | 团队管理核心逻辑(单例模式) | ~300 |
src/main/permission/permission-ipc.js | IPC 通道注册与路由 | ~200 |
src/main/permission/permission-engine.js | RBAC 权限引擎(团队角色联动) | ~450 |
src/renderer/stores/team.ts | 团队 Pinia 状态管理 | ~150 |
