|
|
@@ -0,0 +1,399 @@
|
|
|
+# CRM系统用户权限体系改进方案
|
|
|
+
|
|
|
+## 当前状态分析
|
|
|
+
|
|
|
+### 已实现功能
|
|
|
+- ✅ **用户管理**: 完整的用户CRUD功能
|
|
|
+- ✅ **角色管理**: 基于角色的权限控制(RBAC)
|
|
|
+- ✅ **权限控制**: 通过权限字符串控制菜单和API访问
|
|
|
+- ✅ **客户数据权限**: 基于负责人ID的数据隔离
|
|
|
+- ✅ **区域管理**: 支持省市区三级区域划分
|
|
|
+
|
|
|
+### 缺失功能
|
|
|
+- ❌ **部门管理**: 无部门组织架构
|
|
|
+- ❌ **数据范围控制**: 无法按部门、团队范围管理数据
|
|
|
+- ❌ **权限粒度**: 仅支持模块级权限,缺少操作级权限
|
|
|
+- ❌ **用户组管理**: 无法批量管理用户权限
|
|
|
+- ❌ **数据继承**: 上级部门无法查看下级部门数据
|
|
|
+
|
|
|
+## 改进目标
|
|
|
+
|
|
|
+### 1. 建立完整的组织架构
|
|
|
+- 实现多层级部门管理
|
|
|
+- 支持部门负责人制度
|
|
|
+- 提供部门间数据共享机制
|
|
|
+
|
|
|
+### 2. 精细化权限控制
|
|
|
+- 实现操作级权限控制
|
|
|
+- 支持数据范围权限(个人/部门/公司)
|
|
|
+- 提供灵活的权限继承机制
|
|
|
+
|
|
|
+### 3. 增强数据管理能力
|
|
|
+- 支持基于部门的数据隔离
|
|
|
+- 实现数据权限继承
|
|
|
+- 提供数据分享和转移功能
|
|
|
+
|
|
|
+## 详细改进方案
|
|
|
+
|
|
|
+### 阶段一:部门体系重构
|
|
|
+
|
|
|
+#### 1.1 数据库结构优化
|
|
|
+
|
|
|
+```sql
|
|
|
+-- 部门表
|
|
|
+CREATE TABLE department (
|
|
|
+ id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '部门ID',
|
|
|
+ name VARCHAR(100) NOT NULL COMMENT '部门名称',
|
|
|
+ code VARCHAR(50) UNIQUE COMMENT '部门编码',
|
|
|
+ parent_id INT UNSIGNED COMMENT '父部门ID',
|
|
|
+ manager_id INT UNSIGNED COMMENT '部门负责人ID',
|
|
|
+ description TEXT COMMENT '部门描述',
|
|
|
+ sort_order INT DEFAULT 0 COMMENT '排序',
|
|
|
+ is_active TINYINT DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_parent_id (parent_id),
|
|
|
+ INDEX idx_manager_id (manager_id),
|
|
|
+ INDEX idx_code (code),
|
|
|
+ CONSTRAINT fk_department_parent FOREIGN KEY (parent_id) REFERENCES department(id),
|
|
|
+ CONSTRAINT fk_department_manager FOREIGN KEY (manager_id) REFERENCES users(id)
|
|
|
+) COMMENT = '组织架构部门表';
|
|
|
+
|
|
|
+-- 用户部门关联表
|
|
|
+CREATE TABLE user_department (
|
|
|
+ id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ user_id INT UNSIGNED NOT NULL,
|
|
|
+ department_id INT UNSIGNED NOT NULL,
|
|
|
+ position VARCHAR(100) COMMENT '职位',
|
|
|
+ is_primary TINYINT DEFAULT 1 COMMENT '是否主部门(0:兼职,1:主部门)',
|
|
|
+ join_date DATE COMMENT '入职日期',
|
|
|
+ leave_date DATE COMMENT '离职日期',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ UNIQUE KEY uk_user_department (user_id, department_id),
|
|
|
+ INDEX idx_department_id (department_id),
|
|
|
+ CONSTRAINT fk_user_dept_user FOREIGN KEY (user_id) REFERENCES users(id),
|
|
|
+ CONSTRAINT fk_user_dept_department FOREIGN KEY (department_id) REFERENCES department(id)
|
|
|
+) COMMENT = '用户部门关联表';
|
|
|
+
|
|
|
+-- 数据范围配置表
|
|
|
+CREATE TABLE data_scope (
|
|
|
+ id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ name VARCHAR(100) NOT NULL COMMENT '范围名称',
|
|
|
+ type ENUM('PERSONAL', 'DEPARTMENT', 'COMPANY', 'CUSTOM') NOT NULL COMMENT '范围类型',
|
|
|
+ description TEXT COMMENT '范围描述',
|
|
|
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
|
+) COMMENT = '数据范围配置表';
|
|
|
+```
|
|
|
+
|
|
|
+#### 1.2 用户实体扩展
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 更新用户实体
|
|
|
+@Entity({ name: 'users' })
|
|
|
+export class UserEntity {
|
|
|
+ // ... 现有字段
|
|
|
+
|
|
|
+ @ManyToMany(() => Department)
|
|
|
+ @JoinTable({ name: 'user_department' })
|
|
|
+ departments!: Department[];
|
|
|
+
|
|
|
+ @Column({ name: 'default_department_id', type: 'int', nullable: true })
|
|
|
+ defaultDepartmentId?: number;
|
|
|
+
|
|
|
+ @Column({ name: 'data_scope_type', type: 'enum', enum: DataScopeType, default: DataScopeType.PERSONAL })
|
|
|
+ dataScopeType!: DataScopeType;
|
|
|
+}
|
|
|
+
|
|
|
+// 新增部门实体
|
|
|
+@Entity({ name: 'department' })
|
|
|
+export class Department {
|
|
|
+ @PrimaryGeneratedColumn({ unsigned: true })
|
|
|
+ id!: number;
|
|
|
+
|
|
|
+ @Column({ type: 'varchar', length: 100 })
|
|
|
+ name!: string;
|
|
|
+
|
|
|
+ @Column({ type: 'varchar', length: 50, unique: true })
|
|
|
+ code!: string;
|
|
|
+
|
|
|
+ @ManyToOne(() => Department, dept => dept.children)
|
|
|
+ @JoinColumn({ name: 'parent_id' })
|
|
|
+ parent?: Department;
|
|
|
+
|
|
|
+ @OneToMany(() => Department, dept => dept.parent)
|
|
|
+ children!: Department[];
|
|
|
+
|
|
|
+ @ManyToOne(() => UserEntity)
|
|
|
+ @JoinColumn({ name: 'manager_id' })
|
|
|
+ manager?: UserEntity;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 阶段二:权限体系升级
|
|
|
+
|
|
|
+#### 2.1 权限模型重构
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 权限类型定义
|
|
|
+export enum PermissionType {
|
|
|
+ MODULE = 'module', // 模块权限
|
|
|
+ OPERATION = 'operation', // 操作权限
|
|
|
+ DATA = 'data' // 数据权限
|
|
|
+}
|
|
|
+
|
|
|
+export enum DataScopeType {
|
|
|
+ PERSONAL = 'personal', // 仅个人数据
|
|
|
+ DEPARTMENT = 'department', // 部门数据
|
|
|
+ SUB_DEPARTMENT = 'sub_department', // 部门及下级数据
|
|
|
+ COMPANY = 'company', // 全公司数据
|
|
|
+ CUSTOM = 'custom' // 自定义范围
|
|
|
+}
|
|
|
+
|
|
|
+// 新权限实体
|
|
|
+@Entity({ name: 'permission' })
|
|
|
+export class Permission {
|
|
|
+ @PrimaryGeneratedColumn()
|
|
|
+ id!: number;
|
|
|
+
|
|
|
+ @Column({ type: 'varchar', length: 100 })
|
|
|
+ code!: string; // 如: client:create, client:view:all
|
|
|
+
|
|
|
+ @Column({ type: 'varchar', length: 100 })
|
|
|
+ name!: string;
|
|
|
+
|
|
|
+ @Column({ type: 'enum', enum: PermissionType })
|
|
|
+ type!: PermissionType;
|
|
|
+
|
|
|
+ @Column({ type: 'json', nullable: true })
|
|
|
+ config?: any; // 权限配置
|
|
|
+}
|
|
|
+
|
|
|
+// 角色权限关联
|
|
|
+@Entity({ name: 'role_permission' })
|
|
|
+export class RolePermission {
|
|
|
+ @PrimaryGeneratedColumn()
|
|
|
+ id!: number;
|
|
|
+
|
|
|
+ @ManyToOne(() => Role)
|
|
|
+ role!: Role;
|
|
|
+
|
|
|
+ @ManyToOne(() => Permission)
|
|
|
+ permission!: Permission;
|
|
|
+
|
|
|
+ @Column({ type: 'json', nullable: true })
|
|
|
+ dataScope?: any; // 数据范围配置
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 2.2 细粒度权限控制
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 权限配置示例
|
|
|
+const PERMISSIONS = {
|
|
|
+ // 客户管理权限
|
|
|
+ CLIENT: {
|
|
|
+ CREATE: 'client:create',
|
|
|
+ UPDATE: 'client:update',
|
|
|
+ DELETE: 'client:delete',
|
|
|
+ VIEW: {
|
|
|
+ OWN: 'client:view:own',
|
|
|
+ DEPARTMENT: 'client:view:department',
|
|
|
+ ALL: 'client:view:all'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 合同管理权限
|
|
|
+ CONTRACT: {
|
|
|
+ CREATE: 'contract:create',
|
|
|
+ UPDATE: 'contract:update',
|
|
|
+ DELETE: 'contract:delete',
|
|
|
+ VIEW: {
|
|
|
+ OWN: 'contract:view:own',
|
|
|
+ DEPARTMENT: 'contract:view:department',
|
|
|
+ ALL: 'contract:view:all'
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+### 阶段三:数据权限实现
|
|
|
+
|
|
|
+#### 3.1 数据权限过滤器
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 数据权限服务
|
|
|
+export class DataPermissionService {
|
|
|
+ constructor(private dataSource: DataSource) {}
|
|
|
+
|
|
|
+ async applyDataScope(
|
|
|
+ queryBuilder: SelectQueryBuilder<any>,
|
|
|
+ entity: string,
|
|
|
+ user: UserEntity,
|
|
|
+ action: string
|
|
|
+ ): Promise<SelectQueryBuilder<any>> {
|
|
|
+ const dataScope = await this.getUserDataScope(user, entity, action);
|
|
|
+
|
|
|
+ switch (dataScope.type) {
|
|
|
+ case DataScopeType.PERSONAL:
|
|
|
+ queryBuilder.andWhere(`${entity}.responsible_user_id = :userId`, { userId: user.id });
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DataScopeType.DEPARTMENT:
|
|
|
+ const departmentIds = await this.getDepartmentIds(user);
|
|
|
+ queryBuilder.andWhere(`${entity}.department_id IN (:...departmentIds)`, { departmentIds });
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DataScopeType.SUB_DEPARTMENT:
|
|
|
+ const allDepartmentIds = await this.getSubDepartmentIds(user);
|
|
|
+ queryBuilder.andWhere(`${entity}.department_id IN (:...allDepartmentIds)`, { allDepartmentIds });
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return queryBuilder;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.2 通用CRUD集成
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 更新GenericCrudService以支持数据权限
|
|
|
+export class GenericCrudService<T> {
|
|
|
+ async getList(
|
|
|
+ page: number = 1,
|
|
|
+ pageSize: number = 10,
|
|
|
+ keyword?: string,
|
|
|
+ searchFields?: string[],
|
|
|
+ where?: Partial<T>,
|
|
|
+ relations: string[] = [],
|
|
|
+ order: any = {},
|
|
|
+ filters?: any,
|
|
|
+ user?: UserEntity
|
|
|
+ ): Promise<[T[], number]> {
|
|
|
+ const queryBuilder = this.createQueryBuilder();
|
|
|
+
|
|
|
+ // 应用数据权限
|
|
|
+ if (user) {
|
|
|
+ await this.dataPermissionService.applyDataScope(
|
|
|
+ queryBuilder,
|
|
|
+ this.entity.name,
|
|
|
+ user,
|
|
|
+ 'view'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // ... 其他查询逻辑
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 阶段四:前端权限控制
|
|
|
+
|
|
|
+#### 4.1 权限配置组件
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 权限配置组件
|
|
|
+interface PermissionConfigProps {
|
|
|
+ roleId: number;
|
|
|
+ onChange: (permissions: Permission[]) => void;
|
|
|
+}
|
|
|
+
|
|
|
+const PermissionConfig: React.FC<PermissionConfigProps> = ({ roleId, onChange }) => {
|
|
|
+ const { data: permissions } = useQuery(['permissions'], fetchPermissions);
|
|
|
+ const { data: rolePermissions } = useQuery(['role-permissions', roleId], () =>
|
|
|
+ fetchRolePermissions(roleId)
|
|
|
+ );
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <Card title="模块权限">
|
|
|
+ <Checkbox.Group
|
|
|
+ options={permissions?.filter(p => p.type === 'module')}
|
|
|
+ value={rolePermissions?.map(p => p.id)}
|
|
|
+ onChange={onChange}
|
|
|
+ />
|
|
|
+ </Card>
|
|
|
+
|
|
|
+ <Card title="数据权限">
|
|
|
+ <Radio.Group>
|
|
|
+ <Radio value="personal">个人数据</Radio>
|
|
|
+ <Radio value="department">部门数据</Radio>
|
|
|
+ <Radio value="sub_department">部门及下级</Radio>
|
|
|
+ <Radio value="company">全公司数据</Radio>
|
|
|
+ </Radio.Group>
|
|
|
+ </Card>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+#### 4.2 动态菜单权限
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 更新菜单配置
|
|
|
+const menuItems = [
|
|
|
+ {
|
|
|
+ key: 'clients',
|
|
|
+ label: '客户管理',
|
|
|
+ path: '/admin/clients',
|
|
|
+ permissions: ['client:view'],
|
|
|
+ dataScope: 'own' // 根据用户权限动态显示
|
|
|
+ }
|
|
|
+];
|
|
|
+```
|
|
|
+
|
|
|
+### 实施计划
|
|
|
+
|
|
|
+| 阶段 | 任务 | 预计工时 | 优先级 |
|
|
|
+|------|------|----------|--------|
|
|
|
+| 1 | 数据库结构升级 | 2天 | 高 |
|
|
|
+| 2 | 部门管理功能 | 3天 | 高 |
|
|
|
+| 3 | 权限模型重构 | 3天 | 中 |
|
|
|
+| 4 | 数据权限集成 | 4天 | 高 |
|
|
|
+| 5 | 前端权限控制 | 2天 | 中 |
|
|
|
+| 6 | 测试和优化 | 2天 | 低 |
|
|
|
+
|
|
|
+### 迁移方案
|
|
|
+
|
|
|
+#### 数据迁移
|
|
|
+1. **用户数据**: 保持现有用户表不变,增量升级
|
|
|
+2. **权限数据**: 将现有权限字符串映射到新权限体系
|
|
|
+3. **角色数据**: 保留现有角色,增加数据范围配置
|
|
|
+
|
|
|
+#### 代码迁移
|
|
|
+1. **向后兼容**: 现有权限检查逻辑保持兼容
|
|
|
+2. **渐进升级**: 分模块逐步切换到新权限体系
|
|
|
+3. **回滚方案**: 保留原始数据结构备份
|
|
|
+
|
|
|
+### 测试验证
|
|
|
+
|
|
|
+#### 测试用例
|
|
|
+1. **部门管理测试**:
|
|
|
+ - 部门CRUD操作
|
|
|
+ - 部门层级关系
|
|
|
+ - 部门负责人指定
|
|
|
+
|
|
|
+2. **权限测试**:
|
|
|
+ - 不同角色的权限验证
|
|
|
+ - 数据范围权限验证
|
|
|
+ - 权限继承验证
|
|
|
+
|
|
|
+3. **业务测试**:
|
|
|
+ - 客户数据隔离验证
|
|
|
+ - 跨部门数据共享
|
|
|
+ - 数据权限转移
|
|
|
+
|
|
|
+### 预期效果
|
|
|
+
|
|
|
+#### 功能增强
|
|
|
+- ✅ 完整的组织架构管理
|
|
|
+- ✅ 精细化权限控制
|
|
|
+- ✅ 灵活的数据范围管理
|
|
|
+- ✅ 支持多级部门权限继承
|
|
|
+- ✅ 用户批量权限管理
|
|
|
+
|
|
|
+#### 业务价值
|
|
|
+- 提高数据安全性
|
|
|
+- 支持复杂组织架构
|
|
|
+- 减少权限管理成本
|
|
|
+- 增强系统扩展性
|