import { CODE, IMAGES_TYPE_MAP } from '@/constants/images.constants'; import { delImagesAPI, getImagesList } from '@/services/images'; import { DeleteOutlined, EyeOutlined, SettingOutlined, } from '@ant-design/icons'; import { Button, Checkbox, Input, message, Modal, Popconfirm, Popover, Space, Table, Tag, Tooltip, } from 'antd'; import dayjs from 'dayjs'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { ImportModal, ModalDetailShow } from './components/modalShow/modalShow'; import useTableParams from './hook/hook'; import './index.less'; import { ReactComponent as RefreshIcon } from '@/assets/icons/refresh.svg'; // 列配置定义 type ColumnConfig = { key: string; title: string; dataIndex?: string; width: number; render?: (text: any, record: any, index: number) => React.ReactNode; fixed?: 'left' | 'right'; defaultVisible: boolean; // 默认是否显示 alwaysVisible?: boolean; // 始终显示的列 filters?: { text: string; value: string }[]; filterMultiple?: boolean; // 是否多选过滤 defaultFilteredValue?: string[]; // 默认过滤值 onFilter?: (value: string, record: any) => boolean; }; type TableColumn = { title: string; dataIndex?: string; key: string; width: number; render?: any; fixed?: 'left' | 'right'; hidden?: boolean; }; // 在组件顶部添加防抖函数 const debounce = (func: Function, delay: number) => { let timer: NodeJS.Timeout; return (...args: any[]) => { clearTimeout(timer); timer = setTimeout(() => func(...args), delay); }; }; const ImageList: React.FC = () => { const [images, setImages] = useState([]); const [loading, setLoading] = useState(false); const [selectedImage, setSelectedImage] = useState( null, ); const [detailVisible, setDetailVisible] = useState(false); const [importModalVisible, setImportModalVisible] = useState(false); const [searchText, setSearchText] = useState(''); // 添加本地搜索状态 const searchInputRef = useRef(''); // 保存已发送请求的搜索文本 const { tableParams, getApiParams, updateParams, handleTableChange } = useTableParams({ pagination: { current: 1, pageSize: 10, }, }); // 在组件顶部添加一个 ref 来保存最新的 tableParams const tableParamsRef = useRef(tableParams); tableParamsRef.current = tableParams; // 每次渲染时更新 ref 的值 const [columnSettingsVisible, setColumnSettingsVisible] = useState(false); // 表格参数变化 获取镜像列表 useEffect(() => { loadImages(); }, [ tableParams.pagination?.current, tableParams.pagination?.pageSize, tableParams?.sortOrder, tableParams?.sortField, JSON.stringify(tableParams.filters), ]); // 定义所有列的配置 const columnConfigs: ColumnConfig[] = [ { key: 'index', title: '序号', width: 60, render: (text: any, row: any, index: number) => (tableParams.pagination?.current - 1) * tableParams.pagination?.pageSize + index + 1, defaultVisible: true, alwaysVisible: true, }, { key: 'image_name', title: '镜像名称', dataIndex: 'image_name', width: 200, defaultVisible: true, alwaysVisible: true, render: (text: string) => ( {text || '--'} ), }, { key: 'image_type', title: '桌面类型', dataIndex: 'image_type', width: 100, render: (text: number) => { const key = text as keyof typeof IMAGES_TYPE_MAP; return {IMAGES_TYPE_MAP[key] || '--'}; }, defaultVisible: true, filters: [ { text: '全部', value: '全部' }, ...Object.entries(IMAGES_TYPE_MAP).map(([key, value]) => ({ text: value, value: key, // 保持 key 为字符串 })), ], filterMultiple: false, defaultFilteredValue: ['全部'], // onFilter: (value, record) => { // // 当选择"全部"时显示所有记录 // if (value === '全部') { // return true; // } // // 比较时将字符串 value 转换为数字 // return record.image_type === Number(value); // }, }, { key: 'storage_path', title: '模板存放路径', dataIndex: 'storage_path', width: 140, defaultVisible: true, }, { key: 'bt_path', title: 'BT路径', dataIndex: 'bt_path', width: 140, defaultVisible: true, }, { key: 'image_version', title: '镜像版本', dataIndex: 'image_version', width: 100, defaultVisible: true, }, { key: 'os_version', title: '操作系统', dataIndex: 'os_version', width: 100, defaultVisible: true, }, { key: 'image_status', title: '镜像状态', dataIndex: 'image_status', width: 80, render: (text: number) => {getStatusTag(text)}, defaultVisible: true, }, { key: 'create_time', title: '创建时间', dataIndex: 'create_time', width: 180, render: (text: string) => ( {dayjs(text).format('YYYY-MM-DD HH:mm:ss')} ), defaultVisible: true, }, { key: 'action', title: '操作', width: 100, fixed: 'right' as 'right', render: (_: any, record: IMAGES.ImageItem) => ( ); // 根据visibleColumns过滤显示的列 const filteredColumns = columnConfigs .map((config) => { // 对于始终显示的列 if (config.alwaysVisible) { return { ...config, hidden: undefined, }; } // 对于可控制显示/隐藏的列 return { ...config, ...(visibleColumns[config.key] ? {} : { hidden: true }), }; }) .filter((column) => !column.hidden) as TableColumn[]; const handleRefresh = () => { loadImages(); }; // 导入镜像成功后的回调 const handleImportSuccess = () => { setTimeout(() => { loadImages(); }, 5000); }; // 自定义分页配置 const paginationConfig = { ...tableParams.pagination, showTotal: (total: number) => `共 ${total} 条记录`, showSizeChanger: true, showQuickJumper: true, pageSizeOptions: ['10', '20', '50', '100'], }; const handleSearch = useCallback( (searchValue: string) => { console.log('handleSearch', searchValue, tableParams); // 使用 ref 中的最新值 const currentTableParams = tableParamsRef.current; // 只有当搜索值变化时才更新参数和触发请求 if (searchInputRef.current !== searchValue) { searchInputRef.current = searchValue; updateParams({ pagination: { current: 1, pageSize: currentTableParams.pagination?.pageSize || 10, }, filters: { ...currentTableParams.filters, image_name: searchValue ? searchValue : undefined, }, }); } }, [updateParams], ); const debouncedSearch = useRef(debounce(handleSearch, 500)).current; return (
{ const value = e.target.value; setSearchText(value); // 只有当输入为空时立即触发搜索,否则使用防抖 if (value === '') { handleSearch(''); } else { debouncedSearch(value); } }} style={{ width: 300 }} onSearch={handleSearch} />
{detailVisible ? ( ) : null} {/* 导入弹窗 */} setImportModalVisible(false)} onImportSuccess={handleImportSuccess} /> ); }; export default ImageList;