f938ca6c00
添加角色基于访问控制(RBAC)相关接口: 1. API 代理路由 - api.v3.rbac.roles._index.tsx: 角色列表和创建 - api.v3.rbac.roles.$roleId.tsx: 角色详情、更新和删除 - api.v3.rbac.roles.$roleId.users.tsx: 角色用户关联管理 - api.v3.rbac.users.$userId.roles.tsx: 用户角色列表 - api.v3.rbac.users.$userId.roles.$roleId.tsx: 用户角色分配 2. 模拟数据服务 - rbac-mock-data.server.ts: 提供模拟角色和用户角色数据 - 支持 CRUD 操作 - 包含预置的系统管理员、开发者等角色 接口功能: - ✅ 获取角色列表(支持分页和搜索) - ✅ 获取角色详情 - ✅ 创建、更新、删除角色 - ✅ 获取角色的用户列表 - ✅ 为用户分配/移除角色 注:当前使用模拟数据,待后端接口完善后切换到真实 API 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
227 lines
5.7 KiB
TypeScript
227 lines
5.7 KiB
TypeScript
/**
|
|
* RBAC Mock数据 - 共享存储
|
|
* 所有Remix API路由共享这个数据源
|
|
*/
|
|
|
|
// ==================== 角色数据(与数据库实际数据一致)====================
|
|
|
|
export const mockRoles = [
|
|
{
|
|
id: 1,
|
|
role_key: 'admin',
|
|
role_name: '市级管理员',
|
|
description: '负责本地区的所有业务管理,不包括系统设置和角色权限管理',
|
|
data_scope: 'DEPT',
|
|
is_system: false,
|
|
priority: 0,
|
|
created_at: '2025-07-18T10:35:39+08:00',
|
|
updated_at: '2025-07-18T10:35:39+08:00'
|
|
},
|
|
{
|
|
id: 2,
|
|
role_key: 'common',
|
|
role_name: '普通员工',
|
|
description: '仅能操作自己的数据',
|
|
data_scope: 'SELF',
|
|
is_system: false,
|
|
priority: 0,
|
|
created_at: '2025-07-18T10:35:39+08:00',
|
|
updated_at: '2025-07-18T10:35:39+08:00'
|
|
},
|
|
{
|
|
id: 52,
|
|
role_key: 'provincial_admin',
|
|
role_name: '省级管理员',
|
|
description: '拥有全部权限,可以管理所有地区的评查点规则、提示词、动态按钮、评查组',
|
|
data_scope: 'ALL',
|
|
is_system: true,
|
|
priority: 1,
|
|
created_at: '2025-11-19T17:25:45+08:00',
|
|
updated_at: '2025-11-19T17:25:45+08:00'
|
|
}
|
|
];
|
|
|
|
// ==================== 用户数据 ====================
|
|
|
|
export const mockUsers = [
|
|
{
|
|
id: 1,
|
|
user_id: 1,
|
|
username: 'admin',
|
|
nick_name: '系统管理员',
|
|
phone_number: '13800138000',
|
|
email: 'admin@example.com',
|
|
ou_name: '广东省烟草专卖局',
|
|
area: '广东省',
|
|
status: 1,
|
|
is_leader: true
|
|
},
|
|
{
|
|
id: 2,
|
|
user_id: 2,
|
|
username: 'zhangsan',
|
|
nick_name: '张三',
|
|
phone_number: '13800138001',
|
|
email: 'zhangsan@example.com',
|
|
ou_name: '梅州市烟草专卖局',
|
|
area: '梅州',
|
|
status: 1,
|
|
is_leader: true
|
|
},
|
|
{
|
|
id: 3,
|
|
user_id: 3,
|
|
username: 'lisi',
|
|
nick_name: '李四',
|
|
phone_number: '13800138002',
|
|
email: 'lisi@example.com',
|
|
ou_name: '云浮市烟草专卖局',
|
|
area: '云浮',
|
|
status: 1,
|
|
is_leader: false
|
|
},
|
|
{
|
|
id: 4,
|
|
user_id: 4,
|
|
username: 'wangwu',
|
|
nick_name: '王五',
|
|
phone_number: '13800138003',
|
|
email: 'wangwu@example.com',
|
|
ou_name: '揭阳市烟草专卖局',
|
|
area: '揭阳',
|
|
status: 1,
|
|
is_leader: false
|
|
},
|
|
{
|
|
id: 5,
|
|
user_id: 5,
|
|
username: 'zhaoliu',
|
|
nick_name: '赵六',
|
|
phone_number: '13800138004',
|
|
email: 'zhaoliu@example.com',
|
|
ou_name: '潮州市烟草专卖局',
|
|
area: '潮州',
|
|
status: 1,
|
|
is_leader: false
|
|
},
|
|
{
|
|
id: 6,
|
|
user_id: 6,
|
|
username: 'sunqi',
|
|
nick_name: '孙七',
|
|
phone_number: '13800138005',
|
|
email: 'sunqi@example.com',
|
|
ou_name: '汕头市烟草专卖局',
|
|
area: '汕头',
|
|
status: 1,
|
|
is_leader: true
|
|
}
|
|
];
|
|
|
|
// ==================== 用户-角色关联数据 ====================
|
|
|
|
export const mockUserRoles: Array<{ user_id: number; role_id: number; assigned_at: string }> = [
|
|
{ user_id: 1, role_id: 52, assigned_at: '2025-01-20T10:00:00' }, // admin - provincial_admin (id=52)
|
|
{ user_id: 2, role_id: 1, assigned_at: '2025-01-21T10:00:00' }, // zhangsan - 市级管理员 (id=1)
|
|
{ user_id: 3, role_id: 1, assigned_at: '2025-01-21T11:00:00' }, // lisi - 市级管理员 (id=1)
|
|
{ user_id: 4, role_id: 2, assigned_at: '2025-01-21T12:00:00' }, // wangwu - 普通员工 (id=2)
|
|
];
|
|
|
|
// ==================== 辅助函数 ====================
|
|
|
|
/**
|
|
* 获取角色的用户列表
|
|
*/
|
|
export function getRoleUsers(roleId: number) {
|
|
const userIds = mockUserRoles
|
|
.filter(ur => ur.role_id === roleId)
|
|
.map(ur => ur.user_id);
|
|
|
|
return mockUsers.filter(u => userIds.includes(u.id || u.user_id));
|
|
}
|
|
|
|
/**
|
|
* 为用户分配角色
|
|
*/
|
|
export function assignUserRole(userId: number, roleId: number) {
|
|
// 检查是否已存在
|
|
const exists = mockUserRoles.some(
|
|
ur => ur.user_id === userId && ur.role_id === roleId
|
|
);
|
|
|
|
if (!exists) {
|
|
mockUserRoles.push({
|
|
user_id: userId,
|
|
role_id: roleId,
|
|
assigned_at: new Date().toISOString()
|
|
});
|
|
console.log('✅ [Mock Data] 用户角色分配成功:', { userId, roleId });
|
|
console.log('📊 [Mock Data] 当前用户-角色关联:', mockUserRoles);
|
|
} else {
|
|
console.log('⚠️ [Mock Data] 用户角色关联已存在:', { userId, roleId });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 移除用户角色
|
|
*/
|
|
export function removeUserRole(userId: number, roleId: number) {
|
|
const index = mockUserRoles.findIndex(
|
|
ur => ur.user_id === userId && ur.role_id === roleId
|
|
);
|
|
|
|
if (index > -1) {
|
|
mockUserRoles.splice(index, 1);
|
|
console.log('✅ [Mock Data] 用户角色移除成功:', { userId, roleId });
|
|
console.log('📊 [Mock Data] 当前用户-角色关联:', mockUserRoles);
|
|
return true;
|
|
}
|
|
|
|
console.log('⚠️ [Mock Data] 用户角色关联不存在:', { userId, roleId });
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 添加新角色
|
|
*/
|
|
export function addRole(roleData: any) {
|
|
const newRole = {
|
|
id: Math.max(...mockRoles.map(r => r.id), 0) + 1,
|
|
...roleData,
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString()
|
|
};
|
|
|
|
mockRoles.push(newRole);
|
|
console.log('✅ [Mock Data] 角色创建成功:', newRole);
|
|
return newRole;
|
|
}
|
|
|
|
/**
|
|
* 更新角色
|
|
*/
|
|
export function updateRole(roleId: number, updates: any) {
|
|
const role = mockRoles.find(r => r.id === roleId);
|
|
if (role) {
|
|
Object.assign(role, updates, {
|
|
updated_at: new Date().toISOString()
|
|
});
|
|
console.log('✅ [Mock Data] 角色更新成功:', role);
|
|
return role;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 删除角色
|
|
*/
|
|
export function deleteRole(roleId: number) {
|
|
const index = mockRoles.findIndex(r => r.id === roleId);
|
|
if (index > -1) {
|
|
const deleted = mockRoles.splice(index, 1)[0];
|
|
console.log('✅ [Mock Data] 角色删除成功:', deleted);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|