Merge pull request #15 from Lany798/feat/auth-index-column
Feat/auth index column
This commit is contained in:
@@ -2,7 +2,7 @@ import { useMemo, useState, useEffect, useRef, useCallback } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||||
import { Card } from '@/components/ui/Card';
|
import { Card } from '@/components/ui/Card';
|
||||||
import { usageApi } from '@/services/api';
|
import { usageApi, authFilesApi } from '@/services/api';
|
||||||
import { useDisableModel } from '@/hooks';
|
import { useDisableModel } from '@/hooks';
|
||||||
import { TimeRangeSelector, formatTimeRangeCaption, type TimeRange } from './TimeRangeSelector';
|
import { TimeRangeSelector, formatTimeRangeCaption, type TimeRange } from './TimeRangeSelector';
|
||||||
import { DisableModelModal } from './DisableModelModal';
|
import { DisableModelModal } from './DisableModelModal';
|
||||||
@@ -41,6 +41,7 @@ interface LogEntry {
|
|||||||
inputTokens: number;
|
inputTokens: number;
|
||||||
outputTokens: number;
|
outputTokens: number;
|
||||||
totalTokens: number;
|
totalTokens: number;
|
||||||
|
authIndex: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChannelModelRequest {
|
interface ChannelModelRequest {
|
||||||
@@ -92,6 +93,9 @@ export function RequestLogs({ data, loading: parentLoading, providerMap, provide
|
|||||||
const [logLoading, setLogLoading] = useState(false);
|
const [logLoading, setLogLoading] = useState(false);
|
||||||
const [isFirstLoad, setIsFirstLoad] = useState(true);
|
const [isFirstLoad, setIsFirstLoad] = useState(true);
|
||||||
|
|
||||||
|
// 认证文件索引到名称的映射
|
||||||
|
const [authIndexMap, setAuthIndexMap] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
// 使用禁用模型 Hook
|
// 使用禁用模型 Hook
|
||||||
const {
|
const {
|
||||||
disableState,
|
disableState,
|
||||||
@@ -124,6 +128,33 @@ export function RequestLogs({ data, loading: parentLoading, providerMap, provide
|
|||||||
}
|
}
|
||||||
}, [parentLoading, data]);
|
}, [parentLoading, data]);
|
||||||
|
|
||||||
|
// 加载认证文件映射(authIndex -> 文件名)
|
||||||
|
const loadAuthIndexMap = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const response = await authFilesApi.list();
|
||||||
|
const files = response?.files || [];
|
||||||
|
const map: Record<string, string> = {};
|
||||||
|
files.forEach((file) => {
|
||||||
|
// 兼容 auth_index 和 authIndex 两种字段名(API 返回的是 auth_index)
|
||||||
|
const rawAuthIndex = (file as Record<string, unknown>)['auth_index'] ?? file.authIndex;
|
||||||
|
if (rawAuthIndex !== undefined && rawAuthIndex !== null) {
|
||||||
|
const authIndexKey = String(rawAuthIndex).trim();
|
||||||
|
if (authIndexKey) {
|
||||||
|
map[authIndexKey] = file.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setAuthIndexMap(map);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Failed to load auth files for index mapping:', err);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 初始加载认证文件映射
|
||||||
|
useEffect(() => {
|
||||||
|
loadAuthIndexMap();
|
||||||
|
}, [loadAuthIndexMap]);
|
||||||
|
|
||||||
// 独立获取日志数据
|
// 独立获取日志数据
|
||||||
const fetchLogData = useCallback(async () => {
|
const fetchLogData = useCallback(async () => {
|
||||||
setLogLoading(true);
|
setLogLoading(true);
|
||||||
@@ -283,6 +314,7 @@ export function RequestLogs({ data, loading: parentLoading, providerMap, provide
|
|||||||
inputTokens: detail.tokens.input_tokens || 0,
|
inputTokens: detail.tokens.input_tokens || 0,
|
||||||
outputTokens: detail.tokens.output_tokens || 0,
|
outputTokens: detail.tokens.output_tokens || 0,
|
||||||
totalTokens: detail.tokens.total_tokens || 0,
|
totalTokens: detail.tokens.total_tokens || 0,
|
||||||
|
authIndex: detail.auth_index || '',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -409,9 +441,14 @@ export function RequestLogs({ data, loading: parentLoading, providerMap, provide
|
|||||||
const stats = getStats(entry);
|
const stats = getStats(entry);
|
||||||
const rateValue = parseFloat(stats.successRate);
|
const rateValue = parseFloat(stats.successRate);
|
||||||
const disabled = isModelDisabled(entry.source, entry.model);
|
const disabled = isModelDisabled(entry.source, entry.model);
|
||||||
|
// 将 authIndex 映射为文件名
|
||||||
|
const authDisplayName = entry.authIndex ? (authIndexMap[entry.authIndex] || entry.authIndex) : '-';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<td title={authDisplayName}>
|
||||||
|
{authDisplayName}
|
||||||
|
</td>
|
||||||
<td title={entry.apiKey}>
|
<td title={entry.apiKey}>
|
||||||
{maskSecret(entry.apiKey)}
|
{maskSecret(entry.apiKey)}
|
||||||
</td>
|
</td>
|
||||||
@@ -580,6 +617,7 @@ export function RequestLogs({ data, loading: parentLoading, providerMap, provide
|
|||||||
<table className={`${styles.table} ${styles.virtualTable}`}>
|
<table className={`${styles.table} ${styles.virtualTable}`}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>{t('monitor.logs.header_auth')}</th>
|
||||||
<th>{t('monitor.logs.header_api')}</th>
|
<th>{t('monitor.logs.header_api')}</th>
|
||||||
<th>{t('monitor.logs.header_request_type')}</th>
|
<th>{t('monitor.logs.header_request_type')}</th>
|
||||||
<th>{t('monitor.logs.header_model')}</th>
|
<th>{t('monitor.logs.header_model')}</th>
|
||||||
|
|||||||
Reference in New Issue
Block a user