diff --git a/web/src/components/common/ui/CardTable.js b/web/src/components/common/ui/CardTable.js
index f39c6d48..b24bc708 100644
--- a/web/src/components/common/ui/CardTable.js
+++ b/web/src/components/common/ui/CardTable.js
@@ -18,7 +18,9 @@ For commercial licensing, please contact support@quantumnous.com
*/
import React, { useState, useEffect, useRef } from 'react';
-import { Table, Card, Skeleton, Pagination, Empty } from '@douyinfe/semi-ui';
+import { useTranslation } from 'react-i18next';
+import { Table, Card, Skeleton, Pagination, Empty, Button, Collapsible } from '@douyinfe/semi-ui';
+import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons';
import PropTypes from 'prop-types';
import { useIsMobile } from '../../../hooks/common/useIsMobile';
@@ -30,6 +32,7 @@ import { useIsMobile } from '../../../hooks/common/useIsMobile';
*/
const CardTable = ({ columns = [], dataSource = [], loading = false, rowKey = 'key', ...tableProps }) => {
const isMobile = useIsMobile();
+ const { t } = useTranslation();
// Skeleton 显示控制,确保至少展示 500ms 动效
const [showSkeleton, setShowSkeleton] = useState(loading);
@@ -94,7 +97,14 @@ const CardTable = ({ columns = [], dataSource = [], loading = false, rowKey = 'k
return (
-
+
);
})}
@@ -118,6 +128,78 @@ const CardTable = ({ columns = [], dataSource = [], loading = false, rowKey = 'k
// 渲染移动端卡片
const isEmpty = !showSkeleton && (!dataSource || dataSource.length === 0);
+ // 移动端行卡片组件(含可折叠详情)
+ const MobileRowCard = ({ record, index }) => {
+ const [showDetails, setShowDetails] = useState(false);
+ const rowKeyVal = getRowKey(record, index);
+
+ const hasDetails =
+ tableProps.expandedRowRender &&
+ (!tableProps.rowExpandable || tableProps.rowExpandable(record));
+
+ return (
+
+ {columns.map((col, colIdx) => {
+ // 忽略隐藏列
+ if (tableProps?.visibleColumns && !tableProps.visibleColumns[col.key]) {
+ return null;
+ }
+
+ const title = col.title;
+ const cellContent = col.render
+ ? col.render(record[col.dataIndex], record, index)
+ : record[col.dataIndex];
+
+ // 空标题列(通常为操作按钮)单独渲染
+ if (!title) {
+ return (
+
+ {cellContent}
+
+ );
+ }
+
+ return (
+
+
+ {title}
+
+
+ {cellContent !== undefined && cellContent !== null ? cellContent : '-'}
+
+
+ );
+ })}
+
+ {hasDetails && (
+ <>
+ : }
+ onClick={(e) => {
+ e.stopPropagation();
+ setShowDetails(!showDetails);
+ }}
+ >
+ {showDetails ? t('收起') : t('详情')}
+
+
+
+ {tableProps.expandedRowRender(record, index)}
+
+
+ >
+ )}
+
+ );
+ };
+
if (isEmpty) {
// 若传入 empty 属性则使用之,否则使用默认 Empty
if (tableProps.empty) return tableProps.empty;
@@ -130,52 +212,9 @@ const CardTable = ({ columns = [], dataSource = [], loading = false, rowKey = 'k
return (
- {dataSource.map((record, index) => {
- const rowKeyVal = getRowKey(record, index);
- return (
-
- {columns.map((col, colIdx) => {
- // 忽略隐藏列
- if (tableProps?.visibleColumns && !tableProps.visibleColumns[col.key]) {
- return null;
- }
-
- const title = col.title;
- // 计算单元格内容
- const cellContent = col.render
- ? col.render(record[col.dataIndex], record, index)
- : record[col.dataIndex];
-
- // 空标题列(通常为操作按钮)单独渲染
- if (!title) {
- return (
-
- {cellContent}
-
- );
- }
-
- return (
-
-
- {title}
-
-
- {cellContent !== undefined && cellContent !== null ? cellContent : '-'}
-
-
- );
- })}
-
- );
- })}
+ {dataSource.map((record, index) => (
+
+ ))}
{/* 分页组件 */}
{tableProps.pagination && dataSource.length > 0 && (
diff --git a/web/src/components/table/usage-logs/UsageLogsColumnDefs.js b/web/src/components/table/usage-logs/UsageLogsColumnDefs.js
index 2de5f7e2..d4ff1713 100644
--- a/web/src/components/table/usage-logs/UsageLogsColumnDefs.js
+++ b/web/src/components/table/usage-logs/UsageLogsColumnDefs.js
@@ -268,12 +268,14 @@ export const getLogsColumns = ({
return isAdminUser && (record.type === 0 || record.type === 2 || record.type === 5) ? (
-
- {text}
-
+
+
+ {text}
+
+
{isMultiKey && (
@@ -466,15 +468,17 @@ export const getLogsColumns = ({
render: (text, record, index) => {
return (record.type === 2 || record.type === 5) && text ? (
- {
- copyText(event, text);
- }}
- >
- {text}
-
+
+ {
+ copyText(event, text);
+ }}
+ >
+ {text}
+
+
) : (
<>>