后台新增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
+2
View File
@@ -10,6 +10,7 @@ import kuaishouIndustryRouter from './admin/kuaishou-industry.js'
import ordersRouter from './admin/orders.js'
import notificationsRouter from './admin/notifications.js'
import realtimeRouter from './admin/realtime.js'
import rbacRouter from './admin/rbac.js'
import platformConfigRouter from './admin/platform-config.js'
import { requireAdminSession } from './admin/session.js'
import tasksRouter from './admin/tasks.js'
@@ -24,6 +25,7 @@ router.use(requireAdminSession)
router.use(filesRouter)
router.use(dashboardRouter)
router.use(usersRouter)
router.use(rbacRouter)
router.use(auditLogsRouter)
router.use(platformConfigRouter)
router.use(kuaishouIndustryRouter)
+40
View File
@@ -0,0 +1,40 @@
import { Router } from 'express'
import {
listAdminRolesWithPermissions,
updateAdminRolePermissions,
} from '../../services/admin/admin-rbac-service.js'
import { createJsonHandler, requireAdminRoles } from './session.js'
const router = Router()
router.use('/rbac', requireAdminRoles(['admin']))
router.get(
'/rbac',
createJsonHandler(() => listAdminRolesWithPermissions(), {
successMessage: 'ok',
errorMessage: '读取角色权限失败',
scope: '[admin/rbac]',
}),
)
router.put(
'/rbac/roles/:roleKey/permissions',
createJsonHandler(
(req) => updateAdminRolePermissions(req.params.roleKey, req.body?.permissions),
{
successMessage: '角色权限已更新',
errorMessage: '更新角色权限失败',
scope: '[admin/rbac/roles/:roleKey/permissions]',
audit: (req, data) => ({
action: 'admin_role_permissions_updated',
targetType: 'admin_role',
targetId: String(req.params.roleKey || ''),
data: data && typeof data === 'object' ? (data as Record<string, unknown>) : {},
}),
},
),
)
export default router
+39
View File
@@ -80,6 +80,45 @@ export function requireAdminRoles(allowedRoles: string[]) {
}
}
export function requireAdminPermission(permission: string) {
return (req: Request, res: Response, next: NextFunction): void => {
try {
const session = getRequiredAdminSession(req)
if (!session.permissions.includes(String(permission || '').trim())) {
throw createHttpError('当前账号没有此操作权限', {
statusCode: 403,
errorCode: 'admin_permission_denied',
})
}
next()
} catch (error) {
sendRouteError(res, error, '后台鉴权失败', '[admin/auth/permission]')
}
}
}
export function requireAnyAdminPermission(permissions: string[]) {
return (req: Request, res: Response, next: NextFunction): void => {
try {
const session = getRequiredAdminSession(req)
if (
permissions.some((permission) =>
session.permissions.includes(String(permission || '').trim()),
)
) {
next()
return
}
throw createHttpError('当前账号没有此操作权限', {
statusCode: 403,
errorCode: 'admin_permission_denied',
})
} catch (error) {
sendRouteError(res, error, '后台鉴权失败', '[admin/auth/permission]')
}
}
}
export function getRequiredAdminSession(req: Request): AdminSession {
if (req.adminSession) {
return req.adminSession
@@ -8,13 +8,13 @@ import {
markAdminWorkOrderProblem,
resolveAdminProblemWorkOrder,
} from '../../../services/worker-platform/index.js'
import { createJsonHandler, requireAdminRoles } from '../session.js'
import { createJsonHandler, requireAdminPermission } from '../session.js'
const router = Router()
router.post(
'/worker-platform/orders/:workOrderId/problem',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.manage_problem'),
createJsonHandler(
(req) =>
markAdminWorkOrderProblem(
@@ -38,7 +38,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/problem/resolve',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.manage_problem'),
createJsonHandler(
(req) =>
resolveAdminProblemWorkOrder(
@@ -62,7 +62,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/accept',
requireAdminRoles(['admin', 'operator']),
requireAdminPermission('worker_order.accept'),
createJsonHandler(
(req) =>
acceptAdminWorkOrder(String(req.params.workOrderId || ''), req.adminSession?.username || ''),
@@ -82,7 +82,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/shares/:shareId/accept',
requireAdminRoles(['admin', 'operator']),
requireAdminPermission('worker_order.accept'),
createJsonHandler(
(req) =>
acceptAdminWorkOrderShare(
@@ -106,7 +106,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/shares/:shareId/cancel',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.cancel_share'),
createJsonHandler(
(req) =>
cancelAdminWorkOrderShare(
@@ -131,7 +131,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/deduct-pending-deposit',
requireAdminRoles(['admin', 'operator']),
requireAdminPermission('worker_order.deduct_deposit'),
createJsonHandler(
(req) =>
deductAdminWorkOrderPendingDeposit(
@@ -25,13 +25,18 @@ import {
updateAdminWorkOrder,
updateAdminWorkOrderSharing,
} from '../../../services/worker-platform/index.js'
import { createJsonHandler, requireAdminRoles } from '../session.js'
import {
createJsonHandler,
requireAdminPermission,
requireAnyAdminPermission,
requireAdminRoles,
} from '../session.js'
const router = Router()
router.get(
'/worker-platform/orders',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.view'),
createJsonHandler((req) => listAdminWorkOrders(req.query), {
successMessage: 'ok',
errorMessage: '读取接单订单失败',
@@ -138,7 +143,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/material',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.update_material'),
createJsonHandler(
(req) =>
submitAdminWorkOrderMaterial(
@@ -162,7 +167,7 @@ router.post(
router.put(
'/worker-platform/orders/:workOrderId',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.edit'),
createJsonHandler(
(req) =>
updateAdminWorkOrder(String(req.params.workOrderId || ''), req.body || {}, {
@@ -185,7 +190,7 @@ router.put(
router.post(
'/worker-platform/orders/:workOrderId/assign',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.assign'),
createJsonHandler(
(req) =>
assignAdminWorkOrderToWorker(
@@ -209,7 +214,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/unassign',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.assign'),
createJsonHandler(
(req) =>
unassignAdminWorkOrder(
@@ -232,13 +237,14 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/cancel',
requireAdminRoles(['admin', 'operator', 'support']),
requireAnyAdminPermission(['worker_order.return_to_hall', 'worker_order.cancel']),
createJsonHandler(
(req) =>
cancelAdminWorkOrder(
String(req.params.workOrderId || ''),
req.body || {},
req.adminSession?.username || '',
req.adminSession?.permissions || [],
),
{
successMessage: '撤单处理完成,打手额度已恢复',
@@ -259,7 +265,7 @@ router.post(
router.delete(
'/worker-platform/orders/:workOrderId',
requireAdminRoles(['admin', 'operator']),
requireAdminPermission('worker_order.delete'),
createJsonHandler((req) => deleteAdminWorkOrder(String(req.params.workOrderId || '')), {
successMessage: '工单已删除',
errorMessage: '删除工单失败',
@@ -275,7 +281,7 @@ router.delete(
router.post(
'/worker-platform/orders/:workOrderId/reopen',
requireAdminRoles(['admin', 'operator']),
requireAdminPermission('worker_order.reopen'),
createJsonHandler(
(req) =>
reopenAdminCancelledWorkOrder(
@@ -298,7 +304,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/publish',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.publish'),
createJsonHandler(
(req) =>
publishAdminWorkOrder(String(req.params.workOrderId || ''), req.adminSession?.username || ''),
@@ -318,7 +324,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/unpublish',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.publish'),
createJsonHandler(
(req) =>
unpublishAdminWorkOrder(
@@ -341,7 +347,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/pin',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.publish'),
createJsonHandler(
(req) =>
pinAdminWorkOrder(
@@ -365,7 +371,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/confirm-friend',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.manage_problem'),
createJsonHandler(
(req) =>
confirmAdminWorkOrderFriendAdded(
@@ -388,7 +394,7 @@ router.post(
router.post(
'/worker-platform/orders/:workOrderId/reset-gift-material',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.manage_problem'),
createJsonHandler(
(req) =>
resetAdminWorkOrderGiftMaterial(
@@ -412,7 +418,7 @@ router.post(
router.get(
'/worker-platform/orders/:workOrderId/sharing',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.view'),
createJsonHandler((req) => getAdminWorkOrderSharing(String(req.params.workOrderId || '')), {
successMessage: 'ok',
errorMessage: '读取拼单信息失败',
@@ -422,7 +428,7 @@ router.get(
router.get(
'/worker-platform/orders/:workOrderId/events',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.view'),
createJsonHandler((req) => getAdminWorkOrderEvents(String(req.params.workOrderId || '')), {
successMessage: 'ok',
errorMessage: '读取工单流转记录失败',
@@ -432,7 +438,7 @@ router.get(
router.post(
'/worker-platform/orders/:workOrderId/sharing',
requireAdminRoles(['admin', 'operator']),
requireAdminPermission('worker_order.configure_share'),
createJsonHandler(
(req) =>
updateAdminWorkOrderSharing(
@@ -456,7 +462,7 @@ router.post(
router.post(
'/worker-platform/orders/accept-batch',
requireAdminRoles(['admin', 'operator']),
requireAdminPermission('worker_order.accept'),
createJsonHandler(
(req) => acceptAdminWorkOrders(req.body || {}, req.adminSession?.username || ''),
{
@@ -6,13 +6,13 @@ import {
resolveAdminWorkerOrderFeedback,
reviewAdminWorkerCancelRequest,
} from '../../../services/worker-platform/index.js'
import { createJsonHandler, requireAdminRoles } from '../session.js'
import { createJsonHandler, requireAdminPermission } from '../session.js'
const router = Router()
router.get(
'/worker-platform/cancel-requests',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_cancel_request.review'),
createJsonHandler((req) => listAdminWorkerCancelRequests(req.query), {
successMessage: 'ok',
errorMessage: '读取撤单申请失败',
@@ -22,7 +22,7 @@ router.get(
router.get(
'/worker-platform/feedbacks',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.manage_problem'),
createJsonHandler((req) => listAdminWorkerOrderFeedbacks(req.query), {
successMessage: 'ok',
errorMessage: '读取问题反馈失败',
@@ -32,7 +32,7 @@ router.get(
router.post(
'/worker-platform/feedbacks/:feedbackId/resolve',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_order.manage_problem'),
createJsonHandler(
(req) =>
resolveAdminWorkerOrderFeedback(
@@ -50,7 +50,7 @@ router.post(
router.post(
'/worker-platform/cancel-requests/:requestId/review',
requireAdminRoles(['admin', 'operator', 'support']),
requireAdminPermission('worker_cancel_request.review'),
createJsonHandler(
(req) =>
reviewAdminWorkerCancelRequest(