Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 196 additions & 3 deletions web/src/components/table/ChannelsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
Tag,
Tooltip,
Typography,
Checkbox,
Card,
Form
} from '@douyinfe/semi-ui';
Expand Down Expand Up @@ -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) => (
Expand All @@ -201,6 +293,7 @@ const ChannelsTable = () => {
),
},
{
key: COLUMN_KEYS.TYPE,
title: t('类型'),
dataIndex: 'type',
render: (text, record, index) => {
Expand All @@ -212,6 +305,7 @@ const ChannelsTable = () => {
},
},
{
key: COLUMN_KEYS.STATUS,
title: t('状态'),
dataIndex: 'status',
render: (text, record, index) => {
Expand All @@ -237,13 +331,15 @@ const ChannelsTable = () => {
},
},
{
key: COLUMN_KEYS.RESPONSE_TIME,
title: t('响应时间'),
dataIndex: 'response_time',
render: (text, record, index) => (
<div>{renderResponseTime(text)}</div>
),
},
{
key: COLUMN_KEYS.BALANCE,
title: t('已用/剩余'),
dataIndex: 'expired_time',
render: (text, record, index) => {
Expand Down Expand Up @@ -283,6 +379,7 @@ const ChannelsTable = () => {
},
},
{
key: COLUMN_KEYS.PRIORITY,
title: t('优先级'),
dataIndex: 'priority',
render: (text, record, index) => {
Expand Down Expand Up @@ -334,6 +431,7 @@ const ChannelsTable = () => {
},
},
{
key: COLUMN_KEYS.WEIGHT,
title: t('权重'),
dataIndex: 'weight',
render: (text, record, index) => {
Expand Down Expand Up @@ -385,6 +483,7 @@ const ChannelsTable = () => {
},
},
{
key: COLUMN_KEYS.OPERATE,
title: '',
dataIndex: 'operate',
fixed: 'right',
Expand Down Expand Up @@ -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 (
<Modal
title={t('列设置')}
visible={showColumnSelector}
onCancel={() => setShowColumnSelector(false)}
footer={
<div className="flex justify-end">
<Button
theme="light"
onClick={() => initDefaultColumns()}
className="!rounded-full"
>
{t('重置')}
</Button>
<Button
theme="light"
onClick={() => setShowColumnSelector(false)}
className="!rounded-full"
>
{t('取消')}
</Button>
<Button
type='primary'
onClick={() => setShowColumnSelector(false)}
className="!rounded-full"
>
{t('确定')}
</Button>
</div>
}
size="middle"
centered={true}
>
<div style={{ marginBottom: 20 }}>
<Checkbox
checked={Object.values(visibleColumns).every((v) => v === true)}
indeterminate={
Object.values(visibleColumns).some((v) => v === true) &&
!Object.values(visibleColumns).every((v) => v === true)
}
onChange={(e) => handleSelectAll(e.target.checked)}
>
{t('全选')}
</Checkbox>
</div>
<div
className="flex flex-wrap max-h-96 overflow-y-auto rounded-lg p-4"
style={{ border: '1px solid var(--semi-color-border)' }}
>
{allColumns.map((column) => {
// Skip columns without title
if (!column.title) {
return null;
}

return (
<div
key={column.key}
className="w-1/2 mb-4 pr-2"
>
<Checkbox
checked={!!visibleColumns[column.key]}
onChange={(e) =>
handleColumnVisibilityChange(column.key, e.target.checked)
}
>
{column.title}
</Checkbox>
</div>
);
})}
</div>
</Modal>
);
};

const removeRecord = (record) => {
let newDataSource = [...channels];
if (record.id != null) {
Expand Down Expand Up @@ -1397,6 +1579,16 @@ const ChannelsTable = () => {
>
{t('刷新')}
</Button>

<Button
theme='light'
type='tertiary'
icon={<IconSetting />}
onClick={() => setShowColumnSelector(true)}
className="!rounded-full w-full md:w-auto"
>
{t('列设置')}
</Button>
</div>

<div className="flex flex-col md:flex-row items-center gap-4 w-full md:w-auto order-1 md:order-2">
Expand Down Expand Up @@ -1481,6 +1673,7 @@ const ChannelsTable = () => {

return (
<>
{renderColumnSelector()}
<EditTagModal
visible={showEditTag}
tag={editingTag}
Expand All @@ -1501,7 +1694,7 @@ const ChannelsTable = () => {
bordered={false}
>
<Table
columns={columns}
columns={getVisibleColumns()}
dataSource={pageData}
scroll={{ x: 'max-content' }}
pagination={{
Expand Down