后台新增RBAC权限模型支持按角色配置接单管理权限

- 新增 admin_roles/admin_permissions/admin_role_permissions 三表与种子数据(059迁移)
- 接单平台全部管理路由从固定角色切换为细粒度权限校验
- 撤单按动作二次校验:退回大厅与取消订单分别要求对应权限
- 管理员账号页新增角色权限配置卡片(admin专属,带审计日志)
- 权限更新走事务保证原子性;session实时解析权限确保修改立即生效
This commit is contained in:
yml2213
2026-08-23 16:04:10 +08:00
parent fb0e9c8f9c
commit 3df271b30c
16 changed files with 610 additions and 70 deletions
@@ -24,10 +24,12 @@ import PageHeader from '@/components/admin/PageHeader'
import StatusTag from '@/components/admin/StatusTag'
import {
createAdminUser,
fetchAdminRolePermissions,
fetchAdminUsers,
resetAdminUserPassword,
updateAdminUserRole,
updateAdminUserStatus,
updateAdminRolePermissions,
} from '@/services/admin'
import type { AdminRole, AdminUserListItem } from '@/types/admin'
import { getAdminUserId, hasAdminRole } from '@/utils/admin-auth'
@@ -83,11 +85,33 @@ export default function AdminUsersPage() {
queryFn: () => fetchAdminUsers(queryParams),
})
const data = query.data?.data
const rolePermissionsQuery = useQuery({
queryKey: ['admin-role-permissions'],
enabled: isAdmin,
queryFn: () => fetchAdminRolePermissions(),
})
async function reloadUsers() {
await queryClient.invalidateQueries({ queryKey: ['admin-users'] })
}
async function toggleRolePermission(roleKey: string, permissionKey: string, enabled: boolean) {
const role = rolePermissionsQuery.data?.data.roles.find((item) => item.roleKey === roleKey)
if (!role || roleKey === 'admin') return
const permissions = role.permissions
.filter((item) => item.enabled)
.map((item) => item.permissionKey)
.filter((item) => item !== permissionKey)
if (enabled) permissions.push(permissionKey)
try {
await updateAdminRolePermissions(roleKey, permissions)
await queryClient.invalidateQueries({ queryKey: ['admin-role-permissions'] })
message.success('角色权限已更新')
} catch (error) {
message.error(error instanceof Error ? error.message : '更新角色权限失败')
}
}
async function submitCreate(values: CreateUserForm) {
setCreating(true)
@@ -420,6 +444,37 @@ export default function AdminUsersPage() {
})}
/>
</Card>
<Card title="角色权限">
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
{(rolePermissionsQuery.data?.data.roles || []).map((role) => (
<div key={role.roleKey}>
<Typography.Text strong>{role.roleName}</Typography.Text>
<div style={{ marginTop: 8 }}>
<Space wrap>
{role.permissions.map((permission) => (
<Button
key={permission.permissionKey}
size="small"
type={permission.enabled ? 'primary' : 'default'}
disabled={role.roleKey === 'admin'}
onClick={() =>
void toggleRolePermission(
role.roleKey,
permission.permissionKey,
!permission.enabled,
)
}
>
{permission.permissionName}
</Button>
))}
</Space>
</div>
</div>
))}
</Space>
</Card>
</section>
)
}