import { useState, useEffect } from "react";
import { Card, Button, Table, message, Modal, Tabs } from "antd";
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
SyncOutlined,
} from "@ant-design/icons";
import { SearchControls } from "@/components/SearchControls";
import CardView from "@/components/CardView";
import type { AnnotationTask } from "../annotation.model";
import useFetchData from "@/hooks/useFetchData";
import {
deleteAnnotationTaskByIdUsingDelete, loginAnnotationUsingGet,
queryAnnotationTasksUsingGet,
syncAnnotationTaskUsingPost,
} from "../annotation.api";
import { mapAnnotationTask } from "../annotation.const";
import CreateAnnotationTask from "../Create/components/CreateAnnotationTaskDialog";
import { ColumnType } from "antd/es/table";
import { TemplateList } from "../Template";
// Note: DevelopmentInProgress intentionally not used here
export default function DataAnnotation() {
// return ;
const [activeTab, setActiveTab] = useState("tasks");
const [viewMode, setViewMode] = useState<"list" | "card">("list");
const [showCreateDialog, setShowCreateDialog] = useState(false);
const {
loading,
tableData,
pagination,
searchParams,
fetchData,
handleFiltersChange,
handleKeywordChange,
} = useFetchData(queryAnnotationTasksUsingGet, mapAnnotationTask, 30000, true, [], 0);
const [labelStudioBase, setLabelStudioBase] = useState(null);
const [selectedRowKeys, setSelectedRowKeys] = useState<(string | number)[]>([]);
const [selectedRows, setSelectedRows] = useState([]);
// prefetch config on mount so clicking annotate is fast and we know whether base URL exists
// useEffect ensures this runs once
useEffect(() => {
let mounted = true;
(async () => {
try {
const baseUrl = `http://${window.location.hostname}:${parseInt(window.location.port) + 1}`;
if (mounted) setLabelStudioBase(baseUrl);
} catch (e) {
if (mounted) setLabelStudioBase(null);
}
})();
return () => {
mounted = false;
};
}, []);
const handleAnnotate = (task: AnnotationTask) => {
// Open Label Studio project page in a new tab
(async () => {
try {
// prefer using labeling project id already present on the task
// `mapAnnotationTask` normalizes upstream fields into `labelingProjId`/`projId`,
// so prefer those and fall back to the task id if necessary.
let labelingProjId = (task as any).labelingProjId || (task as any).projId || undefined;
// no fallback external mapping lookup; rely on normalized fields from mapAnnotationTask
// use prefetched base if available
const base = labelStudioBase;
// no debug logging in production
if (labelingProjId) {
// only open external Label Studio when we have a configured base url
await loginAnnotationUsingGet(labelingProjId)
if (base) {
const target = `${base}/projects/${labelingProjId}/data`;
window.open(target, "_blank");
} else {
// no external Label Studio URL configured — do not perform internal redirect in this version
message.error("无法跳转到 Label Studio:未配置 Label Studio 基础 URL");
return;
}
} else {
// no labeling project id available — do not attempt internal redirect in this version
message.error("无法跳转到 Label Studio:该映射未绑定标注项目");
return;
}
} catch (error) {
// on error, surface a user-friendly message instead of redirecting
message.error("无法跳转到 Label Studio:发生错误,请检查配置或控制台日志");
return;
}
})();
};
const handleDelete = (task: AnnotationTask) => {
Modal.confirm({
title: `确认删除标注任务「${task.name}」吗?`,
content: (