1- import React , { useState , useEffect } from "react" ;
1+ import React , { useState } from "react" ;
22import {
33 Button ,
44 Table ,
55 Space ,
66 Tag ,
77 message ,
8- Input ,
9- Select ,
108 Tooltip ,
119 Popconfirm ,
1210 Card ,
@@ -16,7 +14,6 @@ import {
1614 EditOutlined ,
1715 DeleteOutlined ,
1816 EyeOutlined ,
19- FilterOutlined ,
2017} from "@ant-design/icons" ;
2118import type { ColumnsType } from "antd/es/table" ;
2219import {
@@ -26,59 +23,55 @@ import {
2623import type { AnnotationTemplate } from "../annotation.model" ;
2724import TemplateForm from "./TemplateForm.tsx" ;
2825import TemplateDetail from "./TemplateDetail.tsx" ;
29-
30- const { Search } = Input ;
31- const { Option } = Select ;
26+ import { SearchControls } from "@/components/SearchControls.tsx" ;
27+ import useFetchData from "@/hooks/useFetchData.ts" ;
28+ import {
29+ AnnotationTypeMap ,
30+ ClassificationMap ,
31+ DataTypeMap ,
32+ TemplateTypeMap
33+ } from "@/pages/DataAnnotation/annotation.const.tsx" ;
3234
3335const TemplateList : React . FC = ( ) => {
34- const [ templates , setTemplates ] = useState < AnnotationTemplate [ ] > ( [ ] ) ;
35- const [ loading , setLoading ] = useState ( false ) ;
36- const [ total , setTotal ] = useState ( 0 ) ;
37- const [ page , setPage ] = useState ( 1 ) ;
38- const [ size , setSize ] = useState ( 10 ) ;
39-
40- // Filters
41- const [ searchText , setSearchText ] = useState ( "" ) ;
42- const [ categoryFilter , setCategoryFilter ] = useState < string | undefined > ( ) ;
43- const [ dataTypeFilter , setDataTypeFilter ] = useState < string | undefined > ( ) ;
44- const [ labelingTypeFilter , setLabelingTypeFilter ] = useState < string | undefined > ( ) ;
45- const [ builtInFilter , setBuiltInFilter ] = useState < boolean | undefined > ( ) ;
36+ const filterOptions = [
37+ {
38+ key : "category" ,
39+ label : "分类" ,
40+ options : [ ...Object . values ( ClassificationMap ) ] ,
41+ } ,
42+ {
43+ key : "dataType" ,
44+ label : "数据类型" ,
45+ options : [ ...Object . values ( DataTypeMap ) ] ,
46+ } ,
47+ {
48+ key : "labelingType" ,
49+ label : "标注类型" ,
50+ options : [ ...Object . values ( AnnotationTypeMap ) ] ,
51+ } ,
52+ {
53+ key : "builtIn" ,
54+ label : "模板类型" ,
55+ options : [ ...Object . values ( TemplateTypeMap ) ] ,
56+ } ,
57+ ] ;
4658
4759 // Modals
4860 const [ isFormVisible , setIsFormVisible ] = useState ( false ) ;
4961 const [ isDetailVisible , setIsDetailVisible ] = useState ( false ) ;
5062 const [ selectedTemplate , setSelectedTemplate ] = useState < AnnotationTemplate | undefined > ( ) ;
5163 const [ formMode , setFormMode ] = useState < "create" | "edit" > ( "create" ) ;
5264
53- useEffect ( ( ) => {
54- fetchTemplates ( ) ;
55- } , [ page , size , categoryFilter , dataTypeFilter , labelingTypeFilter , builtInFilter ] ) ;
56-
57- const fetchTemplates = async ( ) => {
58- setLoading ( true ) ;
59- try {
60- const params : any = {
61- page,
62- size,
63- } ;
64-
65- if ( categoryFilter ) params . category = categoryFilter ;
66- if ( dataTypeFilter ) params . dataType = dataTypeFilter ;
67- if ( labelingTypeFilter ) params . labelingType = labelingTypeFilter ;
68- if ( builtInFilter !== undefined ) params . builtIn = builtInFilter ;
69-
70- const response = await queryAnnotationTemplatesUsingGet ( params ) ;
71- if ( response . code === 200 && response . data ) {
72- setTemplates ( response . data . content || [ ] ) ;
73- setTotal ( response . data . total || 0 ) ;
74- }
75- } catch ( error ) {
76- message . error ( "获取模板列表失败" ) ;
77- console . error ( error ) ;
78- } finally {
79- setLoading ( false ) ;
80- }
81- } ;
65+ const {
66+ loading,
67+ tableData,
68+ pagination,
69+ searchParams,
70+ setSearchParams,
71+ fetchData,
72+ handleFiltersChange,
73+ handleKeywordChange,
74+ } = useFetchData ( queryAnnotationTemplatesUsingGet , undefined , undefined , undefined , undefined , 0 ) ;
8275
8376 const handleCreate = ( ) => {
8477 setFormMode ( "create" ) ;
@@ -102,7 +95,7 @@ const TemplateList: React.FC = () => {
10295 const response = await deleteAnnotationTemplateByIdUsingDelete ( templateId ) ;
10396 if ( response . code === 200 ) {
10497 message . success ( "模板删除成功" ) ;
105- fetchTemplates ( ) ;
98+ fetchData ( ) ;
10699 } else {
107100 message . error ( response . message || "删除模板失败" ) ;
108101 }
@@ -114,15 +107,7 @@ const TemplateList: React.FC = () => {
114107
115108 const handleFormSuccess = ( ) => {
116109 setIsFormVisible ( false ) ;
117- fetchTemplates ( ) ;
118- } ;
119-
120- const handleClearFilters = ( ) => {
121- setCategoryFilter ( undefined ) ;
122- setDataTypeFilter ( undefined ) ;
123- setLabelingTypeFilter ( undefined ) ;
124- setBuiltInFilter ( undefined ) ;
125- setSearchText ( "" ) ;
110+ fetchData ( ) ;
126111 } ;
127112
128113 const getCategoryColor = ( category : string ) => {
@@ -143,7 +128,6 @@ const TemplateList: React.FC = () => {
143128 key : "name" ,
144129 width : 200 ,
145130 ellipsis : true ,
146- filteredValue : searchText ? [ searchText ] : null ,
147131 onFilter : ( value , record ) =>
148132 record . name . toLowerCase ( ) . includes ( value . toString ( ) . toLowerCase ( ) ) ||
149133 ( record . description ?. toLowerCase ( ) . includes ( value . toString ( ) . toLowerCase ( ) ) ?? false ) ,
@@ -269,78 +253,22 @@ const TemplateList: React.FC = () => {
269253 } ,
270254 ] ;
271255
272- const hasActiveFilters = categoryFilter || dataTypeFilter || labelingTypeFilter || builtInFilter !== undefined ;
273-
274256 return (
275257 < div className = "flex flex-col gap-4" >
276258 { /* Search, Filters and Buttons in one row */ }
277259 < div className = "flex items-center justify-between gap-2" >
278260 { /* Left side: Search and Filters */ }
279261 < div className = "flex items-center gap-2 flex-wrap" >
280- < Search
281- placeholder = "搜索模板..."
282- allowClear
283- style = { { width : 300 } }
284- value = { searchText }
285- onChange = { ( e ) => setSearchText ( e . target . value ) }
262+ < SearchControls
263+ searchTerm = { searchParams . keyword }
264+ onSearchChange = { handleKeywordChange }
265+ searchPlaceholder = "搜索任务名称、描述"
266+ filters = { filterOptions }
267+ onFiltersChange = { handleFiltersChange }
268+ showViewToggle = { true }
269+ onReload = { fetchData }
270+ onClearFilters = { ( ) => setSearchParams ( { ...searchParams , filter : { } } ) }
286271 />
287-
288- < Select
289- placeholder = "分类"
290- allowClear
291- style = { { width : 140 } }
292- value = { categoryFilter }
293- onChange = { setCategoryFilter }
294- >
295- < Option value = "computer-vision" > 计算机视觉</ Option >
296- < Option value = "nlp" > 自然语言处理</ Option >
297- < Option value = "audio" > 音频</ Option >
298- < Option value = "quality-control" > 质量控制</ Option >
299- < Option value = "custom" > 自定义</ Option >
300- </ Select >
301-
302- < Select
303- placeholder = "数据类型"
304- allowClear
305- style = { { width : 120 } }
306- value = { dataTypeFilter }
307- onChange = { setDataTypeFilter }
308- >
309- < Option value = "image" > 图像</ Option >
310- < Option value = "text" > 文本</ Option >
311- < Option value = "audio" > 音频</ Option >
312- < Option value = "video" > 视频</ Option >
313- </ Select >
314-
315- < Select
316- placeholder = "标注类型"
317- allowClear
318- style = { { width : 140 } }
319- value = { labelingTypeFilter }
320- onChange = { setLabelingTypeFilter }
321- >
322- < Option value = "classification" > 分类</ Option >
323- < Option value = "object-detection" > 目标检测</ Option >
324- < Option value = "segmentation" > 分割</ Option >
325- < Option value = "ner" > 命名实体识别</ Option >
326- </ Select >
327-
328- < Select
329- placeholder = "模板类型"
330- allowClear
331- style = { { width : 120 } }
332- value = { builtInFilter }
333- onChange = { setBuiltInFilter }
334- >
335- < Option value = { true } > 系统内置</ Option >
336- < Option value = { false } > 自定义</ Option >
337- </ Select >
338-
339- { hasActiveFilters && (
340- < Button icon = { < FilterOutlined /> } onClick = { handleClearFilters } >
341- 清空筛选
342- </ Button >
343- ) }
344272 </ div >
345273
346274 { /* Right side: Create button */ }
@@ -354,20 +282,10 @@ const TemplateList: React.FC = () => {
354282 < Card >
355283 < Table
356284 columns = { columns }
357- dataSource = { templates }
285+ dataSource = { tableData }
358286 rowKey = "id"
359287 loading = { loading }
360- pagination = { {
361- current : page ,
362- pageSize : size ,
363- total : total ,
364- showSizeChanger : true ,
365- showTotal : ( total ) => `共 ${ total } 个模板` ,
366- onChange : ( page , pageSize ) => {
367- setPage ( page ) ;
368- setSize ( pageSize ) ;
369- } ,
370- } }
288+ pagination = { pagination }
371289 scroll = { { x : 1400 , y : "calc(100vh - 24rem)" } }
372290 />
373291 </ Card >
0 commit comments