// ============================================================ // ModelSelector — 模型选择器(垂直单选列表,按类别分组) // 使用 useModelList() Hook 获取数据,组件仅负责渲染 // ============================================================ import { useMemo } from 'react'; import { Menu, Spin, Empty, Tag, Typography, theme as antTheme } from 'antd'; import { AppstoreOutlined } from '@ant-design/icons'; import { useModelList, MODEL_CATEGORY_LABELS } from '@/hooks/use-api'; import { useHomeContext } from '@/contexts/home-context'; import type { ModelCategory } from '@/services/modules'; const { Text } = Typography; // ---------- 组件 ---------- export function ModelSelector() { const { token } = antTheme.useToken(); const { selectedModel, setSelectedModel } = useHomeContext(); const { data: models, loading, groupedModels } = useModelList(); // 构建 Menu items:分组标题 + 模型项 const menuItems = useMemo(() => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const items: any[] = []; groupedModels.forEach((groupModels, category) => { const categoryLabel = MODEL_CATEGORY_LABELS[category as ModelCategory] || category; items.push({ key: `group-${category}`, label: ( {categoryLabel} ({groupModels.length}) ), type: 'group' as const, children: groupModels.map((model) => ({ key: model.id, label: (
{model.name} {model.status !== 'active' && ( {model.status === 'maintenance' ? '维护' : '停用'} )}
), })), }); }); return items; }, [groupedModels, token.colorTextSecondary]); // 选中菜单项 const handleSelect = ({ key }: { key: string }) => { const model = models?.find((m) => m.id === key); if (model) { setSelectedModel(model); } }; // 加载态 if (loading) { return (
); } // 空态 if (!models || models.length === 0) { return ; } // 选中 key const selectedKeys = selectedModel ? [selectedModel.id] : []; return (
选择模型
); }