mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-19 11:10:49 +08:00
fix(usage): make api details card scrollable
This commit is contained in:
@@ -59,7 +59,7 @@ export function ApiDetailsCard({ apiStats, loading, hasPrices }: ApiDetailsCardP
|
|||||||
sortKey === key ? (sortDir === 'asc' ? ' ▲' : ' ▼') : '';
|
sortKey === key ? (sortDir === 'asc' ? ' ▲' : ' ▼') : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card title={t('usage_stats.api_details')}>
|
<Card title={t('usage_stats.api_details')} className={styles.detailsFixedCard}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className={styles.hint}>{t('common.loading')}</div>
|
<div className={styles.hint}>{t('common.loading')}</div>
|
||||||
) : sorted.length > 0 ? (
|
) : sorted.length > 0 ? (
|
||||||
@@ -82,70 +82,72 @@ export function ApiDetailsCard({ apiStats, loading, hasPrices }: ApiDetailsCardP
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.apiList}>
|
<div className={styles.detailsScroll}>
|
||||||
{sorted.map((api, index) => {
|
<div className={styles.apiList}>
|
||||||
const isExpanded = expandedApis.has(api.endpoint);
|
{sorted.map((api, index) => {
|
||||||
const panelId = `api-models-${index}`;
|
const isExpanded = expandedApis.has(api.endpoint);
|
||||||
|
const panelId = `api-models-${index}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={api.endpoint} className={styles.apiItem}>
|
<div key={api.endpoint} className={styles.apiItem}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.apiHeader}
|
className={styles.apiHeader}
|
||||||
onClick={() => toggleExpand(api.endpoint)}
|
onClick={() => toggleExpand(api.endpoint)}
|
||||||
aria-expanded={isExpanded}
|
aria-expanded={isExpanded}
|
||||||
aria-controls={panelId}
|
aria-controls={panelId}
|
||||||
>
|
>
|
||||||
<div className={styles.apiInfo}>
|
<div className={styles.apiInfo}>
|
||||||
<span className={styles.apiEndpoint}>{api.endpoint}</span>
|
<span className={styles.apiEndpoint}>{api.endpoint}</span>
|
||||||
<div className={styles.apiStats}>
|
<div className={styles.apiStats}>
|
||||||
<span className={styles.apiBadge}>
|
|
||||||
<span className={styles.requestCountCell}>
|
|
||||||
<span>
|
|
||||||
{t('usage_stats.requests_count')}: {api.totalRequests.toLocaleString()}
|
|
||||||
</span>
|
|
||||||
<span className={styles.requestBreakdown}>
|
|
||||||
(<span className={styles.statSuccess}>{api.successCount.toLocaleString()}</span>{' '}
|
|
||||||
<span className={styles.statFailure}>{api.failureCount.toLocaleString()}</span>)
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span className={styles.apiBadge}>
|
|
||||||
{t('usage_stats.tokens_count')}: {formatCompactNumber(api.totalTokens)}
|
|
||||||
</span>
|
|
||||||
{hasPrices && api.totalCost > 0 && (
|
|
||||||
<span className={styles.apiBadge}>
|
<span className={styles.apiBadge}>
|
||||||
{t('usage_stats.total_cost')}: {formatUsd(api.totalCost)}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<span className={styles.expandIcon}>
|
|
||||||
{isExpanded ? '▼' : '▶'}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
{isExpanded && (
|
|
||||||
<div id={panelId} className={styles.apiModels}>
|
|
||||||
{Object.entries(api.models).map(([model, stats]) => (
|
|
||||||
<div key={model} className={styles.modelRow}>
|
|
||||||
<span className={styles.modelName}>{model}</span>
|
|
||||||
<span className={styles.modelStat}>
|
|
||||||
<span className={styles.requestCountCell}>
|
<span className={styles.requestCountCell}>
|
||||||
<span>{stats.requests.toLocaleString()}</span>
|
<span>
|
||||||
|
{t('usage_stats.requests_count')}: {api.totalRequests.toLocaleString()}
|
||||||
|
</span>
|
||||||
<span className={styles.requestBreakdown}>
|
<span className={styles.requestBreakdown}>
|
||||||
(<span className={styles.statSuccess}>{stats.successCount.toLocaleString()}</span>{' '}
|
(<span className={styles.statSuccess}>{api.successCount.toLocaleString()}</span>{' '}
|
||||||
<span className={styles.statFailure}>{stats.failureCount.toLocaleString()}</span>)
|
<span className={styles.statFailure}>{api.failureCount.toLocaleString()}</span>)
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.modelStat}>{formatCompactNumber(stats.tokens)}</span>
|
<span className={styles.apiBadge}>
|
||||||
|
{t('usage_stats.tokens_count')}: {formatCompactNumber(api.totalTokens)}
|
||||||
|
</span>
|
||||||
|
{hasPrices && api.totalCost > 0 && (
|
||||||
|
<span className={styles.apiBadge}>
|
||||||
|
{t('usage_stats.total_cost')}: {formatUsd(api.totalCost)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
<span className={styles.expandIcon}>
|
||||||
)}
|
{isExpanded ? '▼' : '▶'}
|
||||||
</div>
|
</span>
|
||||||
);
|
</button>
|
||||||
})}
|
{isExpanded && (
|
||||||
|
<div id={panelId} className={styles.apiModels}>
|
||||||
|
{Object.entries(api.models).map(([model, stats]) => (
|
||||||
|
<div key={model} className={styles.modelRow}>
|
||||||
|
<span className={styles.modelName}>{model}</span>
|
||||||
|
<span className={styles.modelStat}>
|
||||||
|
<span className={styles.requestCountCell}>
|
||||||
|
<span>{stats.requests.toLocaleString()}</span>
|
||||||
|
<span className={styles.requestBreakdown}>
|
||||||
|
(<span className={styles.statSuccess}>{stats.successCount.toLocaleString()}</span>{' '}
|
||||||
|
<span className={styles.statFailure}>{stats.failureCount.toLocaleString()}</span>)
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span className={styles.modelStat}>{formatCompactNumber(stats.tokens)}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in New Issue
Block a user