change settings page and add ratio task detail page (#77)

* feat: Update site name to DataMate and refine text for AI data processing

* feat: Refactor settings page and implement model access functionality

- Created a new ModelAccess component for managing model configurations.
- Removed the old Settings component and replaced it with a new SettingsPage component that integrates ModelAccess, SystemConfig, and WebhookConfig.
- Added SystemConfig component for managing system settings.
- Implemented WebhookConfig component for managing webhook configurations.
- Updated API functions for model management in settings.apis.ts.
- Adjusted routing to point to the new SettingsPage component.

* feat: Implement Data Collection Page with Task Management and Execution Log

- Created DataCollectionPage component to manage data collection tasks.
- Added TaskManagement and ExecutionLog components for task handling and logging.
- Integrated task operations including start, stop, edit, and delete functionalities.
- Implemented filtering and searching capabilities in task management.
- Introduced SimpleCronScheduler for scheduling tasks with cron expressions.
- Updated CreateTask component to utilize new scheduling and template features.
- Enhanced BasicInformation component to conditionally render fields based on visibility settings.
- Refactored ImportConfiguration component to remove NAS import section.

* feat: Update task creation API endpoint and enhance task creation form with new fields and validation

* Refactor file upload and operator management components

- Removed unnecessary console logs from file download and export functions.
- Added size property to TaskItem interface for better task management.
- Simplified TaskUpload component by utilizing useFileSliceUpload hook for file upload logic.
- Enhanced OperatorPluginCreate component to handle file uploads and parsing more efficiently.
- Updated ConfigureStep component to use Ant Design Form for better data handling and validation.
- Improved PreviewStep component to navigate back to the operator market.
- Added support for additional file types in UploadStep component.
- Implemented delete operator functionality in OperatorMarketPage with confirmation prompts.
- Cleaned up unused API functions in operator.api.ts to streamline the codebase.
- Fixed number formatting utility to handle zero values correctly.

* Refactor Knowledge Generation to Knowledge Base

- Created new API service for Knowledge Base operations including querying, creating, updating, and deleting knowledge bases and files.
- Added constants for Knowledge Base status and type mappings.
- Defined models for Knowledge Base and related files.
- Removed obsolete Knowledge Base creation and home components, replacing them with new implementations under the Knowledge Base structure.
- Updated routing to reflect the new Knowledge Base paths.
- Adjusted menu items to align with the new Knowledge Base terminology.
- Modified ModelAccess interface to include modelName and type properties.

* feat: Implement Knowledge Base Page with CRUD operations and data management

- Added KnowledgeBasePage component for displaying and managing knowledge bases.
- Integrated search and filter functionalities with SearchControls component.
- Implemented CreateKnowledgeBase component for creating and editing knowledge bases.
- Enhanced AddDataDialog for file uploads and dataset selections.
- Introduced TableTransfer component for managing data transfers between tables.
- Updated API functions for knowledge base operations, including file management.
- Refactored knowledge base model to include file status and metadata.
- Adjusted routing to point to the new KnowledgeBasePage.

* feat: enhance OperatorPluginCreate and ConfigureStep for better upload handling and UI updates

* refactor: remove unused components and clean up API logging in KnowledgeBase

* feat: update icons in various components and improve styling for better UI consistency

* fix: adjust upload step handling and improve error display in configuration step

* feat: Add RatioTransfer component for dataset selection and configuration

- Implemented RatioTransfer component to manage dataset selection and ratio configuration.
- Integrated dataset fetching with search and filter capabilities.
- Added RatioConfig component for displaying and updating selected datasets' configurations.
- Enhanced SelectDataset component with improved UI and functionality for dataset selection.
- Updated RatioTasksPage to utilize new ratio task status mapping and improved error handling for task deletion.
- Refactored ratio model and constants for better type safety and clarity.
- Changed Vite configuration to use local backend service for development.

* feat: Add .editorconfig and enhance SystemConfig with table for settings display

* feat: Enhance parameter configuration for range inputs and update default values

* feat: Update site name to DataMate and refine text for AI data processing

* Refactor file upload and operator management components

- Removed unnecessary console logs from file download and export functions.
- Added size property to TaskItem interface for better task management.
- Simplified TaskUpload component by utilizing useFileSliceUpload hook for file upload logic.
- Enhanced OperatorPluginCreate component to handle file uploads and parsing more efficiently.
- Updated ConfigureStep component to use Ant Design Form for better data handling and validation.
- Improved PreviewStep component to navigate back to the operator market.
- Added support for additional file types in UploadStep component.
- Implemented delete operator functionality in OperatorMarketPage with confirmation prompts.
- Cleaned up unused API functions in operator.api.ts to streamline the codebase.
- Fixed number formatting utility to handle zero values correctly.

* Refactor Knowledge Generation to Knowledge Base

- Created new API service for Knowledge Base operations including querying, creating, updating, and deleting knowledge bases and files.
- Added constants for Knowledge Base status and type mappings.
- Defined models for Knowledge Base and related files.
- Removed obsolete Knowledge Base creation and home components, replacing them with new implementations under the Knowledge Base structure.
- Updated routing to reflect the new Knowledge Base paths.
- Adjusted menu items to align with the new Knowledge Base terminology.
- Modified ModelAccess interface to include modelName and type properties.

* feat: Implement Knowledge Base Page with CRUD operations and data management

- Added KnowledgeBasePage component for displaying and managing knowledge bases.
- Integrated search and filter functionalities with SearchControls component.
- Implemented CreateKnowledgeBase component for creating and editing knowledge bases.
- Enhanced AddDataDialog for file uploads and dataset selections.
- Introduced TableTransfer component for managing data transfers between tables.
- Updated API functions for knowledge base operations, including file management.
- Refactored knowledge base model to include file status and metadata.
- Adjusted routing to point to the new KnowledgeBasePage.

* feat: enhance OperatorPluginCreate and ConfigureStep for better upload handling and UI updates

* feat: update icons in various components and improve styling for better UI consistency

* fix: adjust upload step handling and improve error display in configuration step

* feat: Update site name to DataMate and refine text for AI data processing

* Refactor file upload and operator management components

- Removed unnecessary console logs from file download and export functions.
- Added size property to TaskItem interface for better task management.
- Simplified TaskUpload component by utilizing useFileSliceUpload hook for file upload logic.
- Enhanced OperatorPluginCreate component to handle file uploads and parsing more efficiently.
- Updated ConfigureStep component to use Ant Design Form for better data handling and validation.
- Improved PreviewStep component to navigate back to the operator market.
- Added support for additional file types in UploadStep component.
- Implemented delete operator functionality in OperatorMarketPage with confirmation prompts.
- Cleaned up unused API functions in operator.api.ts to streamline the codebase.
- Fixed number formatting utility to handle zero values correctly.

* Refactor Knowledge Generation to Knowledge Base

- Created new API service for Knowledge Base operations including querying, creating, updating, and deleting knowledge bases and files.
- Added constants for Knowledge Base status and type mappings.
- Defined models for Knowledge Base and related files.
- Removed obsolete Knowledge Base creation and home components, replacing them with new implementations under the Knowledge Base structure.
- Updated routing to reflect the new Knowledge Base paths.
- Adjusted menu items to align with the new Knowledge Base terminology.
- Modified ModelAccess interface to include modelName and type properties.

* feat: Implement Knowledge Base Page with CRUD operations and data management

- Added KnowledgeBasePage component for displaying and managing knowledge bases.
- Integrated search and filter functionalities with SearchControls component.
- Implemented CreateKnowledgeBase component for creating and editing knowledge bases.
- Enhanced AddDataDialog for file uploads and dataset selections.
- Introduced TableTransfer component for managing data transfers between tables.
- Updated API functions for knowledge base operations, including file management.
- Refactored knowledge base model to include file status and metadata.
- Adjusted routing to point to the new KnowledgeBasePage.

* feat: enhance OperatorPluginCreate and ConfigureStep for better upload handling and UI updates

* feat: update icons in various components and improve styling for better UI consistency

* fix: adjust upload step handling and improve error display in configuration step

* feat: add settings drawer and integrate SettingsPage component

* feat: add ratio task management features including detail view and API integration
This commit is contained in:
chenghh-9609
2025-11-12 17:23:24 +08:00
committed by GitHub
parent 2b09c7dfd1
commit 442e561817
11 changed files with 707 additions and 113 deletions

View File

@@ -1,5 +1,5 @@
import { memo, useEffect, useState } from "react";
import { Button, Menu, Popover } from "antd";
import { Button, Drawer, Menu, Popover } from "antd";
import {
CloseOutlined,
MenuOutlined,
@@ -9,6 +9,7 @@ import { ClipboardList, Sparkles, X } from "lucide-react";
import { menuItems } from "@/pages/Layout/menu";
import { NavLink, useLocation, useNavigate } from "react-router";
import TaskUpload from "./TaskUpload";
import SettingsPage from "../SettingsPage/SettingsPage";
const AsiderAndHeaderLayout = () => {
const { pathname } = useLocation();
@@ -16,6 +17,7 @@ const AsiderAndHeaderLayout = () => {
const [activeItem, setActiveItem] = useState<string>("");
const [sidebarOpen, setSidebarOpen] = useState(true);
const [taskCenterVisible, setTaskCenterVisible] = useState(false);
const [settingVisible, setSettingVisible] = useState(false);
// Initialize active item based on current pathname
const initActiveItem = () => {
@@ -137,11 +139,8 @@ const AsiderAndHeaderLayout = () => {
</Popover>
<Button
block
color={pathname === "/data/settings" ? "primary" : "default"}
variant={pathname === "/data/settings" ? "filled" : "outlined"}
onClick={() => {
setActiveItem("");
navigate("/data/settings");
setSettingVisible(true);
}}
>
@@ -167,11 +166,8 @@ const AsiderAndHeaderLayout = () => {
</div>
<Button
block
color={pathname === "/data/settings" ? "primary" : "default"}
variant={pathname === "/data/settings" ? "filled" : "outlined"}
onClick={() => {
setActiveItem("");
navigate("/data/settings");
setSettingVisible(true);
}}
>
<SettingOutlined />
@@ -179,7 +175,17 @@ const AsiderAndHeaderLayout = () => {
</div>
)}
</div>
<Drawer
title="设置"
placement="bottom"
width="100%"
height="100%"
open={settingVisible}
onClose={() => setSettingVisible(false)}
bodyStyle={{ padding: 0 }}
>
<SettingsPage></SettingsPage>
</Drawer>
{/* 添加遮罩层,点击外部区域时关闭 */}
{taskCenterVisible && (
<div

View File

@@ -1,6 +1,6 @@
import {Alert, Input, Form} from "antd";
import { Alert, Input, Form } from "antd";
import TextArea from "antd/es/input/TextArea";
import React, {useEffect} from "react";
import React, { useEffect } from "react";
import ParamConfig from "@/pages/DataCleansing/Create/components/ParamConfig.tsx";
export default function ConfigureStep({
@@ -22,14 +22,14 @@ export default function ConfigureStep({
setParsedInfo((op) =>
op.id === operatorId
? {
...op,
overrides: {
...(op?.overrides || op?.defaultParams),
[paramKey]: value,
},
}
...op,
overrides: {
...(op?.overrides || op?.defaultParams),
[paramKey]: value,
},
}
: op
)
);
};
return (
@@ -52,32 +52,40 @@ export default function ConfigureStep({
layout="vertical"
initialValues={parsedInfo}
onValuesChange={(_, allValues) => {
setParsedInfo({...parsedInfo, ...allValues});
setParsedInfo({ ...parsedInfo, ...allValues });
}}
>
{/* 基本信息 */}
<h3 className="text-lg font-semibold text-gray-900"></h3>
<Form.Item label="ID" name="id" rules={[{required: true}]}>
<Input value={parsedInfo.id} readOnly/>
<Form.Item label="ID" name="id" rules={[{ required: true }]}>
<Input value={parsedInfo.id} readOnly />
</Form.Item>
<Form.Item label="名称" name="name" rules={[{required: true}]}>
<Input value={parsedInfo.name}/>
<Form.Item label="名称" name="name" rules={[{ required: true }]}>
<Input value={parsedInfo.name} />
</Form.Item>
<Form.Item label="版本" name="version" rules={[{required: true}]}>
<Input value={parsedInfo.version}/>
<Form.Item label="版本" name="version" rules={[{ required: true }]}>
<Input value={parsedInfo.version} />
</Form.Item>
<Form.Item
label="描述"
name="description"
rules={[{required: false}]}
rules={[{ required: false }]}
>
<TextArea value={parsedInfo.description}/>
<TextArea value={parsedInfo.description} />
</Form.Item>
<Form.Item label="输入类型" name="inputs" rules={[{required: true}]}>
<Input value={parsedInfo.inputs}/>
<Form.Item
label="输入类型"
name="inputs"
rules={[{ required: true }]}
>
<Input value={parsedInfo.inputs} />
</Form.Item>
<Form.Item label="输出类型" name="outputs" rules={[{required: true}]}>
<Input value={parsedInfo.outputs}/>
<Form.Item
label="输出类型"
name="outputs"
rules={[{ required: true }]}
>
<Input value={parsedInfo.outputs} />
</Form.Item>
{parsedInfo.configs && Object.keys(parsedInfo.configs).length > 0 && (
@@ -85,19 +93,17 @@ export default function ConfigureStep({
<h3 className="text-lg font-semibold text-gray-900 mt-10 mb-2">
</h3>
<div className="border p-4 rounded-lg grid grid-cols-2 gap-4">
<Form layout="vertical">
{Object.entries(parsedInfo?.configs).map(([key, param]) =>
<ParamConfig
key={key}
operator={parsedInfo}
paramKey={key}
param={param}
onParamChange={handleConfigChange}
/>
)}
</Form>
</div>
<Form layout="vertical">
{Object.entries(parsedInfo?.configs).map(([key, param]) => (
<ParamConfig
key={key}
operator={parsedInfo}
paramKey={key}
param={param}
onParamChange={handleConfigChange}
/>
))}
</Form>
</>
)}

View File

@@ -0,0 +1,312 @@
import { useEffect, useMemo, useState, useCallback } from "react";
import {
Breadcrumb,
App,
Tabs,
Button,
Card,
Progress,
Badge,
Descriptions,
DescriptionsProps,
} from "antd";
import { ReloadOutlined, DeleteOutlined } from "@ant-design/icons";
import DetailHeader from "@/components/DetailHeader";
import { Link, useNavigate, useParams } from "react-router";
import {
getRatioTaskByIdUsingGet,
deleteRatioTasksUsingDelete,
} from "@/pages/RatioTask/ratio.api";
import { post } from "@/utils/request";
import type { RatioTaskItem } from "@/pages/RatioTask/ratio.model";
import { mapRatioTask } from "../ratio.const";
import { Copy, Pause, PlayIcon } from "lucide-react";
const tabList = [
{
key: "overview",
label: "概览",
},
{
key: "analysis",
label: "配比分析",
},
{
key: "config",
label: "配比配置",
},
];
export default function RatioTaskDetail() {
const { id } = useParams();
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState("overview");
const { message } = App.useApp();
const [ratioTask, setRatioTask] = useState<RatioTaskItem>(
{} as RatioTaskItem
);
const navigateItems = useMemo(
() => [
{
title: <Link to="/data/synthesis/ratio-task"></Link>,
},
{
title: ratioTask.name || "配比任务详情",
},
],
[ratioTask]
);
const fetchRatioTask = useCallback(async () => {
const { data } = await getRatioTaskByIdUsingGet(id as string);
setRatioTask(mapRatioTask(data));
}, [id]);
useEffect(() => {
fetchRatioTask();
}, []);
const handleRefresh = useCallback(
async (showMessage = true) => {
await fetchRatioTask();
if (showMessage) message.success({ content: "任务数据刷新成功" });
},
[fetchRatioTask, message]
);
const handleDelete = async () => {
await deleteRatioTasksUsingDelete(id as string);
navigate("/ratio/task");
message.success("配比任务删除成功");
};
const handleExecute = async () => {
await post(`/api/synthesis/ratio-task/${id}/execute`);
handleRefresh();
message.success("任务已启动");
};
const handleStop = async () => {
await post(`/api/synthesis/ratio-task/${id}/stop`);
handleRefresh();
message.success("任务已停止");
};
useEffect(() => {
const refreshData = () => {
handleRefresh(false);
};
window.addEventListener("update:ratio-task", refreshData);
return () => {
window.removeEventListener("update:ratio-task", refreshData);
};
}, [handleRefresh]);
// 操作列表
const operations = [
{
key: "execute",
label: "启动",
icon: <PlayIcon className="w-4 h-4 text-gray-500" />,
onClick: handleExecute,
disabled: ratioTask.status === "RUNNING",
},
{
key: "stop",
label: "停止",
icon: <Pause className="w-4 h-4 text-gray-500" />,
onClick: handleStop,
disabled: ratioTask.status !== "RUNNING",
},
{
key: "refresh",
label: "刷新",
icon: <ReloadOutlined />,
onClick: handleRefresh,
},
{
key: "delete",
label: "删除",
danger: true,
confirm: {
title: "确认删除该配比任务?",
description: "删除后该任务将无法恢复,请谨慎操作。",
okText: "删除",
cancelText: "取消",
okType: "danger",
},
icon: <DeleteOutlined />,
onClick: handleDelete,
},
];
// 基本信息
const items: DescriptionsProps["items"] = [
{
key: "id",
label: "ID",
children: ratioTask.id,
},
{
key: "name",
label: "名称",
children: ratioTask.name,
},
{
key: "dataset",
label: "目标数据集",
children: (
<Link to={`/data/management/detail/${ratioTask.target_dataset_id}`}>
{ratioTask.target_dataset_name}
</Link>
),
},
{
key: "status",
label: "数据大小",
children: (
<Badge color={ratioTask.status?.color} text={ratioTask.status?.label} />
),
},
{
key: "type",
label: "类型",
children: ratioTask.type || "未知",
},
{
key: "status",
label: "状态",
children: ratioTask?.status?.label || "未知",
},
{
key: "createdBy",
label: "创建者",
children: ratioTask.createdBy || "未知",
},
{
key: "targetLocation",
label: "输出路径",
children: ratioTask.targetLocation || "未知",
},
{
key: "createdAt",
label: "创建时间",
children: ratioTask.createdAt,
},
{
key: "updatedAt",
label: "更新时间",
children: ratioTask.updatedAt,
},
{
key: "description",
label: "描述",
children: ratioTask.description || "无",
},
];
return (
<div className="h-full flex flex-col gap-4">
<Breadcrumb items={navigateItems} />
{/* Header */}
<DetailHeader
data={ratioTask}
statistics={ratioTask?.statistics || []}
operations={operations}
/>
<div className="flex-overflow-auto p-6 pt-2 bg-white rounded-md shadow">
<Tabs activeKey={activeTab} items={tabList} onChange={setActiveTab} />
<div className="h-full overflow-auto">
{activeTab === "overview" && (
<>
<Descriptions
title="基本信息"
layout="vertical"
size="small"
items={items}
column={5}
/>
<h2 className="text-base font-semibold mt-8 mb-4"></h2>
<div className="grid grid-cols-2 gap-4">
{/* 目标配比 */}
<Card title="目标配比">
<div className="space-y-4">
{ratioTask.targetRatio &&
Object.entries(ratioTask.targetRatio).map(
([category, ratio]) => (
<div key={category} className="space-y-2">
<div className="flex justify-between items-center">
<span className="text-sm font-medium text-gray-700">
{category}
</span>
<span className="text-sm font-semibold text-blue-600">
{ratioTask.ratio}%
</span>
</div>
<Progress value={ratio} className="h-2" />
</div>
)
)}
</div>
</Card>
{/* 当前配比 */}
<Card title="当前配比">
<div className="space-y-4">
{ratioTask.currentRatio &&
Object.entries(ratioTask.currentRatio).length > 0 ? (
Object.entries(ratioTask.currentRatio)?.map(
([category, ratio]) => (
<div key={category} className="space-y-2">
<div className="flex justify-between items-center">
<span className="text-sm font-medium text-gray-700">
{category}
</span>
<span className="text-sm font-semibold text-green-600">
{ratioTask.ratio}%
</span>
</div>
<Progress value={ratio} className="h-2" />
</div>
)
)
) : (
<p className="text-sm text-gray-500"></p>
)}
</div>
</Card>
</div>
</>
)}
{activeTab === "analysis" && (
<div className="text-center py-20 text-gray-500">
</div>
)}
{activeTab === "config" && (
<div className="bg-gray-50 rounded-lg p-4 font-mono text-xs overflow-x-auto">
<pre className="text-gray-700 whitespace-pre-wrap break-words">
{JSON.stringify(
{
id: ratioTask.id,
name: ratioTask.name,
type: ratioTask.type,
status: ratioTask.status,
strategy: ratioTask.strategy,
sourceDatasets: ratioTask.sourceDatasets,
targetRatio: ratioTask.targetRatio,
outputPath: ratioTask.outputPath,
createdAt: ratioTask.createdAt,
},
null,
2
)}
</pre>
</div>
)}
</div>
</div>
</div>
);
}

View File

@@ -1,5 +1,5 @@
import { useState } from "react";
import { Button, Card, Table, Tooltip, App } from "antd";
import { Button, Card, Table, App, Badge, Popconfirm } from "antd";
import { Plus } from "lucide-react";
import { DeleteOutlined } from "@ant-design/icons";
import type { RatioTaskItem } from "@/pages/RatioTask/ratio.model";
@@ -11,7 +11,7 @@ import {
queryRatioTasksUsingGet,
} from "../ratio.api";
import useFetchData from "@/hooks/useFetchData";
import { mapRatioTask, ratioTaskStatusMap } from "../ratio.const";
import { mapRatioTask } from "../ratio.const";
export default function RatioTasksPage() {
const { message } = App.useApp();
@@ -68,6 +68,8 @@ export default function RatioTasksPage() {
title: "任务名称",
dataIndex: "name",
key: "name",
width: 200,
fixed: "left" as const,
render: (text: string, record: RatioTaskItem) => (
<a
onClick={() =>
@@ -82,17 +84,28 @@ export default function RatioTasksPage() {
title: "状态",
dataIndex: "status",
key: "status",
render: (status) => ratioTaskStatusMap[status]?.label,
width: 120,
render: (status) => {
return (
<Badge
color={status?.color}
icon={status?.icon}
text={status?.label}
/>
);
},
},
{
title: "配比方式",
dataIndex: "ratio_method",
key: "ratio_method",
width: 120,
},
{
title: "目标数量",
dataIndex: "totals",
key: "totals",
width: 120,
},
{
title: "目标数据集",
@@ -112,21 +125,35 @@ export default function RatioTasksPage() {
title: "创建时间",
dataIndex: "created_at",
key: "created_at",
width: 180,
},
{
title: "操作",
key: "actions",
width: 120,
fixed: "right" as const,
render: (_: any, task: RatioTaskItem) => (
<div className="flex items-center gap-2">
{operations.map((op) => (
<Tooltip key={op.key} title={op.label}>
{operations.map((op) => {
if (op.confirm) {
<Popconfirm
title={op.confirm.title}
description={op.confirm.description}
onConfirm={() => op.onClick(task)}
>
<Button type="text" icon={op.icon} />
</Popconfirm>;
}
return (
<Button
key={op.key}
type="text"
icon={op.icon}
danger={op.danger}
onClick={() => op.onClick(task)}
/>
</Tooltip>
))}
);
})}
</div>
),
},

View File

@@ -1,6 +1,6 @@
import { formatDate } from "@/utils/unit";
import { RatioTaskItem, RatioStatus } from "./ratio.model";
import { BarChart3 } from "lucide-react";
import { BarChart3, Calendar, Database } from "lucide-react";
import { Link } from "react-router";
export const ratioTaskStatusMap: Record<
@@ -9,22 +9,23 @@ export const ratioTaskStatusMap: Record<
value: RatioStatus;
label: string;
color: string;
icon?: React.ReactNode;
}
> = {
[RatioStatus.PENDING]: {
value: RatioStatus.PENDING,
label: "等待中",
color: "blue",
color: "gray",
},
[RatioStatus.RUNNING]: {
value: RatioStatus.RUNNING,
label: "运行中",
color: "green",
color: "blue",
},
[RatioStatus.COMPLETED]: {
value: RatioStatus.COMPLETED,
label: "已完成",
color: "gray",
color: "green",
},
[RatioStatus.FAILED]: {
value: RatioStatus.FAILED,
@@ -41,20 +42,22 @@ export const ratioTaskStatusMap: Record<
export function mapRatioTask(task: Partial<RatioTaskItem>): RatioTaskItem {
return {
...task,
status: ratioTaskStatusMap[task.status || RatioStatus.PENDING]?.value,
status: ratioTaskStatusMap[task.status || RatioStatus.PENDING],
createdAt: formatDate(task.created_at),
updatedAt: formatDate(task.updated_at),
description:
task.ratio_method === "DATASET" ? "按数据集配比" : "按标签配比",
icon: <BarChart3 className="w-6 h-6" />,
icon: <BarChart3 />,
iconColor: task.ratio_method === "DATASET" ? "bg-blue-100" : "bg-green-100",
statistics: [
{
label: "目标数量",
icon: <BarChart3 className="w-4 h-4 text-gray-500" />,
value: (task.totals ?? 0).toLocaleString(),
},
{
label: "目标数据集",
icon: <Database className="w-4 h-4 text-gray-500" />,
value: task.target_dataset_name ? (
<Link to={`/data/management/detail/${task.target_dataset_id}`}>
{task.target_dataset_name}
@@ -65,8 +68,20 @@ export function mapRatioTask(task: Partial<RatioTaskItem>): RatioTaskItem {
},
{
label: "创建时间",
icon: <Calendar className="w-4 h-4 text-gray-500" />,
value: task.created_at || "-",
},
],
type: "balance",
progress: 100,
sourceDatasets: ["sentiment_dataset", "news_classification"],
targetRatio: { 正面: 33, 负面: 33, 中性: 34 },
currentRatio: { 正面: 33, 负面: 33, 中性: 34 },
totalRecords: 15000,
processedRecords: 15000,
estimatedTime: "已完成",
quality: 95,
strategy: "随机下采样",
outputPath: "/data/balanced/sentiment_balanced_20250120",
};
}

View File

@@ -1,60 +1,56 @@
import { useState } from "react";
import { Tabs } from "antd";
import { Button, Menu } from "antd";
import { SettingOutlined, ApiOutlined } from "@ant-design/icons";
import WebhookConfig from "./WebhookConfig";
import ModelAccess from "./ModelAccess";
import { Component, X } from "lucide-react";
import { useNavigate } from "react-router";
import SystemConfig from "./SystemConfig";
import { Component } from "lucide-react";
import ModelAccess from "./ModelAccess";
import WebhookConfig from "./WebhookConfig";
export default function SettingsPage() {
const [activeTab, setActiveTab] = useState("modelAccess");
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState("model-access");
return (
<div className="h-full flex flex-col gap-4">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-xl font-bold text-gray-900"></h1>
<div className="h-screen flex">
<div className="border-right h-full">
{/* <h1 className="min-w-[200px] w-full border-bottom flex gap-2 text-lg font-bold text-gray-900 p-4">
<Button icon={<X />} type="text" onClick={() => navigate(-1)} />
设置中心
</h1> */}
<div className="h-full">
<Menu
mode="inline"
items={[
{
key: "system-config",
icon: <SettingOutlined />,
label: "系统设置",
},
{
key: "model-access",
icon: <Component className="w-4 h-4" />,
label: "模型接入",
},
{
key: "webhook-config",
icon: <ApiOutlined />,
label: "Webhook",
},
]}
selectedKeys={[activeTab]}
onClick={({ key }) => {
setActiveTab(key);
}}
/>
</div>
</div>
{/* Settings Tabs */}
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
items={[
// {
// key: "system",
// label: (
// <span>
// <SettingOutlined className="mr-1" />
// 系统设置
// </span>
// ),
// children: <SystemConfig />,
// },
{
key: "modelAccess",
label: (
<span className="flex items-center">
<Component className="w-4 h-4 mr-1" />
</span>
),
children: <ModelAccess key="modelAccess" />,
},
// {
// key: "webhook",
// label: (
// <span>
// <ApiOutlined className="mr-1" />
// Webhook
// </span>
// ),
// children: <WebhookConfig />,
// },
]}
/>
<div className="flex-1 h-full p-4">
{/* 内容区域,根据 activeTab 渲染不同的组件 */}
{activeTab === "system-config" && <SystemConfig />}
{activeTab === "model-access" && <ModelAccess />}
{activeTab === "webhook-config" && <WebhookConfig />}
</div>
</div>
);
}