fix: usage ux

This commit is contained in:
jialin
2026-04-22 13:16:48 +08:00
committed by jialin
parent 084822814d
commit ad7fc3a993
7 changed files with 532 additions and 236 deletions
+207
View File
@@ -0,0 +1,207 @@
import { exportJsonToExcel } from '@/utils/excel-reader';
import dayjs from 'dayjs';
import { useMemo, useState } from 'react';
import {
generateColumns,
GroupOption,
transformTimelineToTable
} from '../config';
import { UsageFilterItem } from '../config/types';
import useQueryTimeSeriesData from '../services/use-query-timeseries-data';
const DefaultDateConfig = {
defaultRange: 29
};
type UserOptionType = UsageFilterItem & {
value: string;
};
type FilterOptionType = Omit<UsageFilterItem, 'label' | 'deleted'>;
type GroupOptionType = GroupOption<UsageFilterItem>;
interface UseUsageFiltersParams {
initialScope: string;
metaData: {
models?: GroupOptionType[];
users?: UserOptionType[];
api_keys?: GroupOptionType[];
};
chartFilters: {
metric: string;
group_by: string;
granularity: string;
};
summaryColumns: {
title: string;
dataIndex: string;
key: string;
}[];
}
export const useUsageFilters = ({
initialScope,
metaData,
chartFilters,
summaryColumns
}: UseUsageFiltersParams) => {
const {
detailData: timeSeriesData,
loading,
fetchData: fetchTimeSeriesData
} = useQueryTimeSeriesData();
const [commonFilters, setCommonFilters] = useState({
scope: initialScope,
models: [] as string[],
users: [] as string[],
api_keys: [] as string[],
start_date: dayjs()
.subtract(DefaultDateConfig.defaultRange, 'days')
.format('YYYY-MM-DD'),
end_date: dayjs().format('YYYY-MM-DD')
});
const modelOptions = metaData?.models || [];
const userOptions = metaData?.users || [];
const apiKeyOptions = metaData?.api_keys || [];
const buildFilters = (selected: typeof commonFilters) => {
const filters: {
models?: FilterOptionType[];
users?: FilterOptionType[];
api_keys?: FilterOptionType[];
} = {};
if (selected.models.length > 0) {
const modelsSet = new Set(selected.models);
filters.models = modelOptions
.flatMap((group) =>
group.children.filter((item) => modelsSet.has(item.value))
)
.map((item) => ({
identity: item.identity
}));
}
if (selected.users.length > 0) {
filters.users = userOptions
.filter((item) => selected.users.includes(item.value || ''))
.map((item) => ({
identity: item.identity
}));
}
if (selected.api_keys.length > 0) {
const apiKeysSet = new Set(selected.api_keys);
filters.api_keys = apiKeyOptions
.flatMap((group) =>
group.children.filter((item) => apiKeysSet.has(item.value))
)
.map((item) => ({
identity: item.identity
}));
}
return filters;
};
const filters = useMemo(
() => buildFilters(commonFilters),
[commonFilters, modelOptions, userOptions, apiKeyOptions]
);
const fetchData = (
currentSelectedFilters = commonFilters,
currentChartFilters = chartFilters
) => {
fetchTimeSeriesData({
...currentChartFilters,
start_date: currentSelectedFilters.start_date,
end_date: currentSelectedFilters.end_date,
filters: buildFilters(currentSelectedFilters)
});
};
const handleScopeChange = (value: string) => {
const next = { ...commonFilters, scope: value };
setCommonFilters(next);
fetchData(next, chartFilters);
};
const handleDateChange = (_: any, dateStrings: [string, string]) => {
const [start_date, end_date] = dateStrings;
const next = { ...commonFilters, start_date, end_date };
setCommonFilters(next);
fetchData(next, chartFilters);
};
const handleFilterChange = (
type: 'models' | 'users' | 'api_keys',
value: string[]
) => {
const next = { ...commonFilters, [type]: value };
setCommonFilters(next);
fetchData(next, chartFilters);
};
const handleSearch = () => {
fetchData(commonFilters, chartFilters);
};
const handleOnExportChart = () => {
const columns = generateColumns(timeSeriesData?.series || []);
const tableData = transformTimelineToTable(timeSeriesData?.series || []);
exportJsonToExcel({
fileName: `${chartFilters.metric}_${chartFilters.group_by}_${chartFilters.granularity}_${commonFilters.start_date}_${commonFilters.end_date}.xlsx`,
sheets: [
{
jsonData: tableData,
sheetName: chartFilters.metric,
fields: columns.map((col) => col.dataIndex).filter(Boolean),
fieldLabels: Object.fromEntries(
columns.map((col) => [col.dataIndex, col.title])
),
formatMap: {}
},
{
jsonData: [timeSeriesData?.summary || {}],
sheetName: 'summary',
fields: summaryColumns.map((col) => col.dataIndex),
fieldLabels: Object.fromEntries(
summaryColumns.map((col) => [col.dataIndex, col.title])
),
formatMap: {}
}
]
});
};
const filterBar = {
scope: commonFilters.scope,
startDate: commonFilters.start_date,
endDate: commonFilters.end_date,
selectedModels: commonFilters.models,
selectedUsers: commonFilters.users,
selectedApiKeys: commonFilters.api_keys,
modelOptions,
userOptions,
apiKeyOptions,
handleSearch,
onScopeChange: handleScopeChange,
onDateChange: handleDateChange,
onModelsChange: (value: string[]) => handleFilterChange('models', value),
onUsersChange: (value: string[]) => handleFilterChange('users', value),
onApiKeysChange: (value: string[]) => handleFilterChange('api_keys', value),
onExportChart: handleOnExportChart
};
return {
filters,
loading,
commonFilters,
timeSeriesData,
fetchData,
filterBar
};
};