diff --git a/web/src/components/table/ChannelsTable.js b/web/src/components/table/ChannelsTable.js
index 7aef69ce..33e683a9 100644
--- a/web/src/components/table/ChannelsTable.js
+++ b/web/src/components/table/ChannelsTable.js
@@ -17,7 +17,7 @@ import {
AlertCircle,
HelpCircle,
Coins,
- Tags
+ Tags,
} from 'lucide-react';
import { CHANNEL_OPTIONS, ITEMS_PER_PAGE } from '../../constants/index.js';
@@ -52,6 +52,7 @@ import {
IconPlus,
IconRefresh,
IconSetting,
+ IconDescend,
IconSearch,
IconEdit,
IconDelete,
@@ -64,6 +65,7 @@ import {
import { loadChannelModels } from '../../helpers/index.js';
import EditTagModal from '../../pages/Channel/EditTagModal.js';
import { useTranslation } from 'react-i18next';
+import { useTableCompactMode } from '../../hooks/useTableCompactMode';
const ChannelsTable = () => {
const { t } = useTranslation();
@@ -683,6 +685,7 @@ const ChannelsTable = () => {
const [typeCounts, setTypeCounts] = useState({});
const requestCounter = useRef(0);
const [formApi, setFormApi] = useState(null);
+ const [compactMode, setCompactMode] = useTableCompactMode('channels');
const formInitValues = {
searchKeyword: '',
searchGroup: '',
@@ -1576,6 +1579,16 @@ const ChannelsTable = () => {
{t('批量操作')}
+
+ }
+ className="!rounded-full w-full md:w-auto"
+ onClick={() => setCompactMode(!compactMode)}
+ >
+ {compactMode ? t('自适应列表') : t('紧凑列表')}
+
@@ -1766,9 +1779,9 @@ const ChannelsTable = () => {
bordered={false}
>
rest) : getVisibleColumns()}
dataSource={pageData}
- scroll={{ x: 'max-content' }}
+ scroll={compactMode ? undefined : { x: 'max-content' }}
pagination={{
currentPage: activePage,
pageSize: pageSize,
diff --git a/web/src/components/table/LogsTable.js b/web/src/components/table/LogsTable.js
index 90e4a809..a6199441 100644
--- a/web/src/components/table/LogsTable.js
+++ b/web/src/components/table/LogsTable.js
@@ -47,8 +47,9 @@ import {
} from '@douyinfe/semi-illustrations';
import { ITEMS_PER_PAGE } from '../../constants';
import Paragraph from '@douyinfe/semi-ui/lib/es/typography/paragraph';
-import { IconSetting, IconSearch, IconHelpCircle } from '@douyinfe/semi-icons';
+import { IconSetting, IconSearch, IconHelpCircle, IconDescend } from '@douyinfe/semi-icons';
import { Route } from 'lucide-react';
+import { useTableCompactMode } from '../../hooks/useTableCompactMode';
const { Text } = Typography;
@@ -192,7 +193,7 @@ const LogsTable = () => {
if (!modelMapped) {
return renderModelTag(record.model_name, {
onClick: (event) => {
- copyText(event, record.model_name).then((r) => {});
+ copyText(event, record.model_name).then((r) => { });
},
});
} else {
@@ -209,7 +210,7 @@ const LogsTable = () => {
{renderModelTag(record.model_name, {
onClick: (event) => {
- copyText(event, record.model_name).then((r) => {});
+ copyText(event, record.model_name).then((r) => { });
},
})}
@@ -220,7 +221,7 @@ const LogsTable = () => {
{renderModelTag(other.upstream_model_name, {
onClick: (event) => {
copyText(event, other.upstream_model_name).then(
- (r) => {},
+ (r) => { },
);
},
})}
@@ -231,7 +232,7 @@ const LogsTable = () => {
>
{renderModelTag(record.model_name, {
onClick: (event) => {
- copyText(event, record.model_name).then((r) => {});
+ copyText(event, record.model_name).then((r) => { });
},
suffixIcon: (
{
}
let content = other?.claude
? renderClaudeModelPriceSimple(
- other.model_ratio,
- other.model_price,
- other.group_ratio,
- other?.user_group_ratio,
- other.cache_tokens || 0,
- other.cache_ratio || 1.0,
- other.cache_creation_tokens || 0,
- other.cache_creation_ratio || 1.0,
- )
+ other.model_ratio,
+ other.model_price,
+ other.group_ratio,
+ other?.user_group_ratio,
+ other.cache_tokens || 0,
+ other.cache_ratio || 1.0,
+ other.cache_creation_tokens || 0,
+ other.cache_creation_ratio || 1.0,
+ )
: renderModelPriceSimple(
- other.model_ratio,
- other.model_price,
- other.group_ratio,
- other?.user_group_ratio,
- other.cache_tokens || 0,
- other.cache_ratio || 1.0,
- );
+ other.model_ratio,
+ other.model_price,
+ other.group_ratio,
+ other?.user_group_ratio,
+ other.cache_tokens || 0,
+ other.cache_ratio || 1.0,
+ );
return (
{
key: t('日志详情'),
value: other?.claude
? renderClaudeLogContent(
- other?.model_ratio,
- other.completion_ratio,
- other.model_price,
- other.group_ratio,
- other?.user_group_ratio,
- other.cache_ratio || 1.0,
- other.cache_creation_ratio || 1.0,
- )
+ other?.model_ratio,
+ other.completion_ratio,
+ other.model_price,
+ other.group_ratio,
+ other?.user_group_ratio,
+ other.cache_ratio || 1.0,
+ other.cache_creation_ratio || 1.0,
+ )
: renderLogContent(
- other?.model_ratio,
- other.completion_ratio,
- other.model_price,
- other.group_ratio,
- other?.user_group_ratio,
- false,
- 1.0,
- other.web_search || false,
- other.web_search_call_count || 0,
- other.file_search || false,
- other.file_search_call_count || 0,
- ),
+ other?.model_ratio,
+ other.completion_ratio,
+ other.model_price,
+ other.group_ratio,
+ other?.user_group_ratio,
+ false,
+ 1.0,
+ other.web_search || false,
+ other.web_search_call_count || 0,
+ other.file_search || false,
+ other.file_search_call_count || 0,
+ ),
});
}
if (logs[i].type === 2) {
@@ -1145,7 +1146,7 @@ const LogsTable = () => {
const handlePageChange = (page) => {
setActivePage(page);
- loadLogs(page, pageSize).then((r) => {}); // 不传入logType,让其从表单获取最新值
+ loadLogs(page, pageSize).then((r) => { }); // 不传入logType,让其从表单获取最新值
};
const handlePageSizeChange = async (size) => {
@@ -1203,6 +1204,8 @@ const LogsTable = () => {
);
};
+ const [compactMode, setCompactMode] = useTableCompactMode('logs');
+
return (
<>
{renderColumnSelector()}
@@ -1211,45 +1214,57 @@ const LogsTable = () => {
title={
-
-
+
+
+ {t('消耗额度')}: {renderQuota(stat.quota)}
+
+
+ RPM: {stat.rpm}
+
+
+ TPM: {stat.tpm}
+
+
+
+ }
+ className="!rounded-full w-full md:w-auto"
+ onClick={() => setCompactMode(!compactMode)}
>
- {t('消耗额度')}: {renderQuota(stat.quota)}
-
-
- RPM: {stat.rpm}
-
-
- TPM: {stat.tpm}
-
-
+ {compactMode ? t('自适应列表') : t('紧凑列表')}
+
+
@@ -1382,7 +1397,6 @@ const LogsTable = () => {
if (formApi) {
formApi.reset();
setLogType(0);
- // 重置后立即查询,使用setTimeout确保表单重置完成
setTimeout(() => {
refresh();
}, 100);
@@ -1411,7 +1425,7 @@ const LogsTable = () => {
bordered={false}
>
rest) : getVisibleColumns()}
{...(hasExpandableRows() && {
expandedRowRender: expandRowRender,
expandRowByClick: true,
@@ -1421,7 +1435,7 @@ const LogsTable = () => {
dataSource={logs}
rowKey='key'
loading={loading}
- scroll={{ x: 'max-content' }}
+ scroll={compactMode ? undefined : { x: 'max-content' }}
className='rounded-xl overflow-hidden'
size='middle'
empty={
diff --git a/web/src/components/table/MjLogsTable.js b/web/src/components/table/MjLogsTable.js
index 869db485..008a7785 100644
--- a/web/src/components/table/MjLogsTable.js
+++ b/web/src/components/table/MjLogsTable.js
@@ -24,7 +24,7 @@ import {
XCircle,
Loader,
AlertCircle,
- Hash
+ Hash,
} from 'lucide-react';
import {
API,
@@ -59,8 +59,10 @@ import { ITEMS_PER_PAGE } from '../../constants';
import {
IconEyeOpened,
IconSearch,
- IconSetting
+ IconSetting,
+ IconDescend
} from '@douyinfe/semi-icons';
+import { useTableCompactMode } from '../../hooks/useTableCompactMode';
const { Text } = Typography;
@@ -107,6 +109,7 @@ const LogsTable = () => {
const [visibleColumns, setVisibleColumns] = useState({});
const [showColumnSelector, setShowColumnSelector] = useState(false);
const isAdminUser = isAdmin();
+ const [compactMode, setCompactMode] = useTableCompactMode('mjLogs');
// 加载保存的列偏好设置
useEffect(() => {
@@ -802,7 +805,7 @@ const LogsTable = () => {
className="!rounded-2xl mb-4"
title={
-
+
{loading ? (
@@ -821,6 +824,15 @@ const LogsTable = () => {
)}
+
}
+ className="!rounded-full w-full md:w-auto"
+ onClick={() => setCompactMode(!compactMode)}
+ >
+ {compactMode ? t('自适应列表') : t('紧凑列表')}
+
@@ -919,11 +931,11 @@ const LogsTable = () => {
bordered={false}
>
rest) : getVisibleColumns()}
dataSource={logs}
rowKey='key'
loading={loading}
- scroll={{ x: 'max-content' }}
+ scroll={compactMode ? undefined : { x: 'max-content' }}
className="rounded-xl overflow-hidden"
size="middle"
empty={
diff --git a/web/src/components/table/RedemptionsTable.js b/web/src/components/table/RedemptionsTable.js
index e11a4657..f02d6166 100644
--- a/web/src/components/table/RedemptionsTable.js
+++ b/web/src/components/table/RedemptionsTable.js
@@ -45,10 +45,12 @@ import {
IconDelete,
IconStop,
IconPlay,
- IconMore
+ IconMore,
+ IconDescend
} from '@douyinfe/semi-icons';
import EditRedemption from '../../pages/Redemption/EditRedemption';
import { useTranslation } from 'react-i18next';
+import { useTableCompactMode } from '../../hooks/useTableCompactMode';
const { Text } = Typography;
@@ -266,6 +268,7 @@ const RedemptionsTable = () => {
id: undefined,
});
const [showEdit, setShowEdit] = useState(false);
+ const [compactMode, setCompactMode] = useTableCompactMode('redemptions');
// Form 初始值
const formInitValues = {
@@ -465,9 +468,20 @@ const RedemptionsTable = () => {
const renderHeader = () => (
-
-
-
{t('兑换码可以批量生成和分发,适合用于推广活动或批量充值。')}
+
+
+
+ {t('兑换码可以批量生成和分发,适合用于推广活动或批量充值。')}
+
+
}
+ className="!rounded-full w-full md:w-auto"
+ onClick={() => setCompactMode(!compactMode)}
+ >
+ {compactMode ? t('自适应列表') : t('紧凑列表')}
+
@@ -610,9 +624,9 @@ const RedemptionsTable = () => {
bordered={false}
>
rest) : columns}
dataSource={pageData}
- scroll={{ x: 'max-content' }}
+ scroll={compactMode ? undefined : { x: 'max-content' }}
pagination={{
currentPage: activePage,
pageSize: pageSize,
diff --git a/web/src/components/table/TaskLogsTable.js b/web/src/components/table/TaskLogsTable.js
index 37bdde57..8b309942 100644
--- a/web/src/components/table/TaskLogsTable.js
+++ b/web/src/components/table/TaskLogsTable.js
@@ -47,8 +47,10 @@ import { ITEMS_PER_PAGE } from '../../constants';
import {
IconEyeOpened,
IconSearch,
- IconSetting
+ IconSetting,
+ IconDescend
} from '@douyinfe/semi-icons';
+import { useTableCompactMode } from '../../hooks/useTableCompactMode';
const { Text } = Typography;
@@ -471,6 +473,8 @@ const LogsTable = () => {
const [logs, setLogs] = useState([]);
const [loading, setLoading] = useState(false);
+ const [compactMode, setCompactMode] = useTableCompactMode('taskLogs');
+
useEffect(() => {
const localPageSize = parseInt(localStorage.getItem('task-page-size')) || ITEMS_PER_PAGE;
setPageSize(localPageSize);
@@ -650,7 +654,7 @@ const LogsTable = () => {
className="!rounded-2xl mb-4"
title={
-
+
{loading ? (
@@ -665,6 +669,15 @@ const LogsTable = () => {
{t('任务记录')}
)}
+
}
+ className="!rounded-full w-full md:w-auto"
+ onClick={() => setCompactMode(!compactMode)}
+ >
+ {compactMode ? t('自适应列表') : t('紧凑列表')}
+
@@ -763,11 +776,11 @@ const LogsTable = () => {
bordered={false}
>
rest) : getVisibleColumns()}
dataSource={logs}
rowKey='key'
loading={loading}
- scroll={{ x: 'max-content' }}
+ scroll={compactMode ? undefined : { x: 'max-content' }}
className="rounded-xl overflow-hidden"
size="middle"
empty={
diff --git a/web/src/components/table/TokensTable.js b/web/src/components/table/TokensTable.js
index 0a049c39..5c3ba658 100644
--- a/web/src/components/table/TokensTable.js
+++ b/web/src/components/table/TokensTable.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useMemo } from 'react';
import {
API,
copy,
@@ -52,10 +52,12 @@ import {
IconDelete,
IconStop,
IconPlay,
- IconMore
+ IconMore,
+ IconDescend
} from '@douyinfe/semi-icons';
import EditToken from '../../pages/Token/EditToken';
import { useTranslation } from 'react-i18next';
+import { useTableCompactMode } from '../../hooks/useTableCompactMode';
const { Text } = Typography;
@@ -385,6 +387,7 @@ const TokensTable = () => {
const [editingToken, setEditingToken] = useState({
id: undefined,
});
+ const [compactMode, setCompactMode] = useTableCompactMode('tokens');
// Form 初始值
const formInitValues = {
@@ -610,9 +613,20 @@ const TokensTable = () => {
const renderHeader = () => (
-
-
-
{t('令牌用于API访问认证,可以设置额度限制和模型权限。')}
+
+
+
+ {t('令牌用于API访问认证,可以设置额度限制和模型权限。')}
+
+
}
+ className="!rounded-full w-full md:w-auto"
+ onClick={() => setCompactMode(!compactMode)}
+ >
+ {compactMode ? t('自适应列表') : t('紧凑列表')}
+
@@ -687,7 +701,6 @@ const TokensTable = () => {
>
{t('复制所选令牌')}
-