修复部分功能 (#138)

* feature: 版本统一

* feature: 定时同步时默认值展示异常,增加提示

* feature: 修复数据归集搜索

* feature: 优化标注模板查询

* feature: 屏蔽webhook功能
This commit is contained in:
hhhhsc701
2025-12-10 14:31:05 +08:00
committed by GitHub
parent c18b7af2c4
commit 103c21945d
13 changed files with 193 additions and 412 deletions

View File

@@ -1,12 +1,10 @@
import React, { useState, useEffect } from "react";
import React, { useState } from "react";
import {
Button,
Table,
Space,
Tag,
message,
Input,
Select,
Tooltip,
Popconfirm,
Card,
@@ -16,7 +14,6 @@ import {
EditOutlined,
DeleteOutlined,
EyeOutlined,
FilterOutlined,
} from "@ant-design/icons";
import type { ColumnsType } from "antd/es/table";
import {
@@ -26,23 +23,38 @@ import {
import type { AnnotationTemplate } from "../annotation.model";
import TemplateForm from "./TemplateForm.tsx";
import TemplateDetail from "./TemplateDetail.tsx";
const { Search } = Input;
const { Option } = Select;
import {SearchControls} from "@/components/SearchControls.tsx";
import useFetchData from "@/hooks/useFetchData.ts";
import {
AnnotationTypeMap,
ClassificationMap,
DataTypeMap,
TemplateTypeMap
} from "@/pages/DataAnnotation/annotation.const.tsx";
const TemplateList: React.FC = () => {
const [templates, setTemplates] = useState<AnnotationTemplate[]>([]);
const [loading, setLoading] = useState(false);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [size, setSize] = useState(10);
// Filters
const [searchText, setSearchText] = useState("");
const [categoryFilter, setCategoryFilter] = useState<string | undefined>();
const [dataTypeFilter, setDataTypeFilter] = useState<string | undefined>();
const [labelingTypeFilter, setLabelingTypeFilter] = useState<string | undefined>();
const [builtInFilter, setBuiltInFilter] = useState<boolean | undefined>();
const filterOptions = [
{
key: "category",
label: "分类",
options: [...Object.values(ClassificationMap)],
},
{
key: "dataType",
label: "数据类型",
options: [...Object.values(DataTypeMap)],
},
{
key: "labelingType",
label: "标注类型",
options: [...Object.values(AnnotationTypeMap)],
},
{
key: "builtIn",
label: "模板类型",
options: [...Object.values(TemplateTypeMap)],
},
];
// Modals
const [isFormVisible, setIsFormVisible] = useState(false);
@@ -50,35 +62,16 @@ const TemplateList: React.FC = () => {
const [selectedTemplate, setSelectedTemplate] = useState<AnnotationTemplate | undefined>();
const [formMode, setFormMode] = useState<"create" | "edit">("create");
useEffect(() => {
fetchTemplates();
}, [page, size, categoryFilter, dataTypeFilter, labelingTypeFilter, builtInFilter]);
const fetchTemplates = async () => {
setLoading(true);
try {
const params: any = {
page,
size,
};
if (categoryFilter) params.category = categoryFilter;
if (dataTypeFilter) params.dataType = dataTypeFilter;
if (labelingTypeFilter) params.labelingType = labelingTypeFilter;
if (builtInFilter !== undefined) params.builtIn = builtInFilter;
const response = await queryAnnotationTemplatesUsingGet(params);
if (response.code === 200 && response.data) {
setTemplates(response.data.content || []);
setTotal(response.data.total || 0);
}
} catch (error) {
message.error("获取模板列表失败");
console.error(error);
} finally {
setLoading(false);
}
};
const {
loading,
tableData,
pagination,
searchParams,
setSearchParams,
fetchData,
handleFiltersChange,
handleKeywordChange,
} = useFetchData(queryAnnotationTemplatesUsingGet, undefined, undefined, undefined, undefined, 0);
const handleCreate = () => {
setFormMode("create");
@@ -102,7 +95,7 @@ const TemplateList: React.FC = () => {
const response = await deleteAnnotationTemplateByIdUsingDelete(templateId);
if (response.code === 200) {
message.success("模板删除成功");
fetchTemplates();
fetchData();
} else {
message.error(response.message || "删除模板失败");
}
@@ -114,15 +107,7 @@ const TemplateList: React.FC = () => {
const handleFormSuccess = () => {
setIsFormVisible(false);
fetchTemplates();
};
const handleClearFilters = () => {
setCategoryFilter(undefined);
setDataTypeFilter(undefined);
setLabelingTypeFilter(undefined);
setBuiltInFilter(undefined);
setSearchText("");
fetchData();
};
const getCategoryColor = (category: string) => {
@@ -143,7 +128,6 @@ const TemplateList: React.FC = () => {
key: "name",
width: 200,
ellipsis: true,
filteredValue: searchText ? [searchText] : null,
onFilter: (value, record) =>
record.name.toLowerCase().includes(value.toString().toLowerCase()) ||
(record.description?.toLowerCase().includes(value.toString().toLowerCase()) ?? false),
@@ -269,78 +253,22 @@ const TemplateList: React.FC = () => {
},
];
const hasActiveFilters = categoryFilter || dataTypeFilter || labelingTypeFilter || builtInFilter !== undefined;
return (
<div className="flex flex-col gap-4">
{/* Search, Filters and Buttons in one row */}
<div className="flex items-center justify-between gap-2">
{/* Left side: Search and Filters */}
<div className="flex items-center gap-2 flex-wrap">
<Search
placeholder="搜索模板..."
allowClear
style={{ width: 300 }}
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
<SearchControls
searchTerm={searchParams.keyword}
onSearchChange={handleKeywordChange}
searchPlaceholder="搜索任务名称、描述"
filters={filterOptions}
onFiltersChange={handleFiltersChange}
showViewToggle={true}
onReload={fetchData}
onClearFilters={() => setSearchParams({ ...searchParams, filter: {} })}
/>
<Select
placeholder="分类"
allowClear
style={{ width: 140 }}
value={categoryFilter}
onChange={setCategoryFilter}
>
<Option value="computer-vision"></Option>
<Option value="nlp"></Option>
<Option value="audio"></Option>
<Option value="quality-control"></Option>
<Option value="custom"></Option>
</Select>
<Select
placeholder="数据类型"
allowClear
style={{ width: 120 }}
value={dataTypeFilter}
onChange={setDataTypeFilter}
>
<Option value="image"></Option>
<Option value="text"></Option>
<Option value="audio"></Option>
<Option value="video"></Option>
</Select>
<Select
placeholder="标注类型"
allowClear
style={{ width: 140 }}
value={labelingTypeFilter}
onChange={setLabelingTypeFilter}
>
<Option value="classification"></Option>
<Option value="object-detection"></Option>
<Option value="segmentation"></Option>
<Option value="ner"></Option>
</Select>
<Select
placeholder="模板类型"
allowClear
style={{ width: 120 }}
value={builtInFilter}
onChange={setBuiltInFilter}
>
<Option value={true}></Option>
<Option value={false}></Option>
</Select>
{hasActiveFilters && (
<Button icon={<FilterOutlined />} onClick={handleClearFilters}>
</Button>
)}
</div>
{/* Right side: Create button */}
@@ -354,20 +282,10 @@ const TemplateList: React.FC = () => {
<Card>
<Table
columns={columns}
dataSource={templates}
dataSource={tableData}
rowKey="id"
loading={loading}
pagination={{
current: page,
pageSize: size,
total: total,
showSizeChanger: true,
showTotal: (total) => `${total} 个模板`,
onChange: (page, pageSize) => {
setPage(page);
setSize(pageSize);
},
}}
pagination={pagination}
scroll={{ x: 1400, y: "calc(100vh - 24rem)" }}
/>
</Card>