♻️Refactor: Logs Page
This commit is contained in:
@@ -14,8 +14,6 @@ import {
|
|||||||
Avatar,
|
Avatar,
|
||||||
Button,
|
Button,
|
||||||
Descriptions,
|
Descriptions,
|
||||||
Form,
|
|
||||||
Layout,
|
|
||||||
Modal,
|
Modal,
|
||||||
Popover,
|
Popover,
|
||||||
Select,
|
Select,
|
||||||
@@ -25,6 +23,11 @@ import {
|
|||||||
Tag,
|
Tag,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
|
Card,
|
||||||
|
Typography,
|
||||||
|
Divider,
|
||||||
|
Input,
|
||||||
|
DatePicker,
|
||||||
} from '@douyinfe/semi-ui';
|
} from '@douyinfe/semi-ui';
|
||||||
import { ITEMS_PER_PAGE } from '../constants';
|
import { ITEMS_PER_PAGE } from '../constants';
|
||||||
import {
|
import {
|
||||||
@@ -43,9 +46,14 @@ import {
|
|||||||
import Paragraph from '@douyinfe/semi-ui/lib/es/typography/paragraph';
|
import Paragraph from '@douyinfe/semi-ui/lib/es/typography/paragraph';
|
||||||
import { getLogOther } from '../helpers/other.js';
|
import { getLogOther } from '../helpers/other.js';
|
||||||
import { StyleContext } from '../context/Style/index.js';
|
import { StyleContext } from '../context/Style/index.js';
|
||||||
import { IconInherit, IconRefresh, IconSetting } from '@douyinfe/semi-icons';
|
import {
|
||||||
|
IconRefresh,
|
||||||
|
IconSetting,
|
||||||
|
IconEyeOpened,
|
||||||
|
IconSearch,
|
||||||
|
} from '@douyinfe/semi-icons';
|
||||||
|
|
||||||
const { Header } = Layout;
|
const { Text } = Typography;
|
||||||
|
|
||||||
function renderTimestamp(timestamp) {
|
function renderTimestamp(timestamp) {
|
||||||
return <>{timestamp2string(timestamp)}</>;
|
return <>{timestamp2string(timestamp)}</>;
|
||||||
@@ -81,37 +89,37 @@ const LogsTable = () => {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case 1:
|
case 1:
|
||||||
return (
|
return (
|
||||||
<Tag color='cyan' size='large'>
|
<Tag color='cyan' size='large' shape='circle'>
|
||||||
{t('充值')}
|
{t('充值')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
return (
|
return (
|
||||||
<Tag color='lime' size='large'>
|
<Tag color='lime' size='large' shape='circle'>
|
||||||
{t('消费')}
|
{t('消费')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
case 3:
|
case 3:
|
||||||
return (
|
return (
|
||||||
<Tag color='orange' size='large'>
|
<Tag color='orange' size='large' shape='circle'>
|
||||||
{t('管理')}
|
{t('管理')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
case 4:
|
case 4:
|
||||||
return (
|
return (
|
||||||
<Tag color='purple' size='large'>
|
<Tag color='purple' size='large' shape='circle'>
|
||||||
{t('系统')}
|
{t('系统')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
case 5:
|
case 5:
|
||||||
return (
|
return (
|
||||||
<Tag color='red' size='large'>
|
<Tag color='red' size='large' shape='circle'>
|
||||||
{t('错误')}
|
{t('错误')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<Tag color='grey' size='large'>
|
<Tag color='grey' size='large' shape='circle'>
|
||||||
{t('未知')}
|
{t('未知')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
@@ -121,13 +129,13 @@ const LogsTable = () => {
|
|||||||
function renderIsStream(bool) {
|
function renderIsStream(bool) {
|
||||||
if (bool) {
|
if (bool) {
|
||||||
return (
|
return (
|
||||||
<Tag color='blue' size='large'>
|
<Tag color='blue' size='large' shape='circle'>
|
||||||
{t('流')}
|
{t('流')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Tag color='purple' size='large'>
|
<Tag color='purple' size='large' shape='circle'>
|
||||||
{t('非流')}
|
{t('非流')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
@@ -138,21 +146,21 @@ const LogsTable = () => {
|
|||||||
const time = parseInt(type);
|
const time = parseInt(type);
|
||||||
if (time < 101) {
|
if (time < 101) {
|
||||||
return (
|
return (
|
||||||
<Tag color='green' size='large'>
|
<Tag color='green' size='large' shape='circle'>
|
||||||
{' '}
|
{' '}
|
||||||
{time} s{' '}
|
{time} s{' '}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else if (time < 300) {
|
} else if (time < 300) {
|
||||||
return (
|
return (
|
||||||
<Tag color='orange' size='large'>
|
<Tag color='orange' size='large' shape='circle'>
|
||||||
{' '}
|
{' '}
|
||||||
{time} s{' '}
|
{time} s{' '}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Tag color='red' size='large'>
|
<Tag color='red' size='large' shape='circle'>
|
||||||
{' '}
|
{' '}
|
||||||
{time} s{' '}
|
{time} s{' '}
|
||||||
</Tag>
|
</Tag>
|
||||||
@@ -165,21 +173,21 @@ const LogsTable = () => {
|
|||||||
time = time.toFixed(1);
|
time = time.toFixed(1);
|
||||||
if (time < 3) {
|
if (time < 3) {
|
||||||
return (
|
return (
|
||||||
<Tag color='green' size='large'>
|
<Tag color='green' size='large' shape='circle'>
|
||||||
{' '}
|
{' '}
|
||||||
{time} s{' '}
|
{time} s{' '}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else if (time < 10) {
|
} else if (time < 10) {
|
||||||
return (
|
return (
|
||||||
<Tag color='orange' size='large'>
|
<Tag color='orange' size='large' shape='circle'>
|
||||||
{' '}
|
{' '}
|
||||||
{time} s{' '}
|
{time} s{' '}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Tag color='red' size='large'>
|
<Tag color='red' size='large' shape='circle'>
|
||||||
{' '}
|
{' '}
|
||||||
{time} s{' '}
|
{time} s{' '}
|
||||||
</Tag>
|
</Tag>
|
||||||
@@ -198,8 +206,9 @@ const LogsTable = () => {
|
|||||||
<Tag
|
<Tag
|
||||||
color={stringToColor(record.model_name)}
|
color={stringToColor(record.model_name)}
|
||||||
size='large'
|
size='large'
|
||||||
|
shape='circle'
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
copyText(event, record.model_name).then((r) => {});
|
copyText(event, record.model_name).then((r) => { });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{' '}
|
{' '}
|
||||||
@@ -217,8 +226,9 @@ const LogsTable = () => {
|
|||||||
<Tag
|
<Tag
|
||||||
color={stringToColor(record.model_name)}
|
color={stringToColor(record.model_name)}
|
||||||
size='large'
|
size='large'
|
||||||
|
shape='circle'
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
copyText(event, record.model_name).then((r) => {});
|
copyText(event, record.model_name).then((r) => { });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('请求并计费模型')} {record.model_name}{' '}
|
{t('请求并计费模型')} {record.model_name}{' '}
|
||||||
@@ -226,9 +236,10 @@ const LogsTable = () => {
|
|||||||
<Tag
|
<Tag
|
||||||
color={stringToColor(other.upstream_model_name)}
|
color={stringToColor(other.upstream_model_name)}
|
||||||
size='large'
|
size='large'
|
||||||
|
shape='circle'
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
copyText(event, other.upstream_model_name).then(
|
copyText(event, other.upstream_model_name).then(
|
||||||
(r) => {},
|
(r) => { },
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -241,8 +252,9 @@ const LogsTable = () => {
|
|||||||
<Tag
|
<Tag
|
||||||
color={stringToColor(record.model_name)}
|
color={stringToColor(record.model_name)}
|
||||||
size='large'
|
size='large'
|
||||||
|
shape='circle'
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
copyText(event, record.model_name).then((r) => {});
|
copyText(event, record.model_name).then((r) => { });
|
||||||
}}
|
}}
|
||||||
suffixIcon={
|
suffixIcon={
|
||||||
<IconRefresh
|
<IconRefresh
|
||||||
@@ -254,17 +266,6 @@ const LogsTable = () => {
|
|||||||
{record.model_name}{' '}
|
{record.model_name}{' '}
|
||||||
</Tag>
|
</Tag>
|
||||||
</Popover>
|
</Popover>
|
||||||
{/*<Tooltip content={t('实际模型')}>*/}
|
|
||||||
{/* <Tag*/}
|
|
||||||
{/* color={stringToColor(other.upstream_model_name)}*/}
|
|
||||||
{/* size='large'*/}
|
|
||||||
{/* onClick={(event) => {*/}
|
|
||||||
{/* copyText(event, other.upstream_model_name).then(r => {});*/}
|
|
||||||
{/* }}*/}
|
|
||||||
{/* >*/}
|
|
||||||
{/* {' '}{other.upstream_model_name}{' '}*/}
|
|
||||||
{/* </Tag>*/}
|
|
||||||
{/*</Tooltip>*/}
|
|
||||||
</Space>
|
</Space>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -386,6 +387,7 @@ const LogsTable = () => {
|
|||||||
<Tag
|
<Tag
|
||||||
color={colors[parseInt(text) % colors.length]}
|
color={colors[parseInt(text) % colors.length]}
|
||||||
size='large'
|
size='large'
|
||||||
|
shape='circle'
|
||||||
>
|
>
|
||||||
{' '}
|
{' '}
|
||||||
{text}{' '}
|
{text}{' '}
|
||||||
@@ -437,6 +439,7 @@ const LogsTable = () => {
|
|||||||
<Tag
|
<Tag
|
||||||
color='grey'
|
color='grey'
|
||||||
size='large'
|
size='large'
|
||||||
|
shape='circle'
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
//cancel the row click event
|
//cancel the row click event
|
||||||
copyText(event, text);
|
copyText(event, text);
|
||||||
@@ -620,21 +623,21 @@ const LogsTable = () => {
|
|||||||
}
|
}
|
||||||
let content = other?.claude
|
let content = other?.claude
|
||||||
? renderClaudeModelPriceSimple(
|
? renderClaudeModelPriceSimple(
|
||||||
other.model_ratio,
|
other.model_ratio,
|
||||||
other.model_price,
|
other.model_price,
|
||||||
other.group_ratio,
|
other.group_ratio,
|
||||||
other.cache_tokens || 0,
|
other.cache_tokens || 0,
|
||||||
other.cache_ratio || 1.0,
|
other.cache_ratio || 1.0,
|
||||||
other.cache_creation_tokens || 0,
|
other.cache_creation_tokens || 0,
|
||||||
other.cache_creation_ratio || 1.0,
|
other.cache_creation_ratio || 1.0,
|
||||||
)
|
)
|
||||||
: renderModelPriceSimple(
|
: renderModelPriceSimple(
|
||||||
other.model_ratio,
|
other.model_ratio,
|
||||||
other.model_price,
|
other.model_price,
|
||||||
other.group_ratio,
|
other.group_ratio,
|
||||||
other.cache_tokens || 0,
|
other.cache_tokens || 0,
|
||||||
other.cache_ratio || 1.0,
|
other.cache_ratio || 1.0,
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<Paragraph
|
<Paragraph
|
||||||
ellipsis={{
|
ellipsis={{
|
||||||
@@ -673,15 +676,29 @@ const LogsTable = () => {
|
|||||||
visible={showColumnSelector}
|
visible={showColumnSelector}
|
||||||
onCancel={() => setShowColumnSelector(false)}
|
onCancel={() => setShowColumnSelector(false)}
|
||||||
footer={
|
footer={
|
||||||
<>
|
<div className="flex justify-end">
|
||||||
<Button onClick={() => initDefaultColumns()}>{t('重置')}</Button>
|
<Button
|
||||||
<Button onClick={() => setShowColumnSelector(false)}>
|
theme="light"
|
||||||
|
onClick={() => initDefaultColumns()}
|
||||||
|
className="!rounded-full"
|
||||||
|
>
|
||||||
|
{t('重置')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
theme="light"
|
||||||
|
onClick={() => setShowColumnSelector(false)}
|
||||||
|
className="!rounded-full"
|
||||||
|
>
|
||||||
{t('取消')}
|
{t('取消')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type='primary' onClick={() => setShowColumnSelector(false)}>
|
<Button
|
||||||
|
type='primary'
|
||||||
|
onClick={() => setShowColumnSelector(false)}
|
||||||
|
className="!rounded-full"
|
||||||
|
>
|
||||||
{t('确定')}
|
{t('确定')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div style={{ marginBottom: 20 }}>
|
<div style={{ marginBottom: 20 }}>
|
||||||
@@ -697,15 +714,7 @@ const LogsTable = () => {
|
|||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
className="flex flex-wrap max-h-96 overflow-y-auto rounded-lg p-4"
|
||||||
display: 'flex',
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
maxHeight: '400px',
|
|
||||||
overflowY: 'auto',
|
|
||||||
border: '1px solid var(--semi-color-border)',
|
|
||||||
borderRadius: '6px',
|
|
||||||
padding: '16px',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{allColumns.map((column) => {
|
{allColumns.map((column) => {
|
||||||
// Skip admin-only columns for non-admin users
|
// Skip admin-only columns for non-admin users
|
||||||
@@ -721,7 +730,7 @@ const LogsTable = () => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={column.key}
|
key={column.key}
|
||||||
style={{ width: '50%', marginBottom: 16, paddingRight: 8 }}
|
className="w-1/2 mb-4 pr-2"
|
||||||
>
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={!!visibleColumns[column.key]}
|
checked={!!visibleColumns[column.key]}
|
||||||
@@ -921,27 +930,27 @@ const LogsTable = () => {
|
|||||||
key: t('日志详情'),
|
key: t('日志详情'),
|
||||||
value: other?.claude
|
value: other?.claude
|
||||||
? renderClaudeLogContent(
|
? renderClaudeLogContent(
|
||||||
other?.model_ratio,
|
other?.model_ratio,
|
||||||
other.completion_ratio,
|
other.completion_ratio,
|
||||||
other.model_price,
|
other.model_price,
|
||||||
other.group_ratio,
|
other.group_ratio,
|
||||||
other.cache_ratio || 1.0,
|
other.cache_ratio || 1.0,
|
||||||
other.cache_creation_ratio || 1.0,
|
other.cache_creation_ratio || 1.0,
|
||||||
)
|
)
|
||||||
: renderLogContent(
|
: renderLogContent(
|
||||||
other?.model_ratio,
|
other?.model_ratio,
|
||||||
other.completion_ratio,
|
other.completion_ratio,
|
||||||
other.model_price,
|
other.model_price,
|
||||||
other.group_ratio,
|
other.group_ratio,
|
||||||
other?.user_group_ratio,
|
other?.user_group_ratio,
|
||||||
false,
|
false,
|
||||||
1.0,
|
1.0,
|
||||||
undefined,
|
undefined,
|
||||||
other.web_search || false,
|
other.web_search || false,
|
||||||
other.web_search_call_count || 0,
|
other.web_search_call_count || 0,
|
||||||
other.file_search || false,
|
other.file_search || false,
|
||||||
other.file_search_call_count || 0,
|
other.file_search_call_count || 0,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (logs[i].type === 2) {
|
if (logs[i].type === 2) {
|
||||||
@@ -1056,7 +1065,7 @@ const LogsTable = () => {
|
|||||||
|
|
||||||
const handlePageChange = (page) => {
|
const handlePageChange = (page) => {
|
||||||
setActivePage(page);
|
setActivePage(page);
|
||||||
loadLogs(page, pageSize, logType).then((r) => {});
|
loadLogs(page, pageSize, logType).then((r) => { });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePageSizeChange = async (size) => {
|
const handlePageSizeChange = async (size) => {
|
||||||
@@ -1104,86 +1113,56 @@ const LogsTable = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{renderColumnSelector()}
|
{renderColumnSelector()}
|
||||||
<Layout>
|
<Card
|
||||||
<Header>
|
className="!rounded-2xl overflow-hidden mb-4"
|
||||||
<Spin spinning={loadingStat}>
|
title={
|
||||||
<Space>
|
<div className="flex flex-col w-full">
|
||||||
<Tag
|
<div className="flex flex-col md:flex-row justify-between items-center">
|
||||||
color='blue'
|
<div className="flex items-center text-orange-500 mb-2 md:mb-0">
|
||||||
size='large'
|
<IconEyeOpened className="mr-2" />
|
||||||
style={{
|
<Text>{t('日志记录帮助您了解使用情况和排查问题')}</Text>
|
||||||
padding: 15,
|
</div>
|
||||||
borderRadius: '8px',
|
|
||||||
fontWeight: 500,
|
<Spin spinning={loadingStat}>
|
||||||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
|
<div className="flex flex-wrap gap-4">
|
||||||
}}
|
<div className="flex items-center">
|
||||||
>
|
<span className="text-xl mr-2">💰</span>
|
||||||
{t('消耗额度')}: {renderQuota(stat.quota)}
|
<div>
|
||||||
</Tag>
|
<Text type="tertiary" size="small">{t('消耗额度')}</Text>
|
||||||
<Tag
|
<div className="font-medium">{renderQuota(stat.quota)}</div>
|
||||||
color='pink'
|
</div>
|
||||||
size='large'
|
|
||||||
style={{
|
|
||||||
padding: 15,
|
|
||||||
borderRadius: '8px',
|
|
||||||
fontWeight: 500,
|
|
||||||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
RPM: {stat.rpm}
|
|
||||||
</Tag>
|
|
||||||
<Tag
|
|
||||||
color='white'
|
|
||||||
size='large'
|
|
||||||
style={{
|
|
||||||
padding: 15,
|
|
||||||
border: 'none',
|
|
||||||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
|
|
||||||
borderRadius: '8px',
|
|
||||||
fontWeight: 500,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
TPM: {stat.tpm}
|
|
||||||
</Tag>
|
|
||||||
</Space>
|
|
||||||
</Spin>
|
|
||||||
</Header>
|
|
||||||
<Form layout='horizontal' style={{ marginTop: 10 }}>
|
|
||||||
<>
|
|
||||||
<Form.Section>
|
|
||||||
<div style={{ marginBottom: 10 }}>
|
|
||||||
{styleState.isMobile ? (
|
|
||||||
<div>
|
|
||||||
<Form.DatePicker
|
|
||||||
field='start_timestamp'
|
|
||||||
label={t('起始时间')}
|
|
||||||
style={{ width: 272 }}
|
|
||||||
initValue={start_timestamp}
|
|
||||||
type='dateTime'
|
|
||||||
onChange={(value) => {
|
|
||||||
console.log(value);
|
|
||||||
handleInputChange(value, 'start_timestamp');
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Form.DatePicker
|
|
||||||
field='end_timestamp'
|
|
||||||
fluid
|
|
||||||
label={t('结束时间')}
|
|
||||||
style={{ width: 272 }}
|
|
||||||
initValue={end_timestamp}
|
|
||||||
type='dateTime'
|
|
||||||
onChange={(value) =>
|
|
||||||
handleInputChange(value, 'end_timestamp')
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<Form.DatePicker
|
<div className="flex items-center">
|
||||||
field='range_timestamp'
|
<span className="text-xl mr-2">📊</span>
|
||||||
label={t('时间范围')}
|
<div>
|
||||||
initValue={[start_timestamp, end_timestamp]}
|
<Text type="tertiary" size="small">RPM</Text>
|
||||||
|
<div className="font-medium">{stat.rpm || 0}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center">
|
||||||
|
<span className="text-xl mr-2">⚡</span>
|
||||||
|
<div>
|
||||||
|
<Text type="tertiary" size="small">TPM</Text>
|
||||||
|
<div className="font-medium">{stat.tpm || 0}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider margin="12px" />
|
||||||
|
|
||||||
|
{/* 搜索表单区域 */}
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
|
{/* 时间选择器 */}
|
||||||
|
<div className="col-span-1 lg:col-span-2">
|
||||||
|
<DatePicker
|
||||||
|
className="w-full"
|
||||||
|
value={[start_timestamp, end_timestamp]}
|
||||||
type='dateTimeRange'
|
type='dateTimeRange'
|
||||||
name='range_timestamp'
|
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
if (Array.isArray(value) && value.length === 2) {
|
if (Array.isArray(value) && value.length === 2) {
|
||||||
handleInputChange(value[0], 'start_timestamp');
|
handleInputChange(value[0], 'start_timestamp');
|
||||||
@@ -1191,100 +1170,113 @@ const LogsTable = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 日志类型选择器 */}
|
||||||
|
<Select
|
||||||
|
value={logType.toString()}
|
||||||
|
placeholder={t('日志类型')}
|
||||||
|
className="!rounded-full"
|
||||||
|
onChange={(value) => {
|
||||||
|
setLogType(parseInt(value));
|
||||||
|
loadLogs(0, pageSize, parseInt(value));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Select.Option value='0'>{t('全部')}</Select.Option>
|
||||||
|
<Select.Option value='1'>{t('充值')}</Select.Option>
|
||||||
|
<Select.Option value='2'>{t('消费')}</Select.Option>
|
||||||
|
<Select.Option value='3'>{t('管理')}</Select.Option>
|
||||||
|
<Select.Option value='4'>{t('系统')}</Select.Option>
|
||||||
|
<Select.Option value='5'>{t('错误')}</Select.Option>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
{/* 其他搜索字段 */}
|
||||||
|
<Input
|
||||||
|
prefix={<IconSearch />}
|
||||||
|
placeholder={t('令牌名称')}
|
||||||
|
value={token_name}
|
||||||
|
onChange={(value) => handleInputChange(value, 'token_name')}
|
||||||
|
className="!rounded-full"
|
||||||
|
showClear
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
prefix={<IconSearch />}
|
||||||
|
placeholder={t('模型名称')}
|
||||||
|
value={model_name}
|
||||||
|
onChange={(value) => handleInputChange(value, 'model_name')}
|
||||||
|
className="!rounded-full"
|
||||||
|
showClear
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
prefix={<IconSearch />}
|
||||||
|
placeholder={t('分组')}
|
||||||
|
value={group}
|
||||||
|
onChange={(value) => handleInputChange(value, 'group')}
|
||||||
|
className="!rounded-full"
|
||||||
|
showClear
|
||||||
|
/>
|
||||||
|
|
||||||
|
{isAdminUser && (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
prefix={<IconSearch />}
|
||||||
|
placeholder={t('渠道 ID')}
|
||||||
|
value={channel}
|
||||||
|
onChange={(value) => handleInputChange(value, 'channel')}
|
||||||
|
className="!rounded-full"
|
||||||
|
showClear
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
prefix={<IconSearch />}
|
||||||
|
placeholder={t('用户名称')}
|
||||||
|
value={username}
|
||||||
|
onChange={(value) => handleInputChange(value, 'username')}
|
||||||
|
className="!rounded-full"
|
||||||
|
showClear
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Form.Section>
|
|
||||||
<Form.Input
|
{/* 操作按钮区域 */}
|
||||||
field='token_name'
|
<div className="flex justify-between items-center pt-2">
|
||||||
label={t('令牌名称')}
|
<div></div>
|
||||||
value={token_name}
|
<div className="flex gap-2">
|
||||||
placeholder={t('可选值')}
|
<Button
|
||||||
name='token_name'
|
type='primary'
|
||||||
onChange={(value) => handleInputChange(value, 'token_name')}
|
onClick={refresh}
|
||||||
/>
|
loading={loading}
|
||||||
<Form.Input
|
className="!rounded-full"
|
||||||
field='model_name'
|
>
|
||||||
label={t('模型名称')}
|
{t('查询')}
|
||||||
value={model_name}
|
</Button>
|
||||||
placeholder={t('可选值')}
|
<Button
|
||||||
name='model_name'
|
theme='light'
|
||||||
onChange={(value) => handleInputChange(value, 'model_name')}
|
type='tertiary'
|
||||||
/>
|
icon={<IconSetting />}
|
||||||
<Form.Input
|
onClick={() => setShowColumnSelector(true)}
|
||||||
field='group'
|
className="!rounded-full"
|
||||||
label={t('分组')}
|
>
|
||||||
value={group}
|
{t('列设置')}
|
||||||
placeholder={t('可选值')}
|
</Button>
|
||||||
name='group'
|
</div>
|
||||||
onChange={(value) => handleInputChange(value, 'group')}
|
</div>
|
||||||
/>
|
</div>
|
||||||
{isAdminUser && (
|
</div>
|
||||||
<>
|
}
|
||||||
<Form.Input
|
shadows='hover'
|
||||||
field='channel'
|
>
|
||||||
label={t('渠道 ID')}
|
|
||||||
value={channel}
|
|
||||||
placeholder={t('可选值')}
|
|
||||||
name='channel'
|
|
||||||
onChange={(value) => handleInputChange(value, 'channel')}
|
|
||||||
/>
|
|
||||||
<Form.Input
|
|
||||||
field='username'
|
|
||||||
label={t('用户名称')}
|
|
||||||
value={username}
|
|
||||||
placeholder={t('可选值')}
|
|
||||||
name='username'
|
|
||||||
onChange={(value) => handleInputChange(value, 'username')}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Button
|
|
||||||
label={t('查询')}
|
|
||||||
type='primary'
|
|
||||||
htmlType='submit'
|
|
||||||
className='btn-margin-right'
|
|
||||||
onClick={refresh}
|
|
||||||
loading={loading}
|
|
||||||
style={{ marginTop: 24 }}
|
|
||||||
>
|
|
||||||
{t('查询')}
|
|
||||||
</Button>
|
|
||||||
<Form.Section></Form.Section>
|
|
||||||
</>
|
|
||||||
</Form>
|
|
||||||
<div style={{ marginTop: 10 }}>
|
|
||||||
<Select
|
|
||||||
defaultValue='0'
|
|
||||||
style={{ width: 120 }}
|
|
||||||
onChange={(value) => {
|
|
||||||
setLogType(parseInt(value));
|
|
||||||
loadLogs(0, pageSize, parseInt(value));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Select.Option value='0'>{t('全部')}</Select.Option>
|
|
||||||
<Select.Option value='1'>{t('充值')}</Select.Option>
|
|
||||||
<Select.Option value='2'>{t('消费')}</Select.Option>
|
|
||||||
<Select.Option value='3'>{t('管理')}</Select.Option>
|
|
||||||
<Select.Option value='4'>{t('系统')}</Select.Option>
|
|
||||||
<Select.Option value='5'>{t('错误')}</Select.Option>
|
|
||||||
</Select>
|
|
||||||
<Button
|
|
||||||
theme='light'
|
|
||||||
type='tertiary'
|
|
||||||
icon={<IconSetting />}
|
|
||||||
onClick={() => setShowColumnSelector(true)}
|
|
||||||
style={{ marginLeft: 8 }}
|
|
||||||
>
|
|
||||||
{t('列设置')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<Table
|
<Table
|
||||||
style={{ marginTop: 5 }}
|
|
||||||
columns={getVisibleColumns()}
|
columns={getVisibleColumns()}
|
||||||
expandedRowRender={expandRowRender}
|
expandedRowRender={expandRowRender}
|
||||||
expandRowByClick={true}
|
expandRowByClick={true}
|
||||||
dataSource={logs}
|
dataSource={logs}
|
||||||
rowKey='key'
|
rowKey='key'
|
||||||
|
loading={loading}
|
||||||
|
className="rounded-xl overflow-hidden"
|
||||||
|
size="middle"
|
||||||
pagination={{
|
pagination={{
|
||||||
formatPageText: (page) =>
|
formatPageText: (page) =>
|
||||||
t('第 {{start}} - {{end}} 条,共 {{total}} 条', {
|
t('第 {{start}} - {{end}} 条,共 {{total}} 条', {
|
||||||
@@ -1295,7 +1287,7 @@ const LogsTable = () => {
|
|||||||
currentPage: activePage,
|
currentPage: activePage,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
total: logCount,
|
total: logCount,
|
||||||
pageSizeOpts: [10, 20, 50, 100],
|
pageSizeOptions: [10, 20, 50, 100],
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
onPageSizeChange: (size) => {
|
onPageSizeChange: (size) => {
|
||||||
handlePageSizeChange(size);
|
handlePageSizeChange(size);
|
||||||
@@ -1303,7 +1295,7 @@ const LogsTable = () => {
|
|||||||
onPageChange: handlePageChange,
|
onPageChange: handlePageChange,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Card>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -170,6 +170,7 @@
|
|||||||
"充值": "Recharge",
|
"充值": "Recharge",
|
||||||
"用户": "Users",
|
"用户": "Users",
|
||||||
"日志": "Logs",
|
"日志": "Logs",
|
||||||
|
"日志记录帮助您了解使用情况和排查问题": "Log records help you understand usage and troubleshoot issues",
|
||||||
"设置": "Settings",
|
"设置": "Settings",
|
||||||
"关于": "About",
|
"关于": "About",
|
||||||
"价格": "Pricing",
|
"价格": "Pricing",
|
||||||
|
|||||||
@@ -329,3 +329,7 @@ code {
|
|||||||
/* -moz-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08) !important;*/
|
/* -moz-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08) !important;*/
|
||||||
/* min-height: 100%;*/
|
/* min-height: 100%;*/
|
||||||
/*}*/
|
/*}*/
|
||||||
|
|
||||||
|
.semi-datepicker-range-input {
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user