refactor(web): 前端目录重构 — consoles/pages → layouts/features + shared

- consoles/admin/ → layouts/admin-layout/
- consoles/workbench/ → layouts/workbench-layout/ + features/chat/
- pages/ → features/ (dashboard, models, projects, not-found)
- components/ → shared/components/
- hooks/ → shared/hooks/
- utils/ → shared/utils/
- 更新所有 import 路径 (src/web/ + tests/web/)
- 更新开发文档 (README.md, frontend.md, architecture.md)
This commit is contained in:
2026-06-02 23:17:28 +08:00
parent 1f05f259d0
commit b1dec691e9
76 changed files with 249 additions and 111 deletions

View File

@@ -0,0 +1,190 @@
import { Space } from "antd";
import { useState } from "react";
import type { Model, Provider, TestModelRequest } from "../../../shared/api";
import {
useCreateModel,
useDeleteModel,
useModelList,
useTestModelConnection,
useUpdateModel,
} from "../../shared/hooks/use-models";
import {
useCreateProvider,
useDeleteProvider,
useProviderList,
useProviderOptions,
useTestProviderConfig,
useUpdateProvider,
} from "../../shared/hooks/use-providers";
import { ModelFormModal } from "./components/ModelFormModal";
import { ModelsToolbar } from "./components/ModelsToolbar";
import { ModelTable } from "./components/ModelTable";
import { ProviderFormModal } from "./components/ProviderFormModal";
import { ProviderTable } from "./components/ProviderTable";
export function ModelsPage() {
const [activeTab, setActiveTab] = useState<string>("models");
const [providerPage, setProviderPage] = useState(1);
const [providerPageSize, setProviderPageSize] = useState(20);
const [providerKeyword, setProviderKeyword] = useState("");
const [providerDialogOpen, setProviderDialogOpen] = useState(false);
const [editingProvider, setEditingProvider] = useState<null | Provider>(null);
const [modelPage, setModelPage] = useState(1);
const [modelPageSize, setModelPageSize] = useState(20);
const [modelKeyword, setModelKeyword] = useState("");
const [modelDialogOpen, setModelDialogOpen] = useState(false);
const [editingModel, setEditingModel] = useState<Model | null>(null);
const { data: providerData, isLoading: providerLoading } = useProviderList({
keyword: providerKeyword || undefined,
page: providerPage,
pageSize: providerPageSize,
});
const {
data: providerOptionsData,
error: providerOptionsError,
isError: providerOptionsIsError,
isLoading: providerOptionsLoading,
} = useProviderOptions();
const { data: modelData, isLoading: modelLoading } = useModelList({
keyword: modelKeyword || undefined,
page: modelPage,
pageSize: modelPageSize,
});
const createProviderMutation = useCreateProvider();
const updateProviderMutation = useUpdateProvider();
const deleteProviderMutation = useDeleteProvider();
const testProviderConfigMutation = useTestProviderConfig();
const createModelMutation = useCreateModel();
const updateModelMutation = useUpdateModel();
const deleteModelMutation = useDeleteModel();
const testModelMutation = useTestModelConnection();
const isProviderSubmitting = createProviderMutation.isPending || updateProviderMutation.isPending;
const isProviderActionPending = deleteProviderMutation.isPending;
const isModelSubmitting = createModelMutation.isPending || updateModelMutation.isPending;
const isModelActionPending = deleteModelMutation.isPending;
const modelProviders = providerOptionsData?.items ?? [];
const currentKeyword = activeTab === "providers" ? providerKeyword : modelKeyword;
const handleSearch =
activeTab === "providers"
? (value: string) => {
setProviderKeyword(value);
setProviderPage(1);
}
: (value: string) => {
setModelKeyword(value);
setModelPage(1);
};
const handleSearchClear =
activeTab === "providers"
? () => {
setProviderKeyword("");
setProviderPage(1);
}
: () => {
setModelKeyword("");
setModelPage(1);
};
const handleOpenCreate =
activeTab === "providers"
? () => {
setEditingProvider(null);
setProviderDialogOpen(true);
}
: () => {
setEditingModel(null);
setModelDialogOpen(true);
};
return (
<Space className="app-page-flex" orientation="vertical" size="large">
<ModelsToolbar
activeTab={activeTab}
key={activeTab}
keyword={currentKeyword}
onSearch={handleSearch}
onSearchClear={handleSearchClear}
onTabChange={(key) => setActiveTab(key)}
openCreateDialog={handleOpenCreate}
/>
{activeTab === "providers" && (
<>
<ProviderTable
data={providerData}
loading={providerLoading || isProviderActionPending}
onDelete={(id) => deleteProviderMutation.mutateAsync(id)}
onEdit={(provider) => {
setEditingProvider(provider);
setProviderDialogOpen(true);
}}
onPageChange={(p, ps) => {
setProviderPage(p);
setProviderPageSize(ps);
}}
page={providerPage}
pageSize={providerPageSize}
/>
<ProviderFormModal
editingProvider={editingProvider}
onCancel={() => setProviderDialogOpen(false)}
onCreate={(data) => createProviderMutation.mutateAsync(data)}
onOpenChange={setProviderDialogOpen}
onTest={(data) => testProviderConfigMutation.mutateAsync(data)}
onUpdate={(args) => updateProviderMutation.mutateAsync(args)}
open={providerDialogOpen}
submitting={isProviderSubmitting}
/>
</>
)}
{activeTab === "models" && (
<>
<ModelTable
data={modelData}
loading={modelLoading || providerOptionsLoading || isModelActionPending}
onDelete={(id) => deleteModelMutation.mutateAsync(id)}
onEdit={(model) => {
setEditingModel(model);
setModelDialogOpen(true);
}}
onPageChange={(p, ps) => {
setModelPage(p);
setModelPageSize(ps);
}}
page={modelPage}
pageSize={modelPageSize}
providers={modelProviders}
/>
<ModelFormModal
editingModel={editingModel}
onCancel={() => setModelDialogOpen(false)}
onCreate={(data) => createModelMutation.mutateAsync(data)}
onOpenChange={setModelDialogOpen}
onUpdate={(args) => updateModelMutation.mutateAsync(args)}
open={modelDialogOpen}
providers={modelProviders}
providersError={providerOptionsIsError ? providerOptionsError : null}
providersLoading={providerOptionsLoading}
submitting={isModelSubmitting}
testModelConnection={(data: TestModelRequest) => testModelMutation.mutateAsync(data)}
/>
</>
)}
</Space>
);
}