import { useQuery, useQueryClient } from '@tanstack/react-query' import { UploadOutlined } from '@ant-design/icons' import { App, Avatar, Button, Card, Descriptions, Form, Input, InputNumber, Space, Switch, Table, Tag, Upload, } from 'antd' import { useEffect, useMemo, useState } from 'react' import { fetchAdminWorkCategories, fetchAdminWorkerHallConfig, saveAdminWorkerHallConfig, } from '@/services/admin' import { uploadFile } from '@/services/files' import type { WorkCategory } from '@/types/worker-platform' type HallConfigFormValues = { maxVisibleOrders: number showSubcategories: boolean allIconUrl?: string categoryMaxVisibleOrders: Record } export default function HallConfigPanel() { const { message } = App.useApp() const queryClient = useQueryClient() const [form] = Form.useForm() const [saving, setSaving] = useState(false) const [uploadingAllIcon, setUploadingAllIcon] = useState(false) const currentAllIconUrl = Form.useWatch('allIconUrl', form) const configQuery = useQuery({ queryKey: ['admin-worker-hall-config'], queryFn: fetchAdminWorkerHallConfig, }) const config = configQuery.data?.data useEffect(() => { if (config) { form.setFieldsValue({ maxVisibleOrders: config.maxVisibleOrders, showSubcategories: config.showSubcategories ?? true, allIconUrl: config.allIconUrl || '', categoryMaxVisibleOrders: config.categoryMaxVisibleOrders || {}, }) } }, [config, form]) const categoriesQuery = useQuery({ queryKey: ['admin-worker-platform-categories'], queryFn: fetchAdminWorkCategories, }) const treeData = useMemo(() => { const rawCategories = categoriesQuery.data?.data.items || [] const rootCategories = rawCategories.filter((item) => !item.parentId) const childrenMap = new Map() for (const item of rawCategories) { if (item.parentId) { const list = childrenMap.get(item.parentId) || [] list.push(item) childrenMap.set(item.parentId, list) } } return rootCategories.map((root) => { const children = childrenMap.get(root.categoryId) || [] return { ...root, children: children.length > 0 ? children : undefined, } }) }, [categoriesQuery.data?.data.items]) async function handleUploadAllIcon(file: File) { setUploadingAllIcon(true) try { const uploaded = await uploadFile(file, 'hall_icon', 'admin') form.setFieldValue('allIconUrl', uploaded.url) message.success('「全部」图标上传成功') } catch (error) { message.error(error instanceof Error ? error.message : '图标上传失败') } finally { setUploadingAllIcon(false) } return false } async function saveConfig(values: HallConfigFormValues) { setSaving(true) try { await saveAdminWorkerHallConfig({ maxVisibleOrders: Number(values.maxVisibleOrders), showSubcategories: Boolean(values.showSubcategories), allIconUrl: values.allIconUrl ? String(values.allIconUrl).trim() : null, categoryMaxVisibleOrders: values.categoryMaxVisibleOrders || {}, }) 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 ( {config?.visibleOrderCount || 0} {config?.queuedOrderCount || 0} {config?.maxVisibleOrders || '-'}
{currentAllIconUrl ? ( ) : null}
分类最多展示上限 一级分类限额将限制该游戏及旗下所有子分类的总单量;二级分类可单独设置细化限额。
rowKey="categoryId" size="small" pagination={false} loading={categoriesQuery.isLoading} dataSource={treeData} defaultExpandAllRows columns={[ { title: '分类名称', dataIndex: 'name', render: (_, category) => ( {category.iconUrl ? ( ) : null} {category.name} {category.parentId ? ( 二级 ) : ( 一级 )} ), }, { title: '状态', width: 90, render: (_, category) => ( {category.status === 'active' ? '启用' : '停用'} ), }, { title: '最多展示', width: 180, render: (_, category) => ( ), }, ]} />
) }