diff --git a/web/src/components/table/ChannelsTable.js b/web/src/components/table/ChannelsTable.js index 68babe2e..1907387d 100644 --- a/web/src/components/table/ChannelsTable.js +++ b/web/src/components/table/ChannelsTable.js @@ -41,6 +41,7 @@ import { Tag, Tooltip, Typography, + Checkbox, Card, Form } from '@douyinfe/semi-ui'; @@ -172,17 +173,108 @@ const ChannelsTable = () => { } }; - // Define all columns - const columns = [ + // Define column keys for selection + const COLUMN_KEYS = { + ID: 'id', + NAME: 'name', + GROUP: 'group', + TYPE: 'type', + STATUS: 'status', + RESPONSE_TIME: 'response_time', + BALANCE: 'balance', + PRIORITY: 'priority', + WEIGHT: 'weight', + OPERATE: 'operate', + }; + + // State for column visibility + const [visibleColumns, setVisibleColumns] = useState({}); + const [showColumnSelector, setShowColumnSelector] = useState(false); + + // Load saved column preferences from localStorage + useEffect(() => { + const savedColumns = localStorage.getItem('channels-table-columns'); + if (savedColumns) { + try { + const parsed = JSON.parse(savedColumns); + // Make sure all columns are accounted for + const defaults = getDefaultColumnVisibility(); + const merged = { ...defaults, ...parsed }; + setVisibleColumns(merged); + } catch (e) { + console.error('Failed to parse saved column preferences', e); + initDefaultColumns(); + } + } else { + initDefaultColumns(); + } + }, []); + + // Update table when column visibility changes + useEffect(() => { + if (Object.keys(visibleColumns).length > 0) { + // Save to localStorage + localStorage.setItem( + 'channels-table-columns', + JSON.stringify(visibleColumns), + ); + } + }, [visibleColumns]); + + // Get default column visibility + const getDefaultColumnVisibility = () => { + return { + [COLUMN_KEYS.ID]: true, + [COLUMN_KEYS.NAME]: true, + [COLUMN_KEYS.GROUP]: true, + [COLUMN_KEYS.TYPE]: true, + [COLUMN_KEYS.STATUS]: true, + [COLUMN_KEYS.RESPONSE_TIME]: true, + [COLUMN_KEYS.BALANCE]: true, + [COLUMN_KEYS.PRIORITY]: true, + [COLUMN_KEYS.WEIGHT]: true, + [COLUMN_KEYS.OPERATE]: true, + }; + }; + + // Initialize default column visibility + const initDefaultColumns = () => { + const defaults = getDefaultColumnVisibility(); + setVisibleColumns(defaults); + }; + + // Handle column visibility change + const handleColumnVisibilityChange = (columnKey, checked) => { + const updatedColumns = { ...visibleColumns, [columnKey]: checked }; + setVisibleColumns(updatedColumns); + }; + + // Handle "Select All" checkbox + const handleSelectAll = (checked) => { + const allKeys = Object.keys(COLUMN_KEYS).map((key) => COLUMN_KEYS[key]); + const updatedColumns = {}; + + allKeys.forEach((key) => { + updatedColumns[key] = checked; + }); + + setVisibleColumns(updatedColumns); + }; + + // Define all columns with keys + const allColumns = [ { + key: COLUMN_KEYS.ID, title: t('ID'), dataIndex: 'id', }, { + key: COLUMN_KEYS.NAME, title: t('名称'), dataIndex: 'name', }, { + key: COLUMN_KEYS.GROUP, title: t('分组'), dataIndex: 'group', render: (text, record, index) => ( @@ -201,6 +293,7 @@ const ChannelsTable = () => { ), }, { + key: COLUMN_KEYS.TYPE, title: t('类型'), dataIndex: 'type', render: (text, record, index) => { @@ -212,6 +305,7 @@ const ChannelsTable = () => { }, }, { + key: COLUMN_KEYS.STATUS, title: t('状态'), dataIndex: 'status', render: (text, record, index) => { @@ -237,6 +331,7 @@ const ChannelsTable = () => { }, }, { + key: COLUMN_KEYS.RESPONSE_TIME, title: t('响应时间'), dataIndex: 'response_time', render: (text, record, index) => ( @@ -244,6 +339,7 @@ const ChannelsTable = () => { ), }, { + key: COLUMN_KEYS.BALANCE, title: t('已用/剩余'), dataIndex: 'expired_time', render: (text, record, index) => { @@ -283,6 +379,7 @@ const ChannelsTable = () => { }, }, { + key: COLUMN_KEYS.PRIORITY, title: t('优先级'), dataIndex: 'priority', render: (text, record, index) => { @@ -334,6 +431,7 @@ const ChannelsTable = () => { }, }, { + key: COLUMN_KEYS.WEIGHT, title: t('权重'), dataIndex: 'weight', render: (text, record, index) => { @@ -385,6 +483,7 @@ const ChannelsTable = () => { }, }, { + key: COLUMN_KEYS.OPERATE, title: '', dataIndex: 'operate', fixed: 'right', @@ -595,6 +694,89 @@ const ChannelsTable = () => { searchModel: '', }; + // Filter columns based on visibility settings + const getVisibleColumns = () => { + return allColumns.filter((column) => visibleColumns[column.key]); + }; + + // Column selector modal + const renderColumnSelector = () => { + return ( + setShowColumnSelector(false)} + footer={ +
+ + + +
+ } + size="middle" + centered={true} + > +
+ v === true)} + indeterminate={ + Object.values(visibleColumns).some((v) => v === true) && + !Object.values(visibleColumns).every((v) => v === true) + } + onChange={(e) => handleSelectAll(e.target.checked)} + > + {t('全选')} + +
+
+ {allColumns.map((column) => { + // Skip columns without title + if (!column.title) { + return null; + } + + return ( +
+ + handleColumnVisibilityChange(column.key, e.target.checked) + } + > + {column.title} + +
+ ); + })} +
+
+ ); + }; + const removeRecord = (record) => { let newDataSource = [...channels]; if (record.id != null) { @@ -1397,6 +1579,16 @@ const ChannelsTable = () => { > {t('刷新')} + +
@@ -1481,6 +1673,7 @@ const ChannelsTable = () => { return ( <> + {renderColumnSelector()} { bordered={false} >