fix(admin): 风控 tab 点了没反应 —— tab key 白名单漏登记,并合并为唯一来源

## 现象与根因

风控 tab 渲染得出来、但怎么点都切不过去,且不报错、不白屏。

原因是 tab key 名单在同一文件里写了两遍:
  - isWorkerPlatformTab()(changeTab 的守卫)
  - loadActiveTabPreference()(localStorage 旧选择校验)
新增风控 tab 时只把 'risk-control' 加了 TAB_QUERY_KEYS 与 Tabs items,漏了上面两处,
于是 changeTab('risk-control') 在第一行 `if (!isWorkerPlatformTab(nextTab)) return` 就返回了。

这类漏改没有任何报错信号,只能靠点一下才发现——上一轮的验证只查了构建产物里
是否含面板代码,没有验证 tab 真的能切换,所以没拦住。

## 修法

把名单抽到 utils/admin-worker-platform-tabs.ts,只保留唯一一份
WORKER_PLATFORM_TAB_KEYS;查询缓存映射与「只登记缓存但不是 tab」的例外(hall-config,
它是「杂项配置」tab 内部的区块)也一并显式化,避免下次再靠人记。

## 回归测试

新增 tests/admin-worker-platform-tabs.test.ts(5 个用例):
  - 风控 tab 必须被 isWorkerPlatformTab 接受
  - 每个登记了切页缓存的 tab 都必须在合法 tab 名单里 ← 正是本次漏改的形态
  - 名单无重复项 / 非法 key 被拒 / 名单内自洽
This commit is contained in:
yml2213
2026-10-02 17:13:59 +08:00
parent 2982819548
commit e0d7398d37
3 changed files with 121 additions and 60 deletions
@@ -7,6 +7,10 @@ import PageHeader from '@/components/admin/PageHeader'
import type { WorkOrder } from '@/types/worker-platform'
import { fetchAdminWorkerPlatformSummary } from '@/services/admin'
import { getAdminRole, hasAdminPermission } from '@/utils/admin-auth'
import {
WORKER_PLATFORM_TAB_QUERY_KEYS as TAB_QUERY_KEYS,
isWorkerPlatformTab,
} from '@/utils/admin-worker-platform-tabs'
import AfterSalesPanel, { type AfterSalesPanelHandle } from './panels/AfterSalesPanel'
import AnnouncementPanel from './panels/AnnouncementPanel'
import CancelRequestsPanel from './panels/CancelRequestsPanel'
@@ -28,29 +32,6 @@ type AfterSalesLocationState = {
createOrder?: WorkOrder
}
const TAB_QUERY_KEYS: Record<string, string[][]> = {
'consignment-inventory': [['admin-consignment-inventories'], ['admin-consignment-stats']],
'consignment-submissions': [
['admin-consignment-submissions'],
['admin-consignment-submissions-pending-total'],
],
orders: [['admin-work-orders'], ['admin-work-orders-stats']],
'cancel-requests': [['admin-work-order-cancel-requests']],
'after-sales': [['admin-after-sales-orders'], ['admin-after-sales-stats']],
feedbacks: [['admin-feedbacks']],
rules: [['admin-product-rules']],
'product-match': [['admin-product-match']],
categories: [['admin-categories']],
workers: [['admin-workers'], ['admin-worker-users']],
leaderboard: [['admin-leaderboard']],
finance: [['admin-finance-settlements'], ['admin-finance-withdrawals']],
levels: [['admin-worker-levels']],
notifications: [['admin-notifications']],
announcement: [['admin-announcements']],
'hall-config': [['admin-hall-config']],
'risk-control': [['admin-worker-risk-overview'], ['admin-worker-risk-events']],
}
export default function AdminWorkerPlatformPage() {
const queryClient = useQueryClient()
const [searchParams, setSearchParams] = useSearchParams()
@@ -207,49 +188,13 @@ const ACTIVE_TAB_STORAGE_KEY = 'admin-worker-platform-tab'
function loadActiveTabPreference(): string {
const saved = localStorage.getItem(ACTIVE_TAB_STORAGE_KEY)
return saved === 'orders' ||
saved === 'consignment-inventory' ||
saved === 'consignment-submissions' ||
saved === 'leaderboard' ||
saved === 'cancel-requests' ||
saved === 'feedbacks' ||
saved === 'after-sales' ||
saved === 'announcement' ||
saved === 'rules' ||
saved === 'product-match' ||
saved === 'categories' ||
saved === 'workers' ||
saved === 'finance' ||
saved === 'levels' ||
saved === 'notifications'
? saved
: 'orders'
return isWorkerPlatformTab(saved) ? saved : 'orders'
}
function loadActiveTab(tab: string | null): string {
return isWorkerPlatformTab(tab) ? tab : loadActiveTabPreference()
}
function isWorkerPlatformTab(tab: string | null): tab is string {
return [
'orders',
'consignment-inventory',
'consignment-submissions',
'leaderboard',
'cancel-requests',
'feedbacks',
'after-sales',
'announcement',
'rules',
'product-match',
'categories',
'workers',
'finance',
'levels',
'notifications',
].includes(String(tab || ''))
}
function SummaryCards() {
const summaryQuery = useQuery({
queryKey: ['admin-worker-platform-summary'],