Align with gpustack backend commits 7b57cd3b (add route dimension to
usage breakdown) and 51fd25c8 (use model_route_id as models_called):
* group_by, filters, and BreakdownItem now use the `route` dimension;
`models` filter cascader is replaced with a flat `routes` selector
(routes have no provider/cluster grouping).
* Tab / group_by option / column header keep the user-facing "模型 / Model"
wording — only the underlying data dimension changed.
* Drop cluster_name / provider_type columns from the breakdown table;
drop api_keys_used column per design.
* Fix pre-existing excel export bug in use-export-table — string
dataIndex was lodash-joined char-by-char ("input_tokens" →
"i_n_p_u_t..."), array dataIndex was used as a flat key against nested
rows. Rebuilt around buildSheetMeta that emits a stable field key plus
a formatMap using _.get(row, path) for nested values. Sheet name kept
as `models` to match the visible column label.
94 lines
2.4 KiB
TypeScript
94 lines
2.4 KiB
TypeScript
import {
|
|
apiKeysTableDataAtom,
|
|
modelsTableDataAtom,
|
|
usersTableDataAtom
|
|
} from '@/atoms/usage';
|
|
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
|
import { useSetAtom } from 'jotai';
|
|
import React from 'react';
|
|
import { queryUsageBreakdownList } from '../apis';
|
|
import { FilterOptionType, BreakdownItem as ListItem } from '../config/types';
|
|
|
|
export const useQueryBreakdownList = (options?: {
|
|
getLabel?: (item: ListItem) => string;
|
|
getValue?: (item: ListItem) => any;
|
|
key: 'modelsTableData' | 'usersTableData' | 'apiKeysTableData' | string;
|
|
}) => {
|
|
const setApiKeysTableData = useSetAtom(apiKeysTableDataAtom);
|
|
const setModelsTableData = useSetAtom(modelsTableDataAtom);
|
|
const setUsersTableData = useSetAtom(usersTableDataAtom);
|
|
const { key = 'usageBreakdownList' } = options || {};
|
|
const [dataSource, setDataSource] = React.useState<{
|
|
loadend: boolean;
|
|
dataList: ListItem[];
|
|
total: number;
|
|
}>({
|
|
total: 0,
|
|
loadend: false,
|
|
dataList: []
|
|
});
|
|
const { dataList, loading, fetchData, cancelRequest } = useQueryDataList<
|
|
ListItem,
|
|
Global.SearchParams & {
|
|
filters: {
|
|
routes?: FilterOptionType[];
|
|
users?: FilterOptionType[];
|
|
api_keys?: FilterOptionType[];
|
|
};
|
|
},
|
|
Global.PageResponse<ListItem>
|
|
>({
|
|
key: key,
|
|
responseType: 'object',
|
|
fetchList: queryUsageBreakdownList
|
|
});
|
|
|
|
const fetchListData = async (
|
|
params: Global.SearchParams & {
|
|
filters: {
|
|
routes?: FilterOptionType[];
|
|
users?: FilterOptionType[];
|
|
api_keys?: FilterOptionType[];
|
|
};
|
|
}
|
|
) => {
|
|
const res = await fetchData(params);
|
|
setDataSource({
|
|
dataList: res.items || [],
|
|
loadend: true,
|
|
total: res.pagination?.total || 0
|
|
});
|
|
if (key === 'apiKeysTableData') {
|
|
setApiKeysTableData({
|
|
dataList: res.items || [],
|
|
loadend: true,
|
|
total: res.pagination?.total || 0
|
|
});
|
|
}
|
|
if (key === 'modelsTableData') {
|
|
setModelsTableData({
|
|
dataList: res.items || [],
|
|
loadend: true,
|
|
total: res.pagination?.total || 0
|
|
});
|
|
}
|
|
if (key === 'usersTableData') {
|
|
setUsersTableData({
|
|
dataList: res.items || [],
|
|
loadend: true,
|
|
total: res.pagination?.total || 0
|
|
});
|
|
}
|
|
};
|
|
|
|
return {
|
|
dataList,
|
|
dataSource,
|
|
loading,
|
|
fetchData: fetchListData,
|
|
cancelRequest
|
|
};
|
|
};
|
|
|
|
export default useQueryBreakdownList;
|