You've already forked DataMate
feat(annotation): 添加标注数据导出功能
- 新增导出对话框组件,支持多种格式选择 - 实现 JSON、JSONL、CSV、COCO、YOLO 五种导出格式 - 添加导出统计信息显示,包括总文件数和已标注数 - 集成前端导出按钮和后端 API 接口 - 支持仅导出已标注数据和包含原始数据选项 - 实现文件下载和命名功能
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Card, Button, Table, message, Modal, Tabs, Tag, Progress, Tooltip } from "antd";
|
||||
import {
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
SyncOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useNavigate } from "react-router";
|
||||
import { SearchControls } from "@/components/SearchControls";
|
||||
import CardView from "@/components/CardView";
|
||||
import type { AnnotationTask } from "../annotation.model";
|
||||
import useFetchData from "@/hooks/useFetchData";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Card, Button, Table, message, Modal, Tabs, Tag, Progress, Tooltip } from "antd";
|
||||
import {
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
SyncOutlined,
|
||||
DownloadOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useNavigate } from "react-router";
|
||||
import { SearchControls } from "@/components/SearchControls";
|
||||
import CardView from "@/components/CardView";
|
||||
import type { AnnotationTask } from "../annotation.model";
|
||||
import useFetchData from "@/hooks/useFetchData";
|
||||
import {
|
||||
deleteAnnotationTaskByIdUsingDelete,
|
||||
queryAnnotationTasksUsingGet,
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
} from "../annotation.api";
|
||||
import { mapAnnotationTask } from "../annotation.const";
|
||||
import CreateAnnotationTask from "../Create/components/CreateAnnotationTaskDialog";
|
||||
import ExportAnnotationDialog from "./ExportAnnotationDialog";
|
||||
import { ColumnType } from "antd/es/table";
|
||||
import { TemplateList } from "../Template";
|
||||
// Note: DevelopmentInProgress intentionally not used here
|
||||
@@ -40,13 +42,14 @@ const AUTO_MODEL_SIZE_LABELS: Record<string, string> = {
|
||||
x: "YOLOv8x (最精确)",
|
||||
};
|
||||
|
||||
export default function DataAnnotation() {
|
||||
// return <DevelopmentInProgress showTime="2025.10.30" />;
|
||||
const navigate = useNavigate();
|
||||
const [activeTab, setActiveTab] = useState("tasks");
|
||||
const [viewMode, setViewMode] = useState<"list" | "card">("list");
|
||||
const [showCreateDialog, setShowCreateDialog] = useState(false);
|
||||
const [autoTasks, setAutoTasks] = useState<any[]>([]);
|
||||
export default function DataAnnotation() {
|
||||
// return <DevelopmentInProgress showTime="2025.10.30" />;
|
||||
const navigate = useNavigate();
|
||||
const [activeTab, setActiveTab] = useState("tasks");
|
||||
const [viewMode, setViewMode] = useState<"list" | "card">("list");
|
||||
const [showCreateDialog, setShowCreateDialog] = useState(false);
|
||||
const [exportTask, setExportTask] = useState<AnnotationTask | null>(null);
|
||||
const [autoTasks, setAutoTasks] = useState<any[]>([]);
|
||||
|
||||
const {
|
||||
loading,
|
||||
@@ -58,8 +61,8 @@ export default function DataAnnotation() {
|
||||
handleKeywordChange,
|
||||
} = useFetchData(queryAnnotationTasksUsingGet, mapAnnotationTask, 30000, true, [], 0);
|
||||
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<(string | number)[]>([]);
|
||||
const [selectedRows, setSelectedRows] = useState<any[]>([]);
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<(string | number)[]>([]);
|
||||
const [selectedRows, setSelectedRows] = useState<any[]>([]);
|
||||
|
||||
// 拉取自动标注任务(供轮询和创建成功后立即刷新复用)
|
||||
const refreshAutoTasks = async (silent = false) => {
|
||||
@@ -77,24 +80,28 @@ export default function DataAnnotation() {
|
||||
}
|
||||
};
|
||||
|
||||
// 自动标注任务轮询(用于在同一表格中展示处理进度)
|
||||
useEffect(() => {
|
||||
refreshAutoTasks();
|
||||
const timer = setInterval(() => refreshAutoTasks(true), 3000);
|
||||
// 自动标注任务轮询(用于在同一表格中展示处理进度)
|
||||
useEffect(() => {
|
||||
refreshAutoTasks();
|
||||
const timer = setInterval(() => refreshAutoTasks(true), 3000);
|
||||
|
||||
return () => {
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleAnnotate = (task: AnnotationTask) => {
|
||||
const projectId = (task as any)?.id;
|
||||
if (!projectId) {
|
||||
message.error("无法进入标注:缺少标注项目ID");
|
||||
return;
|
||||
}
|
||||
navigate(`/data/annotation/annotate/${projectId}`);
|
||||
};
|
||||
const handleAnnotate = (task: AnnotationTask) => {
|
||||
const projectId = (task as any)?.id;
|
||||
if (!projectId) {
|
||||
message.error("无法进入标注:缺少标注项目ID");
|
||||
return;
|
||||
}
|
||||
navigate(`/data/annotation/annotate/${projectId}`);
|
||||
};
|
||||
|
||||
const handleExport = (task: AnnotationTask) => {
|
||||
setExportTask(task);
|
||||
};
|
||||
|
||||
const handleDelete = (task: AnnotationTask) => {
|
||||
Modal.confirm({
|
||||
@@ -257,6 +264,12 @@ export default function DataAnnotation() {
|
||||
),
|
||||
onClick: handleAnnotate,
|
||||
},
|
||||
{
|
||||
key: "export",
|
||||
label: "导出",
|
||||
icon: <DownloadOutlined className="w-4 h-4" style={{ color: "#1890ff" }} />,
|
||||
onClick: handleExport,
|
||||
},
|
||||
{
|
||||
key: "sync",
|
||||
label: "同步",
|
||||
@@ -552,6 +565,13 @@ export default function DataAnnotation() {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<ExportAnnotationDialog
|
||||
open={!!exportTask}
|
||||
projectId={exportTask?.id || ""}
|
||||
projectName={exportTask?.name || ""}
|
||||
onClose={() => setExportTask(null)}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user