feat(types): 添加express.d.ts类型引用 style: 格式化express.d.ts中的接口定义 refactor: 移除未使用的AntFC类型导入 chore: 删除自动生成的.umi-production文件 feat: 添加店铺管理相关表和初始化脚本 docs: 更新安全规则和交互指南文档 refactor: 统一使用FC类型替代React.FC perf: 优化图表组件导入方式 style: 添加.prettierrc配置文件 refactor: 调整组件导入顺序和结构 feat: 添加平台库存管理路由 fix: 修复订单同步时的库存检查逻辑 docs: 更新RBAC设计和租户管理文档 refactor: 优化部门控制器代码
32 KiB
32 KiB
用户层级架构说明
文档版本: 1.2 最后更新: 2026-03-29 更新内容: 根据实际代码更新表名、字段定义、数据范围类型、服务方法签名、权限点设计,删除不存在的表和服务引用 适用范围: Crawlful Hub 多租户用户管理体系
1. 多租户层级结构
Crawlful Hub 采用多层级的用户架构设计,确保数据隔离和权限控制:
平台(Platform)
↓
商户/公司(Tenant/Organization)
↓
组织结构(Org Tree)
├── 部门A(主管)
│ ├── 组A1(组长)
│ │ ├── 员工1
│ │ └── 员工2
│ └── 组A2(组长)
│ └── 员工3
└── 部门B(主管)
└── ...
1.1 层级关系说明
| 层级 | 英文 | 描述 | 数据隔离级别 |
|---|---|---|---|
| 平台 | Platform | 系统运营方,管理所有租户 | 全局管理 |
| 租户 | Tenant | 企业/商户,拥有独立数据空间 | 完全隔离 |
| 部门 | Department | 租户内的组织结构 | 层级隔离 |
| 店铺 | Shop | 具体电商平台的店铺 | 业务隔离 |
| 用户 | User | 系统使用者 | 权限控制 |
2. 核心层级模型
2.1 层级关系详解
商户 (Merchant/Tenant)
- 定义: 最高业务层级,代表一个独立的企业或组织
- 属性: 商户ID、名称、认证状态、计费套餐、配额限制
- 管理: 由平台管理员创建,商户管理员管理
- 数据: 所有数据归属于特定租户,完全隔离
部门 (Department)
- 定义: 商户内的组织结构单元
- 属性: 部门ID、名称、父部门ID、层级路径(path)、深度(depth)
- 管理: 商户管理员创建和管理部门层级
- 特性: 支持多级嵌套,形成树形结构
店铺 (Shop)
- 定义: 具体的电商平台店铺(如Amazon、TikTok店铺)
- 属性: 店铺ID、平台类型、授权状态、所属部门
- 管理: 可分配给特定部门或用户组
- 隔离: 店铺间操作互不影响
用户 (User)
- 定义: 系统的实际使用者
- 属性: 用户ID、用户名、邮箱、角色、所属租户/部门
- 状态: active(活跃)、inactive(未激活)、suspended(暂停)、deleted(已删除)
2.2 数据隔离机制
租户隔离
-- 所有业务表必须包含 tenant_id 字段
SELECT * FROM cf_products WHERE tenant_id = 'tenant_xxx';
SELECT * FROM cf_orders WHERE tenant_id = 'tenant_xxx';
部门隔离
-- 通过部门路径实现层级数据访问
SELECT * FROM cf_user
WHERE tenant_id = 'tenant_xxx'
AND dept_path LIKE '/dept_a/%';
店铺隔离
-- 店铺级别数据过滤
SELECT * FROM cf_products
WHERE tenant_id = 'tenant_xxx'
AND shop_id = 'shop_xxx';
3. 权限系统(RBAC)
3.1 系统级角色定义
| 角色 | 英文 | 描述 | 权限范围 |
|---|---|---|---|
| ADMIN | 系统管理员 | 平台运营方 | 所有资源的所有操作 |
| MANAGER | 运营主管 | 租户内高级管理 | 租户内大部分资源的管理操作 |
| OPERATOR | 运营专员 | 日常运营人员 | 基础运营操作(商品、订单) |
| FINANCE | 财务主管 | 财务人员 | 财务相关操作(账单、结算) |
| SOURCING | 采购专家 | 采购人员 | 采购相关操作(供应商、选品) |
| LOGISTICS | 物流专家 | 物流人员 | 物流相关操作(发货、跟踪) |
| ANALYST | 数据分析师 | 数据分析人员 | 数据分析相关操作(报表、洞察) |
3.2 店铺级角色定义
| 角色 | 描述 | 权限范围 | 适用场景 |
|---|---|---|---|
| owner | 拥有者 | 删除店铺、管理授权、管理成员、所有权限 | 店铺创建者 |
| admin | 管理员 | 管理商品、管理价格、管理订单、不可删除店铺 | 店铺运营主管 |
| operator | 运营 | 刊登、改价、查看数据 | 日常运营人员 |
| viewer | 只读 | 查看数据、不可操作 | 仅查看报表人员 |
3.3 权限点设计
// 权限对象结构
export interface Permission {
id: string; // 权限ID,格式:资源:操作
name: string; // 权限名称
description: string; // 权限描述
module: string; // 所属模块
action: 'READ' | 'WRITE' | 'DELETE' | 'EXECUTE'; // 操作类型
}
// 权限点定义(按模块划分)
const PERMISSIONS: Permission[] = [
// 系统权限
{ id: 'admin:all', name: '超级管理员', description: '拥有所有系统权限', module: 'SYSTEM', action: 'EXECUTE' },
// 商品权限
{ id: 'product:read', name: '查看商品', description: '允许查看商品列表与详情', module: 'PRODUCT', action: 'READ' },
{ id: 'product:write', name: '编辑商品', description: '允许创建和修改商品信息', module: 'PRODUCT', action: 'WRITE' },
{ id: 'product:delete', name: '删除商品', description: '允许删除商品', module: 'PRODUCT', action: 'DELETE' },
{ id: 'product:publish', name: '发布商品', description: '允许执行商品刊登任务', module: 'PRODUCT', action: 'EXECUTE' },
{ id: 'product:score', name: '商品评分', description: '允许查看AI选品评分', module: 'PRODUCT', action: 'READ' },
// 订单权限
{ id: 'order:read', name: '查看订单', description: '允许查看销售订单', module: 'ORDER', action: 'READ' },
{ id: 'order:write', name: '创建订单', description: '允许创建订单', module: 'ORDER', action: 'WRITE' },
{ id: 'order:cancel', name: '取消订单', description: '允许取消订单', module: 'ORDER', action: 'EXECUTE' },
{ id: 'order:refund', name: '退款处理', description: '允许处理退款', module: 'ORDER', action: 'EXECUTE' },
// 库存权限
{ id: 'inventory:read', name: '查看库存', description: '允许查看库存数据', module: 'INVENTORY', action: 'READ' },
{ id: 'inventory:write', name: '编辑库存', description: '允许调整库存', module: 'INVENTORY', action: 'WRITE' },
{ id: 'inventory:sync', name: '库存同步', description: '允许执行跨平台库存同步', module: 'INVENTORY', action: 'EXECUTE' },
{ id: 'inventory:alert', name: '库存预警', description: '允许配置库存预警', module: 'INVENTORY', action: 'EXECUTE' },
// 财务权限
{ id: 'finance:read', name: '查看财务', description: '允许查看财务数据', module: 'FINANCE', action: 'READ' },
{ id: 'finance:recon', name: '财务对账', description: '允许执行自动化对账', module: 'FINANCE', action: 'EXECUTE' },
{ id: 'finance:settlement', name: '结算管理', description: '允许处理结算', module: 'FINANCE', action: 'EXECUTE' },
{ id: 'finance:report', name: '财务报表', description: '允许查看财务报表', module: 'FINANCE', action: 'READ' },
// 广告权限
{ id: 'ad:read', name: '查看广告', description: '允许查看广告数据', module: 'ADVERTISING', action: 'READ' },
{ id: 'ad:write', name: '编辑广告', description: '允许创建和修改广告', module: 'ADVERTISING', action: 'WRITE' },
{ id: 'ad:launch', name: '投放广告', description: '允许执行广告投放', module: 'ADVERTISING', action: 'EXECUTE' },
{ id: 'ad:optimize', name: '广告优化', description: '允许执行AI广告优化', module: 'ADVERTISING', action: 'EXECUTE' },
// 采购权限
{ id: 'sourcing:read', name: '查看采购', description: '允许查看采购数据', module: 'SOURCING', action: 'READ' },
{ id: 'sourcing:write', name: '编辑采购', description: '允许创建采购单', module: 'SOURCING', action: 'WRITE' },
{ id: 'sourcing:approve', name: '采购审批', description: '允许审批采购单', module: 'SOURCING', action: 'EXECUTE' },
// 物流权限
{ id: 'logistics:read', name: '查看物流', description: '允许查看物流数据', module: 'LOGISTICS', action: 'READ' },
{ id: 'logistics:write', name: '编辑物流', description: '允许配置物流', module: 'LOGISTICS', action: 'WRITE' },
{ id: 'logistics:track', name: '物流追踪', description: '允许追踪物流状态', module: 'LOGISTICS', action: 'EXECUTE' },
// AI权限
{ id: 'ai:read', name: '查看AI分析', description: '允许查看AI分析结果', module: 'AI', action: 'READ' },
{ id: 'ai:scoring', name: 'AI选品评分', description: '允许执行AI选品评分', module: 'AI', action: 'EXECUTE' },
{ id: 'ai:arbitrage', name: '套利识别', description: '允许执行套利机会识别', module: 'AI', action: 'EXECUTE' },
{ id: 'ai:pricing', name: '智能定价', description: '允许执行智能定价建议', module: 'AI', action: 'EXECUTE' },
{ id: 'ai:monitor', name: '价格监控', description: '允许配置竞争对手价格监控', module: 'AI', action: 'EXECUTE' },
// 采集权限
{ id: 'collection:read', name: '查看采集', description: '允许查看采集任务', module: 'COLLECTION', action: 'READ' },
{ id: 'collection:write', name: '编辑采集', description: '允许创建采集任务', module: 'COLLECTION', action: 'WRITE' },
{ id: 'collection:execute', name: '执行采集', description: '允许执行采集任务', module: 'COLLECTION', action: 'EXECUTE' },
// 用户权限
{ id: 'user:read', name: '查看用户', description: '允许查看用户列表', module: 'USER', action: 'READ' },
{ id: 'user:write', name: '编辑用户', description: '允许创建和修改用户', module: 'USER', action: 'WRITE' },
{ id: 'user:role', name: '角色管理', description: '允许分配用户角色', module: 'USER', action: 'EXECUTE' },
// 租户权限
{ id: 'tenant:read', name: '查看租户', description: '允许查看租户信息', module: 'TENANT', action: 'READ' },
{ id: 'tenant:write', name: '编辑租户', description: '允许修改租户配置', module: 'TENANT', action: 'WRITE' },
{ id: 'tenant:config', name: '租户配置', description: '允许配置租户设置', module: 'TENANT', action: 'EXECUTE' },
// 审计权限
{ id: 'audit:read', name: '查看审计', description: '允许查看审计日志', module: 'AUDIT', action: 'READ' },
{ id: 'audit:export', name: '导出审计', description: '允许导出审计日志', module: 'AUDIT', action: 'EXECUTE' },
];
4. 数据范围控制
4.1 数据范围类型
| 范围类型 | 英文 | 说明 | SQL过滤条件 | 适用角色 |
|---|---|---|---|---|
| OWN | Own | 只看自己创建的数据 | WHERE created_by = {userId} |
普通员工 |
| SHOP | Shop | 看自己店铺的数据 | WHERE shop_id IN ({userShops}) |
店铺管理员 |
| DEPT | Department | 看自己部门的数据 | WHERE dept_id IN ({userDepts}) |
部门主管 |
| ORG | Organization | 看整个公司的数据 | WHERE tenant_id = {tenantId} |
高管 |
| ALL | All | 全平台数据(超管) | 无过滤 | 系统管理员 |
4.2 数据范围实现
// 数据范围接口
export interface DataScope {
type: 'ALL' | 'ORG' | 'DEPT' | 'SHOP' | 'OWN';
departmentId?: string;
shopId?: string;
}
// 数据隔离服务
export class DataIsolationService {
static async getUserDataScope(userId: string): Promise<DataScope> {
const user = await UserService.getUserById(userId);
const role = user.role;
switch(role) {
case 'ADMIN':
return { type: 'ALL' };
case 'MANAGER':
return { type: 'ORG', tenantId: user.tenantId };
case 'DEPT_MANAGER':
const depts = await DepartmentService.getSubDepartments(user.deptId);
return { type: 'DEPT', deptIds: depts.map(d => d.id) };
default:
return { type: 'OWN', userId };
}
}
static applyDataScope(query: Knex.QueryBuilder, scope: DataScope): Knex.QueryBuilder {
switch(scope.type) {
case 'OWN':
return query.where('created_by', scope.userId);
case 'SHOP':
return query.whereIn('shop_id', scope.shopIds);
case 'DEPT':
return query.whereIn('dept_id', scope.deptIds);
case 'ORG':
return query.where('tenant_id', scope.tenantId);
case 'ALL':
default:
return query;
}
}
}
4.3 授权模型
核心原则:
5. 技术实现
5.1 数据模型
用户表 (cf_user)
CREATE TABLE cf_user (
id VARCHAR(36) PRIMARY KEY,
tenant_id VARCHAR(36) NOT NULL,
username VARCHAR(64) NOT NULL UNIQUE,
email VARCHAR(128) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(128) NOT NULL,
phone VARCHAR(32),
status ENUM('ACTIVE', 'INACTIVE', 'LOCKED') DEFAULT 'ACTIVE',
role ENUM('ADMIN', 'MANAGER', 'OPERATOR', 'FINANCE', 'SOURCING', 'LOGISTICS', 'ANALYST') NOT NULL,
is_superadmin BOOLEAN DEFAULT FALSE,
last_login_by VARCHAR(36),
last_login_at TIMESTAMP,
created_by VARCHAR(36) NOT NULL,
updated_by VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_tenant (tenant_id),
INDEX idx_email (email),
FOREIGN KEY (tenant_id) REFERENCES cf_tenant(id) ON DELETE CASCADE
);
租户表 (cf_tenant)
CREATE TABLE cf_tenant (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(128) NOT NULL UNIQUE,
domain VARCHAR(128) NOT NULL UNIQUE,
contact_name VARCHAR(64) NOT NULL,
contact_email VARCHAR(128) NOT NULL UNIQUE,
contact_phone VARCHAR(32) NOT NULL,
address VARCHAR(255) NOT NULL,
status ENUM('ACTIVE', 'INACTIVE', 'SUSPENDED') DEFAULT 'ACTIVE',
quota_limit DECIMAL(10, 2) DEFAULT 10000,
quota_used DECIMAL(10, 2) DEFAULT 0,
created_by VARCHAR(36) NOT NULL,
updated_by VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX (domain),
INDEX (status)
);
部门表 (cf_department)
CREATE TABLE cf_department (
id VARCHAR(36) PRIMARY KEY,
tenant_id VARCHAR(36) NOT NULL,
name VARCHAR(128) NOT NULL,
parent_id VARCHAR(36),
path VARCHAR(500),
depth INT DEFAULT 0,
manager_id VARCHAR(36),
status ENUM('ACTIVE', 'INACTIVE') DEFAULT 'ACTIVE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES cf_tenant(id),
INDEX idx_tenant_path (tenant_id, path)
);
角色权限表 (cf_role_permission)
CREATE TABLE cf_role_permission (
id VARCHAR(36) PRIMARY KEY,
role_id VARCHAR(36) NOT NULL,
permission_id VARCHAR(36) NOT NULL,
created_by VARCHAR(36) NOT NULL,
updated_by VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_role_perm (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES cf_role(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES cf_permission(id) ON DELETE CASCADE
);
5.2 核心服务
HierarchyService - 层级服务
export class HierarchyService {
// 初始化租户层级结构
static async initializeTenantHierarchy(tenantId: string): Promise<void>;
// 创建部门
static async createDepartment(
tenantId: string,
name: string,
parentId?: string,
managerId?: string
): Promise<Department>;
// 更新部门
static async updateDepartment(
departmentId: string,
updates: Partial<Department>
): Promise<void>;
// 删除部门
static async deleteDepartment(departmentId: string, tenantId: string): Promise<void>;
// 分配部门经理
static async assignDepartmentManager(
departmentId: string,
managerId: string,
tenantId: string
): Promise<void>;
// 获取部门经理
static async getDepartmentManager(departmentId: string, tenantId: string): Promise<any>;
// 获取部门统计
static async getDepartmentStats(departmentId: string, tenantId: string): Promise<any>;
// 创建店铺
static async createShop(
tenantId: string,
departmentId: string,
shopData: Partial<Shop>
): Promise<Shop>;
// 更新店铺
static async updateShop(shopId: string, updates: Partial<Shop>): Promise<void>;
// 删除店铺
static async deleteShop(shopId: string, tenantId: string): Promise<void>;
// 获取层级统计
static async getHierarchyStats(tenantId: string): Promise<HierarchyStats>;
// 获取部门树
static async getDepartmentTree(tenantId: string): Promise<HierarchyNode[]>;
// 获取部门下的店铺
static async getDepartmentShops(departmentId: string, tenantId: string): Promise<Shop[]>;
// 获取用户层级上下文
static async getUserHierarchyContext(userId: string): Promise<{
departmentId?: string;
departmentPath?: string;
shopIds: string[];
}>;
// 更新用户层级
static async updateUserHierarchy(
userId: string,
updates: { departmentId?: string; shopIds?: string[] }
): Promise<void>;
}
RBACService - 权限服务
export class RBACService {
// 创建角色
static async createRole(roleData: RoleData): Promise<Role>;
// 为角色分配权限
static async assignPermissions(roleId: string, permissions: string[]): Promise<void>;
// 检查用户权限
static async checkPermission(userId: string, permission: string): Promise<boolean>;
// 获取用户所有权限
static async getUserPermissions(userId: string): Promise<string[]>;
// 权限审计
static async auditPermissionChange(auditData: AuditData): Promise<void>;
}
AuthService - 认证服务
export class AuthService {
// 用户登录
static async login(input: LoginInput): Promise<LoginResult>;
// 用户注册
static async register(input: RegisterInput): Promise<RegisterResult>;
// 请求密码重置
static async requestPasswordReset(input: PasswordResetInput): Promise<PasswordResetResult>;
// 检查权限
static async checkPermission(input: PermissionCheckInput): Promise<PermissionCheckResult>;
// 获取用户权限列表
static async getUserPermissionsList(input: UserPermissionsInput): Promise<UserPermissionsResult>;
// 分配角色
static async assignRole(input: AssignRoleInput): Promise<AssignRoleResult>;
// 验证会话
static async validateSession(input: SessionValidationInput): Promise<SessionValidationResult>;
// 刷新Token
static async refreshToken(input: RefreshTokenInput): Promise<RefreshTokenResult>;
// 登出
static async logout(input: LogoutInput): Promise<LogoutResult>;
// 获取活跃会话
static async getActiveSessions(userId: string, tenantId: string): Promise<SessionInfo[]>;
// 初始化表
static async initializeTables(): Promise<void>;
}
5.3 权限检查中间件
// Express 权限检查中间件
export function requirePermission(...permissions: string[]) {
return async (req: Request, res: Response, next: NextFunction) => {
const userId = req.user?.id;
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
// 获取用户所有权限
const userPermissions = await RBACService.getUserPermissions(userId);
// 检查是否拥有所需权限
const hasPermission = permissions.some(p => userPermissions.includes(p));
if (!hasPermission) {
return res.status(403).json({
error: 'Permission denied',
required: permissions,
current: userPermissions
});
}
next();
};
}
// 数据范围中间件
export function applyDataScope(resourceType: string) {
return async (req: Request, res: Response, next: NextFunction) => {
const userId = req.user?.id;
const scope = await DataScopeService.getUserDataScope(userId);
// 将数据范围附加到请求对象
req.dataScope = scope;
next();
};
}
6. 安全考虑
6.1 安全原则
- 最小权限原则: 用户只获得完成工作所必需的最小权限
- 权限分离: 敏感操作需要多个权限组合
- 定期审计: 定期审查权限配置,清理无效权限
- 数据加密: 敏感数据加密存储和传输
- 访问控制: 严格的身份验证和访问控制
6.2 安全措施
| 安全措施 | 实现方式 | 状态 |
|---|---|---|
| 强密码策略 | 密码复杂度检查、定期更换 | ⚠️ 待实现 |
| 双因素认证(2FA) | TOTP/短信验证码 | ✅ 已实现 |
| 登录异常检测 | 异常IP、时间、地点检测 | ⚠️ 待实现 |
| 权限边界检查 | 防止水平/垂直权限提升 | ✅ 已实现 |
| 敏感数据加密 | AES-256加密存储 | ✅ 已实现 |
| 审计日志 | 记录所有权限变更和数据访问 | ✅ 已实现 |
| 会话管理 | Token过期、单点登录限制 | ✅ 已实现 |
| API限流 | 基于用户/租户的请求限流 | ✅ 已实现 |
6.3 审计日志
// 审计日志记录
export class AuditService {
static async log(data: {
tenantId: string;
userId: string;
action: string;
resource: string;
resourceId?: string;
oldValue?: any;
newValue?: any;
ip?: string;
userAgent?: string;
}): Promise<void> {
await db('cf_audit_log').insert({
id: uuidv4(),
...data,
created_at: new Date()
});
}
}
7. 管理功能
7.1 后台管理系统架构
后台管理系统
├── 用户与权限管理
│ ├── 用户管理
│ │ ├── 用户列表
│ │ ├── 用户创建/编辑
│ │ ├── 用户禁用/启用
│ │ └── 用户登录日志
│ ├── 角色管理
│ │ ├── 角色列表
│ │ ├── 角色创建/编辑
│ │ ├── 权限分配
│ │ └── 角色成员
│ ├── 权限管理
│ │ ├── 权限列表
│ │ ├── 权限树
│ │ └── 权限分析
│ └── 部门管理
│ ├── 部门树
│ ├── 部门创建/编辑
│ ├── 部门成员
│ └── 部门统计
├── 租户管理
│ ├── 租户列表
│ ├── 租户创建/编辑
│ ├── 租户配置
│ ├── 配额管理
│ ├── 租户隔离
│ └── 租户数据备份
├── 店铺管理
│ ├── 我的店铺
│ │ ├── 店铺列表(卡片形式)
│ │ ├── 店铺状态(已连接/已过期/错误)
│ │ ├── 编辑店铺配置
│ │ ├── 刷新授权
│ │ ├── 管理成员
│ │ └── 删除店铺
│ ├── 店铺成员管理
│ │ ├── 侧边栏:我的店铺列表
│ │ ├── 主区域:当前店铺的成员列表
│ │ ├── 添加成员
│ │ ├── 修改成员角色
│ │ └── 移除成员
│ └── 用户店铺管理
│ ├── 查看用户拥有的店铺
│ ├── 添加用户到店铺
│ ├── 移除用户的店铺权限
│ └── 批量分配店铺
└── 系统监控
├── 审计日志
├── 登录日志
├── 操作日志
└── 系统告警
7.2 前端实现
| 功能页面 | 组件路径 | 状态 |
|---|---|---|
| 用户管理 | pages/Settings/UserManagement.tsx |
✅ 已实现 |
| 角色管理 | pages/Settings/RoleManagement.tsx |
✅ 已实现 |
| 部门管理 | pages/Settings/DepartmentManagement.tsx |
✅ 已实现 |
| 租户设置 | pages/Settings/TenantSettings.tsx |
✅ 已实现 |
| 订阅管理 | pages/Settings/SubscriptionManage.tsx |
✅ 已实现 |
| 我的店铺 | pages/Settings/MyShops.tsx |
✅ 已实现 |
| 店铺成员管理 | pages/Settings/ShopMemberManagement.tsx |
✅ 已实现 |
| 系统监控 | pages/Monitoring/SystemStatus.tsx |
✅ 已实现 |
| 操作日志 | pages/OperationLogs/index.tsx |
✅ 已实现 |
7.3 店铺管理流程
7.3.1 店铺视角管理(我的店铺)
页面路径: /dashboard/settings/my-shops
功能说明:
- 显示用户拥有的所有店铺(卡片形式)
- 每个店铺卡片显示:
- 店铺名称
- 平台类型(带图标)
- 授权状态(已连接/已过期/错误)
- 成员数量
- 最后同步时间
- 操作按钮:
- 管理成员:跳转到店铺成员管理页面
- 编辑配置:修改店铺名称、平台配置
- 刷新授权:刷新过期的店铺授权
- 删除店铺:删除店铺及其成员关系
使用场景:
- 用户登录系统
- 进入"我的店铺"页面
- 查看自己拥有的所有店铺
- 点击某个店铺的"管理成员"按钮
- 进入店铺成员管理页面
7.3.2 店铺成员管理
页面路径: /dashboard/settings/shop-members/:shopId
功能说明:
- 左侧边栏:我的店铺列表
- 显示用户拥有的所有店铺
- 当前选中的店铺高亮
- 显示每个店铺的成员数量
- 点击切换店铺
- 右侧主区域:当前店铺的成员列表
- 显示成员信息(用户名、邮箱、角色、权限)
- 添加成员(选择用户,分配角色和权限)
- 修改成员角色(下拉选择)
- 移除成员
使用场景:
- 从"我的店铺"页面点击"管理成员"
- 进入店铺成员管理页面
- 左侧边栏显示我的店铺列表
- 选择要管理的店铺
- 右侧显示该店铺的成员列表
- 添加/修改/移除成员
7.3.3 用户视角管理(用户店铺分配)
页面路径: /dashboard/settings/user
功能说明:
- 在用户管理页面,每个用户有"管理店铺"按钮
- 点击后弹出店铺分配模态框
- 模态框功能:
- 按平台分组显示所有店铺
- 支持平台级别全选
- 支持单个店铺选择
- 显示已分配店铺列表
- 保存分配结果
使用场景:
- 管理员进入用户管理页面
- 点击某个用户的"管理店铺"按钮
- 在弹出的模态框中:
- 查看该用户当前拥有的店铺
- 添加新的店铺权限
- 移除现有的店铺权限
- 保存分配结果
7.4 双向管理关系
7.4.1 店铺 → 用户管理
入口: 我的店铺 → 店铺成员管理
操作流程:
我的店铺页面
↓
选择店铺 → 点击"管理成员"
↓
店铺成员管理页面
↓
左侧边栏:我的店铺列表
↓
选择要管理的店铺
↓
右侧主区域:当前店铺的成员列表
↓
添加/修改/移除成员
特点:
- 店铺拥有者可以管理自己店铺的成员
- 可以添加、修改、删除成员
- 可以分配不同的角色和权限
- 侧边栏支持快速切换店铺
7.4.2 用户 → 店铺管理
入口: 用户管理 → 管理店铺
操作流程:
用户管理页面
↓
选择用户 → 点击"管理店铺"
↓
店铺分配模态框
↓
查看该用户拥有的店铺
↓
添加/删除店铺权限
↓
保存分配结果
特点:
- 管理员可以管理任何用户的店铺权限
- 可以批量分配多个店铺
- 支持按平台分组显示
- 可以查看已分配的店铺列表
7.4.3 数据关系
cf_shop(店铺表)
↓
cf_shop_member(店铺成员表)
↓
记录:用户-店铺-角色关系
cf_user(用户表)
↓
通过cf_shop_member关联店铺
关键约束:
- 一个用户可以拥有多个店铺的权限
- 一个店铺可以有多个成员
- 成员角色:owner(拥有者)、admin(管理员)、operator(运营)、viewer(只读)
- 权限可以自定义,也可以使用预设权限
7.5 店铺管理API
7.5.1 店铺相关API
| API路径 | 方法 | 说明 | 权限要求 |
|---|---|---|---|
/api/shops/my-shops |
GET | 获取当前用户的店铺列表 | 登录用户 |
/api/shops/:id |
GET | 获取店铺详情 | 店铺成员 |
/api/shops |
POST | 创建店铺 | 店铺拥有者 |
/api/shops/:id |
PUT | 更新店铺信息 | 店铺拥有者 |
/api/shops/:id/refresh-auth |
POST | 刷新店铺授权 | 店铺拥有者 |
/api/shops/:id |
DELETE | 删除店铺 | 店铺拥有者 |
/api/shops/stats |
GET | 获取店铺统计信息 | 登录用户 |
7.5.2 店铺成员相关API
| API路径 | 方法 | 说明 | 权限要求 |
|---|---|---|---|
/api/shops/:shopId/members |
GET | 获取店铺成员列表 | 店铺成员 |
/api/shops/user/:userId/shops |
GET | 获取用户拥有的店铺 | 管理员或用户本人 |
/api/shop-members |
POST | 添加店铺成员 | 店铺拥有者 |
/api/shop-members/:shopId/:userId |
DELETE | 移除店铺成员 | 店铺拥有者 |
/api/shop-members/:shopId/:userId |
PUT | 更新成员角色和权限 | 店铺拥有者 |
7.5.3 数据源实现
文件路径: dashboard/src/services/shopDataSource.ts
主要方法:
getMyShops(): 获取当前用户的店铺列表getById(id): 获取店铺详情getShopMembers(shopId): 获取店铺成员列表getUserShops(userId): 获取用户拥有的店铺createShop(data): 创建店铺updateShop(id, data): 更新店铺信息refreshAuth(id): 刷新店铺授权deleteShop(id): 删除店铺addMember(data): 添加店铺成员removeMember(shopId, userId): 移除店铺成员updateMemberRole(shopId, userId, role, permissions): 更新成员角色和权限getStats(): 获取店铺统计信息
8. 实现状态
8.1 已实现功能
| 功能模块 | 功能点 | 状态 | 实现位置 |
|---|---|---|---|
| 用户管理 | 用户CRUD | ✅ | UserService.ts, UserManagement.tsx |
| 用户状态管理 | ✅ | UserService.updateUserStatus | |
| 用户缓存 | ✅ | UserService (Redis缓存) | |
| 批量操作 | ✅ | UserService.batchCreateUsers | |
| 角色管理 | 角色CRUD | ✅ | RBACService.ts, RoleManagement.tsx |
| 权限分配 | ✅ | RBACService.assignPermissions | |
| 权限树 | ✅ | RoleManagement.tsx | |
| 部门管理 | 部门CRUD | ✅ | HierarchyService.ts, DepartmentManagement.tsx |
| 层级结构 | ✅ | HierarchyService (path + depth) | |
| 部门转移 | ✅ | HierarchyService.transferUser | |
| 租户管理 | 租户CRUD | ✅ | SaasTenantService.ts |
| 租户隔离 | ✅ | 所有表tenant_id字段 | |
| 配额管理 | ✅ | QuotaGovernance | |
| 店铺管理 | 店铺CRUD | ✅ | ShopService.ts, MyShops.tsx |
| 店铺成员管理 | ✅ | ShopMemberService.ts, ShopMemberManagement.tsx | |
| 店铺授权刷新 | ✅ | ShopService.refreshAuth | |
| 用户店铺分配 | ✅ | UserManagement.tsx | |
| 双向管理关系 | ✅ | 店铺视角 + 用户视角 | |
| 认证授权 | 登录认证 | ✅ | AuthService.ts |
| Token管理 | ✅ | JWT + Refresh Token | |
| 权限检查 | ✅ | requirePermission中间件 | |
| 数据范围 | 范围控制 | ✅ | DataScopeService |
| 部门过滤 | ✅ | dept_path字段 |
8.2 待实现功能
| 功能模块 | 功能点 | 优先级 | 计划时间 |
|---|---|---|---|
| 安全增强 | 强密码策略 | P1 | 待定 |
| 登录异常检测 | P2 | 待定 | |
| 用户体验 | 拖拽排序 | P2 | 待定 |
| 集成扩展 | SSO集成 | P2 | 待定 |
| LDAP/AD集成 | P3 | 待定 | |
| Webhook通知 | P3 | 待定 | |
| 测试覆盖 | 功能测试 | P1 | 待定 |
| 安全测试 | P1 | 待定 | |
| 性能测试 | P2 | 待定 |
9. 相关文档
- User_Tenant_Improvement_Checklist.md - 用户租户改进清单
- RBAC_Design.md - RBAC详细设计
- Governance_Standards.md - 治理规范
- Security_Policy.md - 安全策略
10. 总结
Crawlful Hub 的用户层级架构采用了多租户 + 多层级 + RBAC 的设计模式:
- 多租户隔离: 确保不同商户数据完全隔离,保障数据安全
- 灵活的组织结构: 支持多级部门,适应不同规模企业
- 细粒度权限控制: 基于角色的权限管理,支持自定义角色
- 数据范围控制: 从个人到全平台的多级数据访问控制
- 完整的审计体系: 记录所有操作,支持安全审计
该架构不仅满足了企业级应用的安全需求,也为不同规模的商户提供了灵活的组织管理能力,支持从初创企业到大型集团的业务场景。