🎨 chore(web): apply ESLint and Prettier auto-fixes (baseline)

- Ran: bun run eslint:fix && bun run lint:fix
- Inserted AGPL license header via eslint-plugin-header
- Enforced no-multiple-empty-lines and other lint rules
- Formatted code using Prettier v3 (@so1ve/prettier-config)
- No functional changes; formatting-only baseline across JS/JSX files
This commit is contained in:
t0ng7u
2025-08-30 21:15:10 +08:00
parent 41cf516ec5
commit 0d57b1acd4
274 changed files with 11025 additions and 7659 deletions

View File

@@ -24,7 +24,7 @@ import {
renderNumber,
renderQuota,
modelToColor,
getQuotaWithUnit
getQuotaWithUnit,
} from '../../helpers';
import {
processRawData,
@@ -33,7 +33,7 @@ import {
generateChartTimePoints,
updateChartSpec,
updateMapValue,
initializeMaps
initializeMaps,
} from '../../helpers/dashboard';
export const useDashboardCharts = (
@@ -45,7 +45,7 @@ export const useDashboardCharts = (
setPieData,
setLineData,
setModelColors,
t
t,
) => {
// ========== 图表规格状态 ==========
const [spec_pie, setSpecPie] = useState({
@@ -271,150 +271,160 @@ export const useDashboardCharts = (
return newModelColors;
}, []);
const updateChartData = useCallback((data) => {
const processedData = processRawData(
data,
const updateChartData = useCallback(
(data) => {
const processedData = processRawData(
data,
dataExportDefaultTime,
initializeMaps,
updateMapValue,
);
const {
totalQuota,
totalTimes,
totalTokens,
uniqueModels,
timePoints,
timeQuotaMap,
timeTokensMap,
timeCountMap,
} = processedData;
const trendDataResult = calculateTrendData(
timePoints,
timeQuotaMap,
timeTokensMap,
timeCountMap,
dataExportDefaultTime,
);
setTrendData(trendDataResult);
const newModelColors = generateModelColors(uniqueModels, {});
setModelColors(newModelColors);
const aggregatedData = aggregateDataByTimeAndModel(
data,
dataExportDefaultTime,
);
const modelTotals = new Map();
for (let [_, value] of aggregatedData) {
updateMapValue(modelTotals, value.model, value.count);
}
const newPieData = Array.from(modelTotals)
.map(([model, count]) => ({
type: model,
value: count,
}))
.sort((a, b) => b.value - a.value);
const chartTimePoints = generateChartTimePoints(
aggregatedData,
data,
dataExportDefaultTime,
);
let newLineData = [];
chartTimePoints.forEach((time) => {
let timeData = Array.from(uniqueModels).map((model) => {
const key = `${time}-${model}`;
const aggregated = aggregatedData.get(key);
return {
Time: time,
Model: model,
rawQuota: aggregated?.quota || 0,
Usage: aggregated?.quota
? getQuotaWithUnit(aggregated.quota, 4)
: 0,
};
});
const timeSum = timeData.reduce((sum, item) => sum + item.rawQuota, 0);
timeData.sort((a, b) => b.rawQuota - a.rawQuota);
timeData = timeData.map((item) => ({ ...item, TimeSum: timeSum }));
newLineData.push(...timeData);
});
newLineData.sort((a, b) => a.Time.localeCompare(b.Time));
updateChartSpec(
setSpecPie,
newPieData,
`${t('总计')}${renderNumber(totalTimes)}`,
newModelColors,
'id0',
);
updateChartSpec(
setSpecLine,
newLineData,
`${t('总计')}${renderQuota(totalQuota, 2)}`,
newModelColors,
'barData',
);
// ===== 模型调用次数折线图 =====
let modelLineData = [];
chartTimePoints.forEach((time) => {
const timeData = Array.from(uniqueModels).map((model) => {
const key = `${time}-${model}`;
const aggregated = aggregatedData.get(key);
return {
Time: time,
Model: model,
Count: aggregated?.count || 0,
};
});
modelLineData.push(...timeData);
});
modelLineData.sort((a, b) => a.Time.localeCompare(b.Time));
// ===== 模型调用次数排行柱状图 =====
const rankData = Array.from(modelTotals)
.map(([model, count]) => ({
Model: model,
Count: count,
}))
.sort((a, b) => b.Count - a.Count);
updateChartSpec(
setSpecModelLine,
modelLineData,
`${t('总计')}${renderNumber(totalTimes)}`,
newModelColors,
'lineData',
);
updateChartSpec(
setSpecRankBar,
rankData,
`${t('总计')}${renderNumber(totalTimes)}`,
newModelColors,
'rankData',
);
setPieData(newPieData);
setLineData(newLineData);
setConsumeQuota(totalQuota);
setTimes(totalTimes);
setConsumeTokens(totalTokens);
},
[
dataExportDefaultTime,
initializeMaps,
updateMapValue
);
const {
totalQuota,
totalTimes,
totalTokens,
uniqueModels,
timePoints,
timeQuotaMap,
timeTokensMap,
timeCountMap
} = processedData;
const trendDataResult = calculateTrendData(
timePoints,
timeQuotaMap,
timeTokensMap,
timeCountMap,
dataExportDefaultTime
);
setTrendData(trendDataResult);
const newModelColors = generateModelColors(uniqueModels, {});
setModelColors(newModelColors);
const aggregatedData = aggregateDataByTimeAndModel(data, dataExportDefaultTime);
const modelTotals = new Map();
for (let [_, value] of aggregatedData) {
updateMapValue(modelTotals, value.model, value.count);
}
const newPieData = Array.from(modelTotals).map(([model, count]) => ({
type: model,
value: count,
})).sort((a, b) => b.value - a.value);
const chartTimePoints = generateChartTimePoints(
aggregatedData,
data,
dataExportDefaultTime
);
let newLineData = [];
chartTimePoints.forEach((time) => {
let timeData = Array.from(uniqueModels).map((model) => {
const key = `${time}-${model}`;
const aggregated = aggregatedData.get(key);
return {
Time: time,
Model: model,
rawQuota: aggregated?.quota || 0,
Usage: aggregated?.quota ? getQuotaWithUnit(aggregated.quota, 4) : 0,
};
});
const timeSum = timeData.reduce((sum, item) => sum + item.rawQuota, 0);
timeData.sort((a, b) => b.rawQuota - a.rawQuota);
timeData = timeData.map((item) => ({ ...item, TimeSum: timeSum }));
newLineData.push(...timeData);
});
newLineData.sort((a, b) => a.Time.localeCompare(b.Time));
updateChartSpec(
setSpecPie,
newPieData,
`${t('总计')}${renderNumber(totalTimes)}`,
newModelColors,
'id0'
);
updateChartSpec(
setSpecLine,
newLineData,
`${t('总计')}${renderQuota(totalQuota, 2)}`,
newModelColors,
'barData'
);
// ===== 模型调用次数折线图 =====
let modelLineData = [];
chartTimePoints.forEach((time) => {
const timeData = Array.from(uniqueModels).map((model) => {
const key = `${time}-${model}`;
const aggregated = aggregatedData.get(key);
return {
Time: time,
Model: model,
Count: aggregated?.count || 0,
};
});
modelLineData.push(...timeData);
});
modelLineData.sort((a, b) => a.Time.localeCompare(b.Time));
// ===== 模型调用次数排行柱状图 =====
const rankData = Array.from(modelTotals)
.map(([model, count]) => ({
Model: model,
Count: count,
}))
.sort((a, b) => b.Count - a.Count);
updateChartSpec(
setSpecModelLine,
modelLineData,
`${t('总计')}${renderNumber(totalTimes)}`,
newModelColors,
'lineData'
);
updateChartSpec(
setSpecRankBar,
rankData,
`${t('总计')}${renderNumber(totalTimes)}`,
newModelColors,
'rankData'
);
setPieData(newPieData);
setLineData(newLineData);
setConsumeQuota(totalQuota);
setTimes(totalTimes);
setConsumeTokens(totalTokens);
}, [
dataExportDefaultTime,
setTrendData,
generateModelColors,
setModelColors,
setPieData,
setLineData,
setConsumeQuota,
setTimes,
setConsumeTokens,
t
]);
setTrendData,
generateModelColors,
setModelColors,
setPieData,
setLineData,
setConsumeQuota,
setTimes,
setConsumeTokens,
t,
],
);
// ========== 初始化图表主题 ==========
useEffect(() => {
@@ -432,6 +442,6 @@ export const useDashboardCharts = (
// 函数
updateChartData,
generateModelColors
generateModelColors,
};
};
};

View File

@@ -49,7 +49,8 @@ export const useDashboardData = (userState, userDispatch, statusState) => {
data_export_default_time: '',
});
const [dataExportDefaultTime, setDataExportDefaultTime] = useState(getDefaultTime());
const [dataExportDefaultTime, setDataExportDefaultTime] =
useState(getDefaultTime());
// ========== 数据状态 ==========
const [quotaData, setQuotaData] = useState([]);
@@ -72,7 +73,7 @@ export const useDashboardData = (userState, userDispatch, statusState) => {
consumeQuota: [],
tokens: [],
rpm: [],
tpm: []
tpm: [],
});
// ========== Uptime 数据 ==========
@@ -86,7 +87,8 @@ export const useDashboardData = (userState, userDispatch, statusState) => {
// ========== Panel enable flags ==========
const apiInfoEnabled = statusState?.status?.api_info_enabled ?? true;
const announcementsEnabled = statusState?.status?.announcements_enabled ?? true;
const announcementsEnabled =
statusState?.status?.announcements_enabled ?? true;
const faqEnabled = statusState?.status?.faq_enabled ?? true;
const uptimeEnabled = statusState?.status?.uptime_kuma_enabled ?? true;
@@ -94,16 +96,25 @@ export const useDashboardData = (userState, userDispatch, statusState) => {
const hasInfoPanels = announcementsEnabled || faqEnabled || uptimeEnabled;
// ========== Memoized Values ==========
const timeOptions = useMemo(() => TIME_OPTIONS.map(option => ({
...option,
label: t(option.label)
})), [t]);
const timeOptions = useMemo(
() =>
TIME_OPTIONS.map((option) => ({
...option,
label: t(option.label),
})),
[t],
);
const performanceMetrics = useMemo(() => {
const { start_timestamp, end_timestamp } = inputs;
const timeDiff = (Date.parse(end_timestamp) - Date.parse(start_timestamp)) / 60000;
const avgRPM = isNaN(times / timeDiff) ? '0' : (times / timeDiff).toFixed(3);
const avgTPM = isNaN(consumeTokens / timeDiff) ? '0' : (consumeTokens / timeDiff).toFixed(3);
const timeDiff =
(Date.parse(end_timestamp) - Date.parse(start_timestamp)) / 60000;
const avgRPM = isNaN(times / timeDiff)
? '0'
: (times / timeDiff).toFixed(3);
const avgTPM = isNaN(consumeTokens / timeDiff)
? '0'
: (consumeTokens / timeDiff).toFixed(3);
return { avgRPM, avgTPM, timeDiff };
}, [times, consumeTokens, inputs.start_timestamp, inputs.end_timestamp]);
@@ -218,13 +229,16 @@ export const useDashboardData = (userState, userDispatch, statusState) => {
return data;
}, [loadQuotaData, loadUptimeData]);
const handleSearchConfirm = useCallback(async (updateChartDataCallback) => {
const data = await refresh();
if (data && data.length > 0 && updateChartDataCallback) {
updateChartDataCallback(data);
}
setSearchModalVisible(false);
}, [refresh]);
const handleSearchConfirm = useCallback(
async (updateChartDataCallback) => {
const data = await refresh();
if (data && data.length > 0 && updateChartDataCallback) {
updateChartDataCallback(data);
}
setSearchModalVisible(false);
},
[refresh],
);
// ========== Effects ==========
useEffect(() => {
@@ -305,6 +319,6 @@ export const useDashboardData = (userState, userDispatch, statusState) => {
// 导航和翻译
navigate,
t,
isMobile
isMobile,
};
};
};

View File

@@ -27,7 +27,7 @@ import {
IconPulse,
IconStopwatchStroked,
IconTypograph,
IconSend
IconSend,
} from '@douyinfe/semi-icons';
import { renderQuota } from '../../helpers';
import { createSectionTitle } from '../../helpers/dashboard';
@@ -40,111 +40,114 @@ export const useDashboardStats = (
trendData,
performanceMetrics,
navigate,
t
t,
) => {
const groupedStatsData = useMemo(() => [
{
title: createSectionTitle(Wallet, t('账户数据')),
color: 'bg-blue-50',
items: [
{
title: t('当前余额'),
value: renderQuota(userState?.user?.quota),
icon: <IconMoneyExchangeStroked />,
avatarColor: 'blue',
trendData: [],
trendColor: '#3b82f6'
},
{
title: t('历史消耗'),
value: renderQuota(userState?.user?.used_quota),
icon: <IconHistogram />,
avatarColor: 'purple',
trendData: [],
trendColor: '#8b5cf6'
}
]
},
{
title: createSectionTitle(Activity, t('使用统计')),
color: 'bg-green-50',
items: [
{
title: t('请求次数'),
value: userState.user?.request_count,
icon: <IconSend />,
avatarColor: 'green',
trendData: [],
trendColor: '#10b981'
},
{
title: t('统计次数'),
value: times,
icon: <IconPulse />,
avatarColor: 'cyan',
trendData: trendData.times,
trendColor: '#06b6d4'
}
]
},
{
title: createSectionTitle(Zap, t('资源消耗')),
color: 'bg-yellow-50',
items: [
{
title: t('统计额度'),
value: renderQuota(consumeQuota),
icon: <IconCoinMoneyStroked />,
avatarColor: 'yellow',
trendData: trendData.consumeQuota,
trendColor: '#f59e0b'
},
{
title: t('统计Tokens'),
value: isNaN(consumeTokens) ? 0 : consumeTokens,
icon: <IconTextStroked />,
avatarColor: 'pink',
trendData: trendData.tokens,
trendColor: '#ec4899'
}
]
},
{
title: createSectionTitle(Gauge, t('性能指标')),
color: 'bg-indigo-50',
items: [
{
title: t('平均RPM'),
value: performanceMetrics.avgRPM,
icon: <IconStopwatchStroked />,
avatarColor: 'indigo',
trendData: trendData.rpm,
trendColor: '#6366f1'
},
{
title: t('平均TPM'),
value: performanceMetrics.avgTPM,
icon: <IconTypograph />,
avatarColor: 'orange',
trendData: trendData.tpm,
trendColor: '#f97316'
}
]
}
], [
userState?.user?.quota,
userState?.user?.used_quota,
userState?.user?.request_count,
times,
consumeQuota,
consumeTokens,
trendData,
performanceMetrics,
navigate,
t
]);
const groupedStatsData = useMemo(
() => [
{
title: createSectionTitle(Wallet, t('账户数据')),
color: 'bg-blue-50',
items: [
{
title: t('当前余额'),
value: renderQuota(userState?.user?.quota),
icon: <IconMoneyExchangeStroked />,
avatarColor: 'blue',
trendData: [],
trendColor: '#3b82f6',
},
{
title: t('历史消耗'),
value: renderQuota(userState?.user?.used_quota),
icon: <IconHistogram />,
avatarColor: 'purple',
trendData: [],
trendColor: '#8b5cf6',
},
],
},
{
title: createSectionTitle(Activity, t('使用统计')),
color: 'bg-green-50',
items: [
{
title: t('请求次数'),
value: userState.user?.request_count,
icon: <IconSend />,
avatarColor: 'green',
trendData: [],
trendColor: '#10b981',
},
{
title: t('统计次数'),
value: times,
icon: <IconPulse />,
avatarColor: 'cyan',
trendData: trendData.times,
trendColor: '#06b6d4',
},
],
},
{
title: createSectionTitle(Zap, t('资源消耗')),
color: 'bg-yellow-50',
items: [
{
title: t('统计额度'),
value: renderQuota(consumeQuota),
icon: <IconCoinMoneyStroked />,
avatarColor: 'yellow',
trendData: trendData.consumeQuota,
trendColor: '#f59e0b',
},
{
title: t('统计Tokens'),
value: isNaN(consumeTokens) ? 0 : consumeTokens,
icon: <IconTextStroked />,
avatarColor: 'pink',
trendData: trendData.tokens,
trendColor: '#ec4899',
},
],
},
{
title: createSectionTitle(Gauge, t('性能指标')),
color: 'bg-indigo-50',
items: [
{
title: t('平均RPM'),
value: performanceMetrics.avgRPM,
icon: <IconStopwatchStroked />,
avatarColor: 'indigo',
trendData: trendData.rpm,
trendColor: '#6366f1',
},
{
title: t('平均TPM'),
value: performanceMetrics.avgTPM,
icon: <IconTypograph />,
avatarColor: 'orange',
trendData: trendData.tpm,
trendColor: '#f97316',
},
],
},
],
[
userState?.user?.quota,
userState?.user?.used_quota,
userState?.user?.request_count,
times,
consumeQuota,
consumeTokens,
trendData,
performanceMetrics,
navigate,
t,
],
);
return {
groupedStatsData
groupedStatsData,
};
};
};