feat(risk-control): 新增 IP/账号手动封禁,并收口财务同步的全表更新

- 风控:worker_risk_bans 表 + 前置封禁中间件(登录一并拦截)+ 后台列表/新增/解封
- 财务:成本快照补商品维度收口到本批 order_item_id,不再整表扫 899MB 的 order_items
- 性能:order_items 覆盖索引(迁移 110)、大厅 pageSize 上限 20、已读/上传接口限流
This commit is contained in:
yml2213
2026-10-30 20:15:14 +08:00
parent 1b170d3f45
commit fb485f7e36
17 changed files with 1373 additions and 18 deletions
@@ -3,9 +3,12 @@ import type { Request } from 'express'
import {
banAdminWorkerRisk,
banAdminWorkerRiskTarget,
getAdminWorkerRiskOverview,
listAdminWorkerRiskBans,
listAdminWorkerRiskEvents,
releaseAdminWorkerRiskTracker,
revokeAdminWorkerRiskBan,
saveAdminWorkerRiskConfig,
unbanAdminWorkerRisk,
} from '../../../services/worker-platform/index.js'
@@ -63,6 +66,70 @@ router.post(
}),
)
/**
* 手动封禁(IP / 账号)的持久化列表。
*
* 与「实时风控」里那批内存 tracker 的区别:这里是落库的事实,进程重启不丢,
* 中间件按它拦截 /api/v1/worker 下的所有请求(含登录)。
*/
router.get(
'/worker-platform/risk-control/bans',
requireAdminRoles(['admin', 'operator', 'support']),
createJsonHandler((req) => listAdminWorkerRiskBans((req.query || {}) as JsonRecord), {
successMessage: 'ok',
errorMessage: '读取封禁列表失败',
scope: '[admin/worker-platform/risk-control/bans]',
}),
)
router.post(
'/worker-platform/risk-control/bans',
requireAdminRoles(['admin']),
createJsonHandler(
(req) => banAdminWorkerRiskTarget(actorOf(req), (req.body || {}) as JsonRecord),
{
successMessage: '封禁已生效',
errorMessage: '封禁失败',
scope: '[admin/worker-platform/risk-control/bans]',
audit: (req, data) => {
const result = data as JsonRecord
const ban = (result.ban || {}) as JsonRecord
return {
action: 'worker_risk_ban_created',
targetType: String(
ban.targetType || (req.body as JsonRecord | undefined)?.targetType || '',
),
targetId: String(ban.target || ''),
data: { ban },
}
},
},
),
)
router.post(
'/worker-platform/risk-control/bans/:banId/revoke',
requireAdminRoles(['admin']),
createJsonHandler(
(req) =>
revokeAdminWorkerRiskBan(
paramOf(req.params.banId),
actorOf(req),
(req.body || {}) as JsonRecord,
),
{
successMessage: '封禁已解除',
errorMessage: '解除封禁失败',
scope: '[admin/worker-platform/risk-control/bans/:banId/revoke]',
audit: (req) => ({
action: 'worker_risk_ban_revoked',
targetType: 'worker_risk_ban',
targetId: String(paramOf(req.params.banId)),
}),
},
),
)
router.get(
'/worker-platform/risk-control/events',
requireAdminRoles(['admin', 'operator', 'support']),