refactor: clean up tag management and dataset handling, update API endpoints

This commit is contained in:
chenghh-9609
2025-10-22 14:41:14 +08:00
parent 1c97afed7d
commit b9a7e7a0a9
11 changed files with 106 additions and 135 deletions

View File

@@ -92,17 +92,6 @@ function CustomTag({
); );
} }
export const mockPreparedTags = [
{ id: "1", name: "重要" },
{ id: "2", name: "待处理" },
{ id: "3", name: "已完成" },
{ id: "4", name: "审核中" },
{ id: "5", name: "高优先级" },
{ id: "6", name: "低优先级" },
{ id: "7", name: "客户A" },
{ id: "8", name: "客户B" },
];
const TagManager: React.FC = ({ const TagManager: React.FC = ({
onFetch, onFetch,
onCreate, onCreate,
@@ -112,7 +101,7 @@ const TagManager: React.FC = ({
onFetch: () => Promise<any>; onFetch: () => Promise<any>;
onCreate: (tag: Pick<TagItem, "name">) => Promise<{ ok: boolean }>; onCreate: (tag: Pick<TagItem, "name">) => Promise<{ ok: boolean }>;
onDelete: (tagId: number) => Promise<{ ok: boolean }>; onDelete: (tagId: number) => Promise<{ ok: boolean }>;
onUpdate: (oldTagId: number, newTag: string) => Promise<{ ok: boolean }>; onUpdate: (tag: TagItem) => Promise<{ ok: boolean }>;
}) => { }) => {
const [showTagManager, setShowTagManager] = useState(false); const [showTagManager, setShowTagManager] = useState(false);
const { message } = App.useApp(); const { message } = App.useApp();
@@ -121,9 +110,6 @@ const TagManager: React.FC = ({
const [editingTag, setEditingTag] = useState<string | null>(null); const [editingTag, setEditingTag] = useState<string | null>(null);
const [editingTagValue, setEditingTagValue] = useState(""); const [editingTagValue, setEditingTagValue] = useState("");
// 预置标签
const [preparedTags, setPreparedTags] = useState(mockPreparedTags);
// 获取标签列表 // 获取标签列表
const fetchTags = async () => { const fetchTags = async () => {
if (!onFetch) return; if (!onFetch) return;
@@ -161,7 +147,7 @@ const TagManager: React.FC = ({
const updateTag = async (oldTag: TagItem, newTag: string) => { const updateTag = async (oldTag: TagItem, newTag: string) => {
try { try {
await onUpdate?.(oldTag.id, { ...oldTag, name: newTag }); await onUpdate?.({ ...oldTag, name: newTag });
fetchTags(); fetchTags();
message.success("标签更新成功"); message.success("标签更新成功");
} catch (error) { } catch (error) {
@@ -213,9 +199,8 @@ const TagManager: React.FC = ({
title="标签管理" title="标签管理"
width={500} width={500}
> >
<div className="space-y-4"> <div className="space-y-4 flex flex-col overflow-y-auto h-full">
{/* Add New Tag */} {/* Add New Tag */}
<div className="space-y-2">
<div className="flex gap-2"> <div className="flex gap-2">
<Input <Input
placeholder="输入标签名称..." placeholder="输入标签名称..."
@@ -237,16 +222,9 @@ const TagManager: React.FC = ({
</Button> </Button>
</div> </div>
</div>
<h2 className="font-large font-bold w-full"></h2> <div className="flex-1 overflow-auto">
<div className="grid grid-cols-2 gap-2"> <div className="overflow-auto grid grid-cols-2 gap-2">
{preparedTags.length > 0 &&
preparedTags.map((tag) => <CustomTag key={tag.id} tag={tag} />)}
</div>
<h2 className="font-large font-bold w-full"></h2>
<div className="grid grid-cols-2 gap-2 mt-4">
{tags.map((tag) => ( {tags.map((tag) => (
<CustomTag <CustomTag
isEditable isEditable
@@ -263,6 +241,7 @@ const TagManager: React.FC = ({
))} ))}
</div> </div>
</div> </div>
</div>
</Drawer> </Drawer>
</> </>
); );

View File

@@ -1,5 +1,8 @@
import { queryDatasetsUsingGet } from "@/pages/DataManagement/dataset.api"; import { queryDatasetsUsingGet } from "@/pages/DataManagement/dataset.api";
import { datasetTypeMap } from "@/pages/DataManagement/dataset.const"; import {
datasetTypeMap,
mapDataset,
} from "@/pages/DataManagement/dataset.const";
import { Button, Form, Input, Modal, Select } from "antd"; import { Button, Form, Input, Modal, Select } from "antd";
import TextArea from "antd/es/input/TextArea"; import TextArea from "antd/es/input/TextArea";
import { Database } from "lucide-react"; import { Database } from "lucide-react";
@@ -26,7 +29,7 @@ export default function CreateAnnotationTask({
page: 0, page: 0,
size: 1000, size: 1000,
}); });
setDatasets(data.content || []); setDatasets(data.content.map(mapDataset) || []);
}; };
fetchDatasets(); fetchDatasets();
}, [open]); }, [open]);
@@ -74,22 +77,20 @@ export default function CreateAnnotationTask({
> >
<Select <Select
placeholder="请选择数据集" placeholder="请选择数据集"
options={datasets.map((dataset) => ({ options={datasets.map((dataset) => {
return {
label: ( label: (
<div className="flex items-center justify-between gap-3 py-2"> <div className="flex items-center justify-between gap-3 py-2">
<div className="flex items-center font-sm text-gray-900"> <div className="flex items-center font-sm text-gray-900">
<span> <span className="mr-2">{dataset.icon}</span>
{dataset.icon || <Database className="w-4 h-4 mr-2" />}
</span>
<span>{dataset.name}</span> <span>{dataset.name}</span>
</div> </div>
<div className="text-xs text-gray-500"> <div className="text-xs text-gray-500">{dataset.size}</div>
{datasetTypeMap[dataset?.datasetType]?.label}
</div>
</div> </div>
), ),
value: dataset.id, value: dataset.id,
}))} };
})}
/> />
</Form.Item> </Form.Item>
</Form> </Form>

View File

@@ -19,8 +19,10 @@ import {
import { mapAnnotationTask } from "../annotation.const"; import { mapAnnotationTask } from "../annotation.const";
import CreateAnnotationTask from "../Create/components/CreateAnnptationTaskDialog"; import CreateAnnotationTask from "../Create/components/CreateAnnptationTaskDialog";
import { ColumnType } from "antd/es/table"; import { ColumnType } from "antd/es/table";
import DevelopmentInProgress from "@/components/DevelopmentInProgress";
export default function DataAnnotation() { export default function DataAnnotation() {
return <DevelopmentInProgress />;
const navigate = useNavigate(); const navigate = useNavigate();
const [viewMode, setViewMode] = useState<"list" | "card">("list"); const [viewMode, setViewMode] = useState<"list" | "card">("list");
const [showCreateDialog, setShowCreateDialog] = useState(false); const [showCreateDialog, setShowCreateDialog] = useState(false);

View File

@@ -2,7 +2,7 @@ import { get, post, put, del, download } from "@/utils/request";
// 标注任务管理相关接口 // 标注任务管理相关接口
export function queryAnnotationTasksUsingGet(params?: any) { export function queryAnnotationTasksUsingGet(params?: any) {
return get("/api/project/mappings/list", params); return get("/project/mappings/list", params);
} }
export function createAnnotationTaskUsingPost(data: any) { export function createAnnotationTaskUsingPost(data: any) {

View File

@@ -3,6 +3,7 @@ import { queryDatasetsUsingGet } from "@/pages/DataManagement/dataset.api";
import { import {
datasetTypeMap, datasetTypeMap,
datasetTypes, datasetTypes,
mapDataset,
} from "@/pages/DataManagement/dataset.const"; } from "@/pages/DataManagement/dataset.const";
import { import {
Dataset, Dataset,
@@ -34,7 +35,7 @@ export default function CreateTaskStepOne({
const fetchDatasets = async () => { const fetchDatasets = async () => {
const { data } = await queryDatasetsUsingGet({ page: 0, size: 1000 }); const { data } = await queryDatasetsUsingGet({ page: 0, size: 1000 });
setDatasets(data.content || []); setDatasets(data.content.map(mapDataset) || []);
}; };
useEffect(() => { useEffect(() => {
@@ -76,22 +77,20 @@ export default function CreateTaskStepOne({
<Form.Item label="源数据集" name="srcDatasetId" required> <Form.Item label="源数据集" name="srcDatasetId" required>
<Select <Select
placeholder="请选择源数据集" placeholder="请选择源数据集"
options={datasets.map((dataset) => ({ options={datasets.map((dataset) => {
return {
label: ( label: (
<div className="flex items-center justify-between gap-3 py-2"> <div className="flex items-center justify-between gap-3 py-2">
<div className="flex items-center font-sm text-gray-900"> <div className="flex items-center font-sm text-gray-900">
<span> <span className="mr-2">{dataset.icon}</span>
{dataset.icon || <Database className="w-4 h-4 mr-2" />}
</span>
<span>{dataset.name}</span> <span>{dataset.name}</span>
</div> </div>
<div className="text-xs text-gray-500"> <div className="text-xs text-gray-500">{dataset.size}</div>
{datasetTypeMap[dataset?.datasetType]?.label}
</div>
</div> </div>
), ),
value: dataset.id, value: dataset.id,
}))} };
})}
/> />
</Form.Item> </Form.Item>
<Form.Item label="目标数据集名称" name="destDatasetName" required> <Form.Item label="目标数据集名称" name="destDatasetName" required>

View File

@@ -2,7 +2,6 @@ import RadioCard from "@/components/RadioCard";
import { Input, Select, Form } from "antd"; import { Input, Select, Form } from "antd";
import { datasetTypes } from "../../dataset.const"; import { datasetTypes } from "../../dataset.const";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { mockPreparedTags } from "@/components/TagManagement";
import { queryDatasetTagsUsingGet } from "../../dataset.api"; import { queryDatasetTagsUsingGet } from "../../dataset.api";
export default function BasicInformation({ export default function BasicInformation({
@@ -26,26 +25,11 @@ export default function BasicInformation({
const fetchTags = async () => { const fetchTags = async () => {
try { try {
const { data } = await queryDatasetTagsUsingGet(); const { data } = await queryDatasetTagsUsingGet();
const preparedTags = mockPreparedTags.map((tag) => ({
label: tag.name,
value: tag.name,
}));
const customTags = data.map((tag) => ({ const customTags = data.map((tag) => ({
label: tag.name, label: tag.name,
value: tag.name, value: tag.name,
})); }));
setTagOptions([ setTagOptions(customTags);
{
label: <span></span>,
title: "prepared",
options: preparedTags,
},
{
label: <span></span>,
title: "custom",
options: customTags,
},
]);
} catch (error) { } catch (error) {
console.error("Error fetching tags: ", error); console.error("Error fetching tags: ", error);
} }

View File

@@ -121,7 +121,7 @@ export default function DatasetDetail() {
{ {
icon: <Clock className="text-blue-400 w-4 h-4" />, icon: <Clock className="text-blue-400 w-4 h-4" />,
key: "time", key: "time",
value: dataset?.createdAt, value: dataset?.updatedAt,
}, },
]; ];

View File

@@ -20,8 +20,8 @@ import {
deleteDatasetByIdUsingDelete, deleteDatasetByIdUsingDelete,
createDatasetTagUsingPost, createDatasetTagUsingPost,
queryDatasetTagsUsingGet, queryDatasetTagsUsingGet,
updateDatasetTagByIdUsingPut, deleteDatasetTagUsingDelete,
deleteDatasetTagByIdUsingDelete, updateDatasetTagUsingPut,
} from "../dataset.api"; } from "../dataset.api";
import { formatBytes } from "@/utils/unit"; import { formatBytes } from "@/utils/unit";
import EditDataset from "../Create/EditDataset"; import EditDataset from "../Create/EditDataset";
@@ -295,8 +295,8 @@ export default function DatasetManagementPage() {
{/* tasks */} {/* tasks */}
<TagManager <TagManager
onCreate={createDatasetTagUsingPost} onCreate={createDatasetTagUsingPost}
onDelete={deleteDatasetTagByIdUsingDelete} onDelete={(ids: string) => deleteDatasetTagUsingDelete({ ids })}
onUpdate={updateDatasetTagByIdUsingPut} onUpdate={updateDatasetTagUsingPut}
onFetch={queryDatasetTagsUsingGet} onFetch={queryDatasetTagsUsingGet}
/> />
<Link to="/data/management/create"> <Link to="/data/management/create">

View File

@@ -97,13 +97,13 @@ export function createDatasetTagUsingPost(data: any) {
} }
// 更新数据集标签 // 更新数据集标签
export function updateDatasetTagByIdUsingPut(id: string | number, data: any) { export function updateDatasetTagUsingPut(data: any) {
return put(`/api/data-management/tags/${id}`, data); return put(`/api/data-management/tags`, data);
} }
// 删除数据集标签 // 删除数据集标签
export function deleteDatasetTagByIdUsingDelete(id: string | number) { export function deleteDatasetTagUsingDelete(data: any) {
return del(`/api/data-management/tags/${id}`); return del(`/api/data-management/tags`, data);
} }
// 数据集质量检查 // 数据集质量检查

View File

@@ -23,6 +23,8 @@ import {
Music, Music,
Videotape, Videotape,
Database, Database,
Image,
ScanText,
} from "lucide-react"; } from "lucide-react";
export const datasetTypeMap: Record< export const datasetTypeMap: Record<
@@ -41,8 +43,8 @@ export const datasetTypeMap: Record<
value: DatasetType.TEXT, value: DatasetType.TEXT,
label: "文本", label: "文本",
order: 1, order: 1,
icon: FileText, icon: ScanText,
iconColor: "#3b82f6", iconColor: "blue",
children: [ children: [
DatasetSubType.TEXT_DOCUMENT, DatasetSubType.TEXT_DOCUMENT,
DatasetSubType.TEXT_WEB, DatasetSubType.TEXT_WEB,
@@ -54,8 +56,8 @@ export const datasetTypeMap: Record<
value: DatasetType.IMAGE, value: DatasetType.IMAGE,
label: "图像", label: "图像",
order: 2, order: 2,
icon: FileImage, icon: Image,
iconColor: "#3b82f6", iconColor: "green",
children: [DatasetSubType.IMAGE_IMAGE, DatasetSubType.IMAGE_CAPTION], children: [DatasetSubType.IMAGE_IMAGE, DatasetSubType.IMAGE_CAPTION],
description: "用于处理和分析图像数据的数据集", description: "用于处理和分析图像数据的数据集",
}, },
@@ -64,7 +66,7 @@ export const datasetTypeMap: Record<
label: "音频", label: "音频",
order: 3, order: 3,
icon: Music, icon: Music,
iconColor: "#3b82f6", iconColor: "orange",
children: [DatasetSubType.AUDIO_AUDIO, DatasetSubType.AUDIO_JSONL], children: [DatasetSubType.AUDIO_AUDIO, DatasetSubType.AUDIO_JSONL],
description: "用于处理和分析音频数据的数据集", description: "用于处理和分析音频数据的数据集",
}, },
@@ -73,7 +75,7 @@ export const datasetTypeMap: Record<
label: "视频", label: "视频",
order: 3, order: 3,
icon: Video, icon: Video,
iconColor: "#3b82f6", iconColor: "purple",
children: [DatasetSubType.VIDEO_VIDEO, DatasetSubType.VIDEO_JSONL], children: [DatasetSubType.VIDEO_VIDEO, DatasetSubType.VIDEO_JSONL],
description: "用于处理和分析视频数据的数据集", description: "用于处理和分析视频数据的数据集",
}, },
@@ -193,14 +195,22 @@ export const dataSourceMap: Record<string, { label: string; value: string }> = {
export const dataSourceOptions = Object.values(dataSourceMap); export const dataSourceOptions = Object.values(dataSourceMap);
export function mapDataset(dataset: Dataset) { export function mapDataset(dataset: Dataset) {
const IconComponent = datasetTypeMap[dataset?.datasetType]?.icon || null; const { icon: IconComponent, iconColor } =
datasetTypeMap[dataset?.datasetType] || {};
return { return {
...dataset, ...dataset,
type: datasetTypeMap[dataset.datasetType]?.label || "未知", type: datasetTypeMap[dataset.datasetType]?.label || "未知",
size: formatBytes(dataset.totalSize || 0), size: formatBytes(dataset.totalSize || 0),
createdAt: formatDateTime(dataset.createdAt) || "--", createdAt: formatDateTime(dataset.createdAt) || "--",
updatedAt: formatDateTime(dataset?.updatedAt) || "--", updatedAt: formatDateTime(dataset?.updatedAt) || "--",
icon: IconComponent ? <IconComponent className="w-4 h-4" /> : <Database />, icon: IconComponent ? (
<IconComponent
className="w-5 h-5 text-gray-500"
// style={{ color: iconColor }}
/>
) : (
<Database />
),
status: datasetStatusMap[dataset.status], status: datasetStatusMap[dataset.status],
statistics: [ statistics: [
{ label: "文件数", value: dataset.fileCount || 0 }, { label: "文件数", value: dataset.fileCount || 0 },

View File

@@ -1,4 +1,4 @@
import React, { memo, useEffect, useState } from "react"; import { memo, useEffect, useState } from "react";
import { Button, Menu, Popover } from "antd"; import { Button, Menu, Popover } from "antd";
import { import {
CloseOutlined, CloseOutlined,
@@ -105,7 +105,6 @@ const AsiderAndHeaderLayout = () => {
defaultOpenKeys={["synthesis"]} defaultOpenKeys={["synthesis"]}
onClick={({ key }) => { onClick={({ key }) => {
setActiveItem(key); setActiveItem(key);
console.log(`/data/${key}`);
navigate(`/data/${key}`); navigate(`/data/${key}`);
}} }}
/> />
@@ -169,10 +168,7 @@ const AsiderAndHeaderLayout = () => {
<div <div
className="fixed inset-0 z-40" className="fixed inset-0 z-40"
onClick={() => { onClick={() => {
console.log("clicked outside");
setTaskCenterVisible(false); setTaskCenterVisible(false);
toggleShowTaskPopover(false);
}} }}
/> />
)} )}