新增大厅订单容量控制

This commit is contained in:
yml2213
2026-08-21 14:02:30 +08:00
parent cc03382921
commit 874b093a4b
20 changed files with 407 additions and 44 deletions
@@ -224,6 +224,10 @@ function patchWorkerHallCaches(
queryClient: ReturnType<typeof useQueryClient>,
event: RealtimeEvent,
) {
if (event.operation === 'refresh') {
void queryClient.resetQueries({ queryKey: ['worker-hall-orders'] })
return
}
const workerSnapshot = applyWorkerDepositRule(queryClient, event.data)
const item = workerSnapshot as {
status?: unknown
@@ -11,6 +11,7 @@ import AnnouncementPanel from './panels/AnnouncementPanel'
import CancelRequestsPanel from './panels/CancelRequestsPanel'
import FinancePanel from './panels/FinancePanel'
import FeedbacksPanel from './panels/FeedbacksPanel'
import HallConfigPanel from './panels/HallConfigPanel'
import LevelsPanel from './panels/LevelsPanel'
import NotificationsPanel from './panels/NotificationsPanel'
import ProductRulesPanel from './panels/ProductRulesPanel'
@@ -66,6 +67,7 @@ export default function AdminWorkerPlatformPage() {
{ key: 'workers', label: '打手', children: <WorkersPanel /> },
{ key: 'finance', label: '资金', children: <FinancePanel /> },
{ key: 'levels', label: '等级权限', children: <LevelsPanel /> },
{ key: 'hall', label: '大厅配置', children: <HallConfigPanel /> },
...(isAdmin
? [{ key: 'notifications', label: '通知配置', children: <NotificationsPanel /> }]
: []),
@@ -90,6 +92,7 @@ function loadActiveTabPreference(): string {
saved === 'workers' ||
saved === 'finance' ||
saved === 'levels' ||
saved === 'hall' ||
saved === 'notifications'
? saved
: 'orders'
@@ -111,6 +114,7 @@ function isWorkerPlatformTab(tab: string | null): tab is string {
'workers',
'finance',
'levels',
'hall',
'notifications',
].includes(String(tab || ''))
}
@@ -125,7 +129,11 @@ function SummaryCards() {
const items = [
{ label: '待处理打手', value: summary?.pendingWorkerCount || 0 },
{ label: '待完善订单', value: summary?.pendingMaterialCount || 0 },
{ label: '大厅订单', value: summary?.openOrderCount || 0 },
{
label: '大厅展示',
value: `${summary?.openOrderCount || 0}/${summary?.hallMaxVisibleOrders || 0}`,
},
{ label: '等待入厅', value: summary?.queuedHallOrderCount || 0 },
{ label: '代练中', value: summary?.inProgressOrderCount || 0 },
]
@@ -0,0 +1,67 @@
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { App, Button, Card, Descriptions, Form, InputNumber, Space } from 'antd'
import { useEffect, useState } from 'react'
import { fetchAdminWorkerHallConfig, saveAdminWorkerHallConfig } from '@/services/admin'
type HallConfigFormValues = {
maxVisibleOrders: number
}
export default function HallConfigPanel() {
const { message } = App.useApp()
const queryClient = useQueryClient()
const [form] = Form.useForm<HallConfigFormValues>()
const [saving, setSaving] = useState(false)
const configQuery = useQuery({
queryKey: ['admin-worker-hall-config'],
queryFn: fetchAdminWorkerHallConfig,
})
const config = configQuery.data?.data
useEffect(() => {
if (config) form.setFieldsValue({ maxVisibleOrders: config.maxVisibleOrders })
}, [config, form])
async function saveConfig(values: HallConfigFormValues) {
setSaving(true)
try {
await saveAdminWorkerHallConfig({ maxVisibleOrders: Number(values.maxVisibleOrders) })
await Promise.all([
queryClient.invalidateQueries({ queryKey: ['admin-worker-hall-config'] }),
queryClient.invalidateQueries({ queryKey: ['admin-worker-platform-summary'] }),
])
message.success('大厅配置已保存')
} catch (error) {
message.error(error instanceof Error ? error.message : '保存大厅配置失败')
} finally {
setSaving(false)
}
}
return (
<Card title="大厅配置" bordered={false} loading={configQuery.isLoading}>
<Space direction="vertical" size="middle" style={{ width: '100%', maxWidth: 560 }}>
<Descriptions size="small" column={3}>
<Descriptions.Item label="展示中">{config?.visibleOrderCount || 0}</Descriptions.Item>
<Descriptions.Item label="等待入厅">{config?.queuedOrderCount || 0}</Descriptions.Item>
<Descriptions.Item label="当前上限">{config?.maxVisibleOrders || '-'}</Descriptions.Item>
</Descriptions>
<Form form={form} layout="inline" onFinish={saveConfig}>
<Form.Item
name="maxVisibleOrders"
label="大厅订单总数"
rules={[{ required: true, message: '请输入大厅订单总数' }]}
>
<InputNumber min={1} max={500} precision={0} style={{ width: 160 }} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={saving}>
</Button>
</Form.Item>
</Form>
</Space>
</Card>
)
}
@@ -438,9 +438,11 @@ export default function WorkOrdersPanel() {
return runAction(
() => publishAdminWorkOrder(row.workOrderId),
(response) =>
response.data.voucherConsume.voucherCount > 0
? '电子凭证已自动核销,订单已发布到大厅'
: '订单已发布到大厅',
response.data.hallVisible
? response.data.voucherConsume.voucherCount > 0
? '电子凭证已自动核销,订单已展示在大厅'
: '订单已展示在大厅'
: '订单已进入大厅等待队列',
)
}
@@ -12,6 +12,7 @@ import type {
KuaishouMatchSource,
WorkProductMatchLog,
WorkerFinanceConfig,
WorkerHallConfig,
WorkerFinanceRequest,
WorkerCancelRequest,
WorkerOrderFeedback,
@@ -38,10 +39,20 @@ export function fetchAdminWorkerPlatformSummary() {
pendingWorkerCount: number
pendingMaterialCount: number
openOrderCount: number
queuedHallOrderCount: number
hallMaxVisibleOrders: number
inProgressOrderCount: number
}>('/api/v1/admin/worker-platform/summary')
}
export function fetchAdminWorkerHallConfig() {
return apiGet<WorkerHallConfig>('/api/v1/admin/worker-platform/hall-config')
}
export function saveAdminWorkerHallConfig(payload: Pick<WorkerHallConfig, 'maxVisibleOrders'>) {
return apiPost<WorkerHallConfig>('/api/v1/admin/worker-platform/hall-config', payload)
}
export function fetchAdminWorkerAnnouncement() {
return apiGet<WorkerAnnouncementConfig>('/api/v1/admin/worker-platform/announcement')
}
@@ -454,6 +465,7 @@ export function publishAdminWorkOrder(workOrderId: number) {
return apiPost<{
order: WorkOrder
voucherConsume: WorkOrderVoucherConsumeResult
hallVisible: boolean
}>(`/api/v1/admin/worker-platform/orders/${workOrderId}/publish`)
}
@@ -199,6 +199,12 @@ export type WorkerAnnouncementConfig = {
content: string
}
export type WorkerHallConfig = {
maxVisibleOrders: number
visibleOrderCount: number
queuedOrderCount: number
}
export type WorkerWithdrawalAccount = {
accountChannel: string
accountName: string