mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
💄 style: fix usage table display issues (#10108)
* wip: use stack bar chart * 💄 style: update labels * 🐛 fix: should not include INF vales * ♻️ refactor: improve codes * 💄 style: improve label format * 💄 style: improve label format
This commit is contained in:
@@ -2,43 +2,66 @@ import { BarChart, type BarChartProps, ChartTooltipFrame, ChartTooltipRow } from
|
||||
import { Flexbox, Text } from '@lobehub/ui';
|
||||
import { Divider } from 'antd';
|
||||
|
||||
export const UsageBarChart = ({ ...props }: BarChartProps) => (
|
||||
import { formatNumber, formatTokenNumber } from '@/utils/format';
|
||||
|
||||
interface UsageBarChartProps extends BarChartProps {
|
||||
showType: 'spend' | 'token';
|
||||
}
|
||||
|
||||
export const UsageBarChart = ({ ...props }: UsageBarChartProps) => (
|
||||
<BarChart
|
||||
{...props}
|
||||
customTooltip={({ active, payload, label, valueFormatter }) => {
|
||||
customTooltip={({ active, payload, label }) => {
|
||||
if (active && payload) {
|
||||
const sum = payload.reduce(
|
||||
(acc: number, cur: any) => (typeof cur.value === 'number' ? acc + cur.value : acc),
|
||||
0,
|
||||
);
|
||||
return (
|
||||
<ChartTooltipFrame>
|
||||
<Flexbox horizontal justify={'space-between'} paddingBlock={8} paddingInline={16}>
|
||||
<Text as={'p'} ellipsis style={{ margin: 0 }}>
|
||||
{label}
|
||||
</Text>
|
||||
<span style={{ fontWeight: 'bold' }}>
|
||||
{payload.reduce((acc: number, cur: any) => acc + cur.value, 0)}
|
||||
</span>
|
||||
</Flexbox>
|
||||
<Divider style={{ margin: 0 }} />
|
||||
<Flexbox
|
||||
gap={4}
|
||||
paddingBlock={8}
|
||||
paddingInline={16}
|
||||
style={{ flexDirection: 'column-reverse', marginTop: 4 }}
|
||||
>
|
||||
{payload.map(({ value, color, name }: any, idx: number) =>
|
||||
typeof value === 'number' && value > 0 ? (
|
||||
<ChartTooltipRow
|
||||
color={color}
|
||||
key={`id-${idx}`}
|
||||
name={name}
|
||||
value={(valueFormatter as any)?.(value)}
|
||||
/>
|
||||
) : null,
|
||||
{sum !== 0 && (
|
||||
<span style={{ fontWeight: 'bold' }}>
|
||||
{props.showType === 'spend' ? formatNumber(sum, 2) : formatTokenNumber(sum)}
|
||||
</span>
|
||||
)}
|
||||
</Flexbox>
|
||||
{sum !== 0 && (
|
||||
<>
|
||||
<Divider style={{ margin: 0 }} />
|
||||
<Flexbox
|
||||
gap={4}
|
||||
paddingBlock={8}
|
||||
paddingInline={16}
|
||||
style={{ flexDirection: 'column-reverse', marginTop: 4 }}
|
||||
>
|
||||
{payload.map(({ value, color, name }: any, idx: number) =>
|
||||
typeof value === 'number' && value > 0 ? (
|
||||
<ChartTooltipRow
|
||||
color={color}
|
||||
key={`id-${idx}`}
|
||||
name={name}
|
||||
value={
|
||||
props.showType === 'spend'
|
||||
? formatNumber(value, 2)
|
||||
: formatTokenNumber(value)
|
||||
}
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
</Flexbox>
|
||||
</>
|
||||
)}
|
||||
</ChartTooltipFrame>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
valueFormatter={(num) =>
|
||||
props.showType === 'spend' ? formatNumber(num, 2) : formatTokenNumber(num)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ProviderIcon } from '@lobehub/icons';
|
||||
import { Flexbox, Tag, Text } from '@lobehub/ui';
|
||||
import { Flexbox, Tag, Text, Tooltip } from '@lobehub/ui';
|
||||
import { type TableColumnType } from 'antd';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { memo, useEffect } from 'react';
|
||||
@@ -53,7 +53,9 @@ const UsageTable = memo<UsageChartProps>(({ dateStrings }) => {
|
||||
marginRight: -8,
|
||||
}}
|
||||
/>
|
||||
<Text>{value?.length > 12 ? `${value.slice(0, 12)}...` : value}</Text>
|
||||
<Tooltip title={value}>
|
||||
<Text>{value?.length > 12 ? `${value.slice(0, 12)}...` : value}</Text>
|
||||
</Tooltip>
|
||||
</Flexbox>
|
||||
),
|
||||
title: t('usage.table.model'),
|
||||
|
||||
@@ -83,9 +83,21 @@ const UsageTrends = memo<UsageChartProps>(({ isLoading, data, groupBy }) => {
|
||||
const charts =
|
||||
data &&
|
||||
(type === ShowType.Spend ? (
|
||||
<UsageBarChart categories={spendCate} data={spendData} index="day" />
|
||||
<UsageBarChart
|
||||
categories={spendCate}
|
||||
data={spendData}
|
||||
index="day"
|
||||
showType="spend"
|
||||
stack={true}
|
||||
/>
|
||||
) : (
|
||||
<UsageBarChart categories={tokenCate} data={tokenData} index="day" />
|
||||
<UsageBarChart
|
||||
categories={tokenCate}
|
||||
data={tokenData}
|
||||
index="day"
|
||||
showType="token"
|
||||
stack={true}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
|
||||
@@ -28,7 +28,7 @@ export class UsageRecordService {
|
||||
// Set startAt and endAt
|
||||
let startAt: string;
|
||||
let endAt: string;
|
||||
if (mo) {
|
||||
if (mo && dayjs(mo, 'YYYY-MM', true).isValid()) {
|
||||
// mo format: "YYYY-MM"
|
||||
startAt = dayjs(mo, 'YYYY-MM').startOf('month').format('YYYY-MM-DD');
|
||||
endAt = dayjs(mo, 'YYYY-MM').endOf('month').format('YYYY-MM-DD');
|
||||
@@ -89,15 +89,18 @@ export class UsageRecordService {
|
||||
// Set startAt and endAt
|
||||
let startAt: string;
|
||||
let endAt: string;
|
||||
if (mo) {
|
||||
let month: string;
|
||||
if (mo && dayjs(mo, 'YYYY-MM', true).isValid()) {
|
||||
// mo format: "YYYY-MM"
|
||||
startAt = dayjs(mo, 'YYYY-MM').startOf('month').format('YYYY-MM-DD');
|
||||
endAt = dayjs(mo, 'YYYY-MM').endOf('month').format('YYYY-MM-DD');
|
||||
month = mo;
|
||||
} else {
|
||||
startAt = dayjs().startOf('month').format('YYYY-MM-DD');
|
||||
endAt = dayjs().endOf('month').format('YYYY-MM-DD');
|
||||
month = dayjs().format('YYYY-MM');
|
||||
}
|
||||
const spends = await this.findByMonth(mo);
|
||||
const spends = await this.findByMonth(month);
|
||||
// Clustering by time
|
||||
let usages = new Map<string, { date: Date; logs: UsageRecordItem[] }>();
|
||||
spends.forEach((spend) => {
|
||||
|
||||
Reference in New Issue
Block a user