🚀 feat(web/channels): Deep modular refactor of Channels table
1. Split monolithic `ChannelsTable` (2200+ LOC) into focused components
• `channels/index.jsx` – composition entry
• `ChannelsTable.jsx` – pure `<Table>` rendering
• `ChannelsActions.jsx` – bulk & settings toolbar
• `ChannelsFilters.jsx` – search / create / column-settings form
• `ChannelsTabs.jsx` – type tabs
• `ChannelsColumnDefs.js` – column definitions & render helpers
• `modals/` – BatchTag, ColumnSelector, ModelTest modals
2. Extract domain hook
• Moved `useChannelsData.js` → `src/hooks/channels/useChannelsData.js`
– centralises state, API calls, pagination, filters, batch ops
– now exports `setActivePage`, fixing tab / status switch errors
3. Update wiring
• All sub-components consume data via `useChannelsData` props
• Adjusted import paths after hook relocation
4. Clean legacy file
• Legacy `components/table/ChannelsTable.js` now re-exports new module
5. Bug fixes
• Tab switching, status filter & tag aggregation restored
• Column selector & batch actions operate via unified hook
This commit completes the first phase of modularising the Channels feature, laying groundwork for consistent, maintainable table architecture across the app.
2025-07-18 21:05:36 +08:00
|
|
|
import React from 'react';
|
|
|
|
|
import {
|
|
|
|
|
Button,
|
|
|
|
|
Dropdown,
|
|
|
|
|
Modal,
|
|
|
|
|
Switch,
|
|
|
|
|
Typography,
|
|
|
|
|
Select
|
|
|
|
|
} from '@douyinfe/semi-ui';
|
|
|
|
|
|
|
|
|
|
const ChannelsActions = ({
|
|
|
|
|
enableBatchDelete,
|
|
|
|
|
batchDeleteChannels,
|
|
|
|
|
setShowBatchSetTag,
|
|
|
|
|
testAllChannels,
|
|
|
|
|
fixChannelsAbilities,
|
|
|
|
|
updateAllChannelsBalance,
|
|
|
|
|
deleteAllDisabledChannels,
|
|
|
|
|
compactMode,
|
|
|
|
|
setCompactMode,
|
|
|
|
|
idSort,
|
|
|
|
|
setIdSort,
|
|
|
|
|
setEnableBatchDelete,
|
|
|
|
|
enableTagMode,
|
|
|
|
|
setEnableTagMode,
|
|
|
|
|
statusFilter,
|
|
|
|
|
setStatusFilter,
|
|
|
|
|
getFormValues,
|
|
|
|
|
loadChannels,
|
|
|
|
|
searchChannels,
|
|
|
|
|
activeTypeKey,
|
|
|
|
|
activePage,
|
|
|
|
|
pageSize,
|
|
|
|
|
setActivePage,
|
|
|
|
|
t
|
|
|
|
|
}) => {
|
|
|
|
|
return (
|
2025-07-18 22:04:54 +08:00
|
|
|
<div className="flex flex-col gap-2">
|
🚀 feat(web/channels): Deep modular refactor of Channels table
1. Split monolithic `ChannelsTable` (2200+ LOC) into focused components
• `channels/index.jsx` – composition entry
• `ChannelsTable.jsx` – pure `<Table>` rendering
• `ChannelsActions.jsx` – bulk & settings toolbar
• `ChannelsFilters.jsx` – search / create / column-settings form
• `ChannelsTabs.jsx` – type tabs
• `ChannelsColumnDefs.js` – column definitions & render helpers
• `modals/` – BatchTag, ColumnSelector, ModelTest modals
2. Extract domain hook
• Moved `useChannelsData.js` → `src/hooks/channels/useChannelsData.js`
– centralises state, API calls, pagination, filters, batch ops
– now exports `setActivePage`, fixing tab / status switch errors
3. Update wiring
• All sub-components consume data via `useChannelsData` props
• Adjusted import paths after hook relocation
4. Clean legacy file
• Legacy `components/table/ChannelsTable.js` now re-exports new module
5. Bug fixes
• Tab switching, status filter & tag aggregation restored
• Column selector & batch actions operate via unified hook
This commit completes the first phase of modularising the Channels feature, laying groundwork for consistent, maintainable table architecture across the app.
2025-07-18 21:05:36 +08:00
|
|
|
{/* 第一行:批量操作按钮 + 设置开关 */}
|
2025-07-18 22:04:54 +08:00
|
|
|
<div className="flex flex-col md:flex-row justify-between gap-2">
|
🚀 feat(web/channels): Deep modular refactor of Channels table
1. Split monolithic `ChannelsTable` (2200+ LOC) into focused components
• `channels/index.jsx` – composition entry
• `ChannelsTable.jsx` – pure `<Table>` rendering
• `ChannelsActions.jsx` – bulk & settings toolbar
• `ChannelsFilters.jsx` – search / create / column-settings form
• `ChannelsTabs.jsx` – type tabs
• `ChannelsColumnDefs.js` – column definitions & render helpers
• `modals/` – BatchTag, ColumnSelector, ModelTest modals
2. Extract domain hook
• Moved `useChannelsData.js` → `src/hooks/channels/useChannelsData.js`
– centralises state, API calls, pagination, filters, batch ops
– now exports `setActivePage`, fixing tab / status switch errors
3. Update wiring
• All sub-components consume data via `useChannelsData` props
• Adjusted import paths after hook relocation
4. Clean legacy file
• Legacy `components/table/ChannelsTable.js` now re-exports new module
5. Bug fixes
• Tab switching, status filter & tag aggregation restored
• Column selector & batch actions operate via unified hook
This commit completes the first phase of modularising the Channels feature, laying groundwork for consistent, maintainable table architecture across the app.
2025-07-18 21:05:36 +08:00
|
|
|
{/* 左侧:批量操作按钮 */}
|
|
|
|
|
<div className="flex flex-wrap md:flex-nowrap items-center gap-2 w-full md:w-auto order-2 md:order-1">
|
|
|
|
|
<Button
|
|
|
|
|
size='small'
|
|
|
|
|
disabled={!enableBatchDelete}
|
|
|
|
|
type='danger'
|
|
|
|
|
className="w-full md:w-auto"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: t('确定是否要删除所选通道?'),
|
|
|
|
|
content: t('此修改将不可逆'),
|
|
|
|
|
onOk: () => batchDeleteChannels(),
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{t('删除所选通道')}
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
size='small'
|
|
|
|
|
disabled={!enableBatchDelete}
|
|
|
|
|
type='tertiary'
|
|
|
|
|
onClick={() => setShowBatchSetTag(true)}
|
|
|
|
|
className="w-full md:w-auto"
|
|
|
|
|
>
|
|
|
|
|
{t('批量设置标签')}
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<Dropdown
|
|
|
|
|
size='small'
|
|
|
|
|
trigger='click'
|
|
|
|
|
render={
|
|
|
|
|
<Dropdown.Menu>
|
|
|
|
|
<Dropdown.Item>
|
|
|
|
|
<Button
|
|
|
|
|
size='small'
|
|
|
|
|
type='tertiary'
|
|
|
|
|
className="w-full"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: t('确定?'),
|
|
|
|
|
content: t('确定要测试所有通道吗?'),
|
|
|
|
|
onOk: () => testAllChannels(),
|
|
|
|
|
size: 'small',
|
|
|
|
|
centered: true,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{t('测试所有通道')}
|
|
|
|
|
</Button>
|
|
|
|
|
</Dropdown.Item>
|
|
|
|
|
<Dropdown.Item>
|
|
|
|
|
<Button
|
|
|
|
|
size='small'
|
|
|
|
|
className="w-full"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: t('确定是否要修复数据库一致性?'),
|
|
|
|
|
content: t('进行该操作时,可能导致渠道访问错误,请仅在数据库出现问题时使用'),
|
|
|
|
|
onOk: () => fixChannelsAbilities(),
|
|
|
|
|
size: 'sm',
|
|
|
|
|
centered: true,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{t('修复数据库一致性')}
|
|
|
|
|
</Button>
|
|
|
|
|
</Dropdown.Item>
|
|
|
|
|
<Dropdown.Item>
|
|
|
|
|
<Button
|
|
|
|
|
size='small'
|
|
|
|
|
type='secondary'
|
|
|
|
|
className="w-full"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: t('确定?'),
|
|
|
|
|
content: t('确定要更新所有已启用通道余额吗?'),
|
|
|
|
|
onOk: () => updateAllChannelsBalance(),
|
|
|
|
|
size: 'sm',
|
|
|
|
|
centered: true,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{t('更新所有已启用通道余额')}
|
|
|
|
|
</Button>
|
|
|
|
|
</Dropdown.Item>
|
|
|
|
|
<Dropdown.Item>
|
|
|
|
|
<Button
|
|
|
|
|
size='small'
|
|
|
|
|
type='danger'
|
|
|
|
|
className="w-full"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: t('确定是否要删除禁用通道?'),
|
|
|
|
|
content: t('此修改将不可逆'),
|
|
|
|
|
onOk: () => deleteAllDisabledChannels(),
|
|
|
|
|
size: 'sm',
|
|
|
|
|
centered: true,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{t('删除禁用通道')}
|
|
|
|
|
</Button>
|
|
|
|
|
</Dropdown.Item>
|
|
|
|
|
</Dropdown.Menu>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<Button size='small' theme='light' type='tertiary' className="w-full md:w-auto">
|
|
|
|
|
{t('批量操作')}
|
|
|
|
|
</Button>
|
|
|
|
|
</Dropdown>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
size='small'
|
|
|
|
|
type='tertiary'
|
|
|
|
|
className="w-full md:w-auto"
|
|
|
|
|
onClick={() => setCompactMode(!compactMode)}
|
|
|
|
|
>
|
|
|
|
|
{compactMode ? t('自适应列表') : t('紧凑列表')}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 右侧:设置开关区域 */}
|
2025-07-18 22:04:54 +08:00
|
|
|
<div className="flex flex-col md:flex-row items-start md:items-center gap-2 w-full md:w-auto order-1 md:order-2">
|
🚀 feat(web/channels): Deep modular refactor of Channels table
1. Split monolithic `ChannelsTable` (2200+ LOC) into focused components
• `channels/index.jsx` – composition entry
• `ChannelsTable.jsx` – pure `<Table>` rendering
• `ChannelsActions.jsx` – bulk & settings toolbar
• `ChannelsFilters.jsx` – search / create / column-settings form
• `ChannelsTabs.jsx` – type tabs
• `ChannelsColumnDefs.js` – column definitions & render helpers
• `modals/` – BatchTag, ColumnSelector, ModelTest modals
2. Extract domain hook
• Moved `useChannelsData.js` → `src/hooks/channels/useChannelsData.js`
– centralises state, API calls, pagination, filters, batch ops
– now exports `setActivePage`, fixing tab / status switch errors
3. Update wiring
• All sub-components consume data via `useChannelsData` props
• Adjusted import paths after hook relocation
4. Clean legacy file
• Legacy `components/table/ChannelsTable.js` now re-exports new module
5. Bug fixes
• Tab switching, status filter & tag aggregation restored
• Column selector & batch actions operate via unified hook
This commit completes the first phase of modularising the Channels feature, laying groundwork for consistent, maintainable table architecture across the app.
2025-07-18 21:05:36 +08:00
|
|
|
<div className="flex items-center justify-between w-full md:w-auto">
|
|
|
|
|
<Typography.Text strong className="mr-2">
|
|
|
|
|
{t('使用ID排序')}
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
<Switch
|
|
|
|
|
size='small'
|
|
|
|
|
checked={idSort}
|
|
|
|
|
onChange={(v) => {
|
|
|
|
|
localStorage.setItem('id-sort', v + '');
|
|
|
|
|
setIdSort(v);
|
|
|
|
|
const { searchKeyword, searchGroup, searchModel } = getFormValues();
|
|
|
|
|
if (searchKeyword === '' && searchGroup === '' && searchModel === '') {
|
|
|
|
|
loadChannels(activePage, pageSize, v, enableTagMode);
|
|
|
|
|
} else {
|
|
|
|
|
searchChannels(enableTagMode, activeTypeKey, statusFilter, activePage, pageSize, v);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between w-full md:w-auto">
|
|
|
|
|
<Typography.Text strong className="mr-2">
|
|
|
|
|
{t('开启批量操作')}
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
<Switch
|
|
|
|
|
size='small'
|
|
|
|
|
checked={enableBatchDelete}
|
|
|
|
|
onChange={(v) => {
|
|
|
|
|
localStorage.setItem('enable-batch-delete', v + '');
|
|
|
|
|
setEnableBatchDelete(v);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between w-full md:w-auto">
|
|
|
|
|
<Typography.Text strong className="mr-2">
|
|
|
|
|
{t('标签聚合模式')}
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
<Switch
|
|
|
|
|
size='small'
|
|
|
|
|
checked={enableTagMode}
|
|
|
|
|
onChange={(v) => {
|
|
|
|
|
localStorage.setItem('enable-tag-mode', v + '');
|
|
|
|
|
setEnableTagMode(v);
|
|
|
|
|
setActivePage(1);
|
|
|
|
|
loadChannels(1, pageSize, idSort, v);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center justify-between w-full md:w-auto">
|
|
|
|
|
<Typography.Text strong className="mr-2">
|
|
|
|
|
{t('状态筛选')}
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
<Select
|
|
|
|
|
size='small'
|
|
|
|
|
value={statusFilter}
|
|
|
|
|
onChange={(v) => {
|
|
|
|
|
localStorage.setItem('channel-status-filter', v);
|
|
|
|
|
setStatusFilter(v);
|
|
|
|
|
setActivePage(1);
|
|
|
|
|
loadChannels(1, pageSize, idSort, enableTagMode, activeTypeKey, v);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Select.Option value="all">{t('全部')}</Select.Option>
|
|
|
|
|
<Select.Option value="enabled">{t('已启用')}</Select.Option>
|
|
|
|
|
<Select.Option value="disabled">{t('已禁用')}</Select.Option>
|
|
|
|
|
</Select>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default ChannelsActions;
|