feat: 完成前端重构,采用 Ant Design 5 和完整测试体系
- 采用 Ant Design 5 作为 UI 组件库,替换自定义组件 - 集成 React Router v7 提供路由导航 - 使用 TanStack Query v5 管理数据获取和缓存 - 建立 Vitest + React Testing Library 测试体系 - 添加 Playwright E2E 测试覆盖 - 使用 MSW mock API 响应 - 配置 TypeScript strict 模式 - 采用 SCSS Modules 组织样式 - 更新 OpenSpec 规格以反映前端架构变更 - 归档 frontend-refactor 变更记录
This commit is contained in:
101
frontend/src/pages/Providers/index.tsx
Normal file
101
frontend/src/pages/Providers/index.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { useState } from 'react';
|
||||
import type { Provider, Model, UpdateProviderInput, UpdateModelInput } from '@/types';
|
||||
import { useProviders, useCreateProvider, useUpdateProvider, useDeleteProvider } from '@/hooks/useProviders';
|
||||
import { useCreateModel, useUpdateModel } from '@/hooks/useModels';
|
||||
import { ProviderTable } from './ProviderTable';
|
||||
import { ProviderForm } from './ProviderForm';
|
||||
import { ModelForm } from './ModelForm';
|
||||
|
||||
export function ProvidersPage() {
|
||||
const { data: providers = [], isLoading } = useProviders();
|
||||
const createProvider = useCreateProvider();
|
||||
const updateProvider = useUpdateProvider();
|
||||
const deleteProvider = useDeleteProvider();
|
||||
const createModel = useCreateModel();
|
||||
const updateModel = useUpdateModel();
|
||||
|
||||
const [providerFormOpen, setProviderFormOpen] = useState(false);
|
||||
const [editingProvider, setEditingProvider] = useState<Provider | undefined>();
|
||||
const [modelFormOpen, setModelFormOpen] = useState(false);
|
||||
const [editingModel, setEditingModel] = useState<Model | undefined>();
|
||||
const [modelFormProviderId, setModelFormProviderId] = useState('');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>供应商管理</h1>
|
||||
|
||||
<ProviderTable
|
||||
providers={providers}
|
||||
loading={isLoading}
|
||||
onAdd={() => {
|
||||
setEditingProvider(undefined);
|
||||
setProviderFormOpen(true);
|
||||
}}
|
||||
onEdit={(provider) => {
|
||||
setEditingProvider(provider);
|
||||
setProviderFormOpen(true);
|
||||
}}
|
||||
onDelete={(id) => deleteProvider.mutate(id)}
|
||||
onAddModel={(providerId) => {
|
||||
setEditingModel(undefined);
|
||||
setModelFormProviderId(providerId);
|
||||
setModelFormOpen(true);
|
||||
}}
|
||||
onEditModel={(model) => {
|
||||
setEditingModel(model);
|
||||
setModelFormProviderId(model.providerId);
|
||||
setModelFormOpen(true);
|
||||
}}
|
||||
/>
|
||||
|
||||
<ProviderForm
|
||||
open={providerFormOpen}
|
||||
provider={editingProvider}
|
||||
loading={createProvider.isPending || updateProvider.isPending}
|
||||
onSave={(values) => {
|
||||
if (editingProvider) {
|
||||
const input: Partial<UpdateProviderInput> = {};
|
||||
if (values.name !== editingProvider.name) input.name = values.name;
|
||||
if (values.apiKey) input.apiKey = values.apiKey;
|
||||
if (values.baseUrl !== editingProvider.baseUrl) input.baseUrl = values.baseUrl;
|
||||
if (values.enabled !== editingProvider.enabled) input.enabled = values.enabled;
|
||||
updateProvider.mutate(
|
||||
{ id: editingProvider.id, input },
|
||||
{ onSuccess: () => setProviderFormOpen(false) },
|
||||
);
|
||||
} else {
|
||||
createProvider.mutate(values, {
|
||||
onSuccess: () => setProviderFormOpen(false),
|
||||
});
|
||||
}
|
||||
}}
|
||||
onCancel={() => setProviderFormOpen(false)}
|
||||
/>
|
||||
|
||||
<ModelForm
|
||||
open={modelFormOpen}
|
||||
model={editingModel}
|
||||
providerId={modelFormProviderId}
|
||||
providers={providers}
|
||||
loading={createModel.isPending || updateModel.isPending}
|
||||
onSave={(values) => {
|
||||
if (editingModel) {
|
||||
const input: Partial<UpdateModelInput> = {};
|
||||
if (values.providerId !== editingModel.providerId) input.providerId = values.providerId;
|
||||
if (values.modelName !== editingModel.modelName) input.modelName = values.modelName;
|
||||
if (values.enabled !== editingModel.enabled) input.enabled = values.enabled;
|
||||
updateModel.mutate(
|
||||
{ id: editingModel.id, input },
|
||||
{ onSuccess: () => setModelFormOpen(false) },
|
||||
);
|
||||
} else {
|
||||
createModel.mutate(values, {
|
||||
onSuccess: () => setModelFormOpen(false),
|
||||
});
|
||||
}
|
||||
}}
|
||||
onCancel={() => setModelFormOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user