From 131a1fae591a7fa580958ef7a6d644d99ccd453b Mon Sep 17 00:00:00 2001 From: ningyv <1793599591@qq.com> Date: Tue, 6 May 2025 11:09:18 +0800 Subject: [PATCH] feature/1.8-Improve system observability --- .../charts/ServiceAreaChart.tsx | 8 +- .../serviceOverview/charts/ServiceBarChar.tsx | 55 +++++-- .../pages/serviceOverview/serviceOverview.tsx | 148 +++++++++++------- .../core/src/pages/serviceOverview/utils.ts | 2 +- .../dashboard/src/pages/DashboardTotal.tsx | 130 ++++++++------- .../packages/dashboard/src/utils/dashboard.ts | 111 +++++++++++++ 6 files changed, 329 insertions(+), 125 deletions(-) diff --git a/frontend/packages/core/src/pages/serviceOverview/charts/ServiceAreaChart.tsx b/frontend/packages/core/src/pages/serviceOverview/charts/ServiceAreaChart.tsx index 9edd3647..015d2970 100644 --- a/frontend/packages/core/src/pages/serviceOverview/charts/ServiceAreaChart.tsx +++ b/frontend/packages/core/src/pages/serviceOverview/charts/ServiceAreaChart.tsx @@ -9,6 +9,7 @@ type AreaChartInfo = { data: number[] max: string min: string + originValue?: number showXAxis?: boolean } @@ -17,9 +18,10 @@ type ServiceAreaCharProps = { dataInfo?: AreaChartInfo height?: number showAvgLine?: boolean + customMarkLineValue?: number } -const ServiceAreaChart = ({ customClassNames, dataInfo, height, showAvgLine }: ServiceAreaCharProps) => { +const ServiceAreaChart = ({ customClassNames, dataInfo, height, showAvgLine, customMarkLineValue }: ServiceAreaCharProps) => { const chartRef = useRef(null) const [option, setOption] = useState({}) const [hasData, setHasData] = useState(true) @@ -186,7 +188,9 @@ const ServiceAreaChart = ({ customClassNames, dataInfo, height, showAvgLine }: S show: false // 悬停时不显示标签 } }, - data: [{ type: 'average', name: 'Avg' }] + data: dataInfo?.originValue !== undefined ? + [{ yAxis: dataInfo?.originValue, name: '自定义值' }] : + [{ type: 'average', name: 'Avg' }] } : undefined, areaStyle: { color: { diff --git a/frontend/packages/core/src/pages/serviceOverview/charts/ServiceBarChar.tsx b/frontend/packages/core/src/pages/serviceOverview/charts/ServiceBarChar.tsx index cb594bd5..1267f2bd 100644 --- a/frontend/packages/core/src/pages/serviceOverview/charts/ServiceBarChar.tsx +++ b/frontend/packages/core/src/pages/serviceOverview/charts/ServiceBarChar.tsx @@ -21,6 +21,8 @@ export type BarChartInfo = { traffic2xxTotal?: string traffic4xxTotal?: string traffic5xxTotal?: string + max?: string | number + min?: string | number } type ServiceBarCharProps = { @@ -29,9 +31,17 @@ type ServiceBarCharProps = { height?: number showAvgLine?: boolean showLegendIndicator?: boolean + hideIndicatorValue?: boolean } -const ServiceBarChar = ({ customClassNames, dataInfo, height, showAvgLine, showLegendIndicator }: ServiceBarCharProps) => { +const ServiceBarChar = ({ + customClassNames, + dataInfo, + height, + showAvgLine, + showLegendIndicator, + hideIndicatorValue +}: ServiceBarCharProps) => { const chartRef = useRef(null) const [option, setOption] = useState({}) // 使用从主题配置中导入的默认颜色,而不是硬编码的颜色值 @@ -78,7 +88,10 @@ const ServiceBarChar = ({ customClassNames, dataInfo, height, showAvgLine, showL const option: EChartsOption = { title: [ { - text: '{titleStyle|' + $t(dataInfo.title) + '}\n\n{valueStyle|' + dataInfo.value + '}', + text: + '{titleStyle|' + + $t(dataInfo.title) + + `}${hideIndicatorValue ? '' : '\n\n{valueStyle|' + dataInfo.value + '}'}`, left: '2%', top: '0', textStyle: { @@ -125,23 +138,23 @@ const ServiceBarChar = ({ customClassNames, dataInfo, height, showAvgLine, showL show: !isNumberArray, data: legendData, right: '10px', - top: '60px', + top: hideIndicatorValue ? '10px' : '60px', itemWidth: 10, itemHeight: 10, textStyle: { color: '#333' }, icon: 'rect', - formatter: function(name: string): string { + formatter: function (name: string): string { // 这里可以映射或自定义图例文本 const customNames: Record = { - 'inputToken': `${$t('输入 Token')} ${showLegendIndicator ? `(${dataInfo.inputTokenTotal})` : ''}`, - 'outputToken': `${$t('输出 Token')} ${showLegendIndicator ? `(${dataInfo.outputTokenTotal})` : ''}`, + inputToken: `${$t('输入 Token')} ${showLegendIndicator ? `(${dataInfo.inputTokenTotal})` : ''}`, + outputToken: `${$t('输出 Token')} ${showLegendIndicator ? `(${dataInfo.outputTokenTotal})` : ''}`, '2xx': `${'2xx'} ${showLegendIndicator ? `(${dataInfo.request2xxTotal || dataInfo.traffic2xxTotal})` : ''}`, '4xx': `${'4xx'} ${showLegendIndicator ? `(${dataInfo.request4xxTotal || dataInfo.traffic4xxTotal})` : ''}`, '5xx': `${'5xx'} ${showLegendIndicator ? `(${dataInfo.request5xxTotal || dataInfo.traffic5xxTotal})` : ''}` - }; - return customNames[name] || name; + } + return customNames[name] || name } }, xAxis: { @@ -252,10 +265,10 @@ const ServiceBarChar = ({ customClassNames, dataInfo, height, showAvgLine, showL }, emphasis: { lineStyle: { - width: 1 // 保持线条宽度不变,禁用默认的悬停加粗 + width: 1 // 保持线条宽度不变,禁用默认的悬停加粗 }, label: { - show: false // 悬停时不显示标签 + show: false // 悬停时不显示标签 } }, data: [{ type: 'average', name: 'Avg' }] @@ -289,10 +302,10 @@ const ServiceBarChar = ({ customClassNames, dataInfo, height, showAvgLine, showL }, emphasis: { lineStyle: { - width: 1 // 保持线条宽度不变,禁用默认的悬停加粗 + width: 1 // 保持线条宽度不变,禁用默认的悬停加粗 }, label: { - show: false // 悬停时不显示标签 + show: false // 悬停时不显示标签 } }, data: [{ type: 'average', name: 'Avg' }] @@ -348,6 +361,24 @@ const ServiceBarChar = ({ customClassNames, dataInfo, height, showAvgLine, showL }, []) return (
+ { + hideIndicatorValue && ( +
+
+
+
+ +
+ {dataInfo?.max} +
+ +
+ {dataInfo?.min} +
+
+
+ ) + }
{ const { code, data, msg } = response @@ -114,24 +118,24 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ ...setBarChartInfoData({ title: $t('请求次数'), data: serviceOverview.requestOverview, - value: serviceOverview.requestTotal, + value: formatNumberWithUnit(serviceOverview.requestTotal), date: serviceOverview.date }), - request2xxTotal: serviceOverview.request2xxTotal, - request4xxTotal: serviceOverview.request4xxTotal, - request5xxTotal: serviceOverview.request5xxTotal + request2xxTotal: formatNumberWithUnit(serviceOverview.request2xxTotal), + request4xxTotal: formatNumberWithUnit(serviceOverview.request4xxTotal), + request5xxTotal: formatNumberWithUnit(serviceOverview.request5xxTotal) }, // 流量消耗总数 { ...setBarChartInfoData({ title: $t('网络流量'), data: serviceOverview.trafficOverview, - value: serviceOverview.trafficTotal, + value: formatBytes(serviceOverview.trafficTotal), date: serviceOverview.date }), - traffic2xxTotal: serviceOverview.traffic2xxTotal, - traffic4xxTotal: serviceOverview.traffic4xxTotal, - traffic5xxTotal: serviceOverview.traffic5xxTotal + traffic2xxTotal: formatBytes(serviceOverview.traffic2xxTotal), + traffic4xxTotal: formatBytes(serviceOverview.traffic4xxTotal), + traffic5xxTotal: formatBytes(serviceOverview.traffic5xxTotal) } ]) // 设置平均值数据 @@ -140,29 +144,36 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ { title: $t('平均响应时间'), data: serviceOverview.avgResponseTimeOverview, - value: serviceOverview.avgResponseTime, + value: formatDuration(serviceOverview.avgResponseTime), + originValue: serviceOverview.avgResponseTime, date: serviceOverview.date, - max: serviceOverview.maxResponseTime, - min: serviceOverview.minResponseTime, + max: formatDuration(serviceOverview.maxResponseTime), + min: formatDuration(serviceOverview.minResponseTime), type: 'area', showXAxis: false }, // 平均请求 - setBarChartInfoData({ - title: $t('平均每消费者的请求次数'), - data: serviceOverview.avgRequestPerSubscriberOverview, - value: serviceOverview.avgRequestPerSubscriber, - date: serviceOverview.date, - showXAxis: false - }), + { + ...setBarChartInfoData({ + title: $t('平均每消费者的请求次数'), + data: serviceOverview.avgRequestPerSubscriberOverview, + date: serviceOverview.date, + showXAxis: false + }), + max: abbreviateFloat(serviceOverview.maxRequestPerSubscriber), + min: abbreviateFloat(serviceOverview.minRequestPerSubscriber) + }, // 平均流量消耗 - setBarChartInfoData({ - title: $t('平均每消费者的网络流量'), - data: serviceOverview.avgTrafficPerSubscriberOverview, - value: serviceOverview.avgTrafficPerSubscriber, - date: serviceOverview.date, - showXAxis: false - }) + { + ...setBarChartInfoData({ + title: $t('平均每消费者的网络流量'), + data: serviceOverview.avgTrafficPerSubscriberOverview, + date: serviceOverview.date, + showXAxis: false + }), + max: formatBytes(serviceOverview.maxTrafficPerSubscriber), + min: formatBytes(serviceOverview.minTrafficPerSubscriber) + } ]) } @@ -186,12 +197,12 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ ...setBarChartInfoData({ title: $t('请求次数'), data: serviceOverview.requestOverview, - value: serviceOverview.requestTotal, + value: formatNumberWithUnit(serviceOverview.requestTotal), date: serviceOverview.date }), - request2xxTotal: serviceOverview.request2xxTotal, - request4xxTotal: serviceOverview.request4xxTotal, - request5xxTotal: serviceOverview.request5xxTotal + request2xxTotal: formatNumberWithUnit(serviceOverview.request2xxTotal), + request4xxTotal: formatNumberWithUnit(serviceOverview.request4xxTotal), + request5xxTotal: formatNumberWithUnit(serviceOverview.request5xxTotal) }, // token 消耗总数 { @@ -201,11 +212,11 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ inputToken: item.inputToken, outputToken: item.outputToken })), - value: serviceOverview.tokenTotal, + value: formatNumberWithUnit(serviceOverview.tokenTotal), date: serviceOverview.date }), - inputTokenTotal: serviceOverview.inputTokenTotal, - outputTokenTotal: serviceOverview.outputTokenTotal + inputTokenTotal: formatNumberWithUnit(serviceOverview.inputTokenTotal), + outputTokenTotal: formatNumberWithUnit(serviceOverview.outputTokenTotal) } ]) // 设置平均值数据 @@ -214,29 +225,38 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ { title: $t('平均 Token 消耗'), data: serviceOverview.avgTokenOverview, - value: serviceOverview.avgToken, + value: formatNumberWithUnit(serviceOverview.avgToken) + ' Token/s', + originValue: serviceOverview.avgToken, date: serviceOverview.date, - min: serviceOverview.minToken, - max: serviceOverview.maxToken, + min: formatNumberWithUnit(serviceOverview.minToken) + ' Token/s', + max: formatNumberWithUnit(serviceOverview.maxToken) + ' Token/s', type: 'area' }, - // 平均请求 - setBarChartInfoData({ - title: $t('平均每消费者的请求次数'), - data: serviceOverview.avgRequestPerSubscriberOverview, - value: serviceOverview.avgRequestPerSubscriber, - date: serviceOverview.date - }), + { + // 平均请求 + ...setBarChartInfoData({ + title: $t('平均每消费者的请求次数'), + data: serviceOverview.avgRequestPerSubscriberOverview, + date: serviceOverview.date + }), + max: abbreviateFloat(serviceOverview.maxRequestPerSubscriber), + min: abbreviateFloat(serviceOverview.minRequestPerSubscriber) + }, // 评价 token 消耗 - setBarChartInfoData({ - title: $t('平均每消费者的 Token 消耗'), - data: serviceOverview.avgTokenPerSubscriberOverview.map((item: { inputToken: number; outputToken: number }) => ({ - inputToken: item.inputToken, - outputToken: item.outputToken - })), - value: serviceOverview.avgTokenPerSubscriber, - date: serviceOverview.date - }) + { + ...setBarChartInfoData({ + title: $t('平均每消费者的 Token 消耗'), + data: serviceOverview.avgTokenPerSubscriberOverview.map( + (item: { inputToken: number; outputToken: number }) => ({ + inputToken: item.inputToken, + outputToken: item.outputToken + }) + ), + date: serviceOverview.date + }), + max: abbreviateFloat(serviceOverview.maxTokenPerSubscriber), + min: abbreviateFloat(serviceOverview.minTokenPerSubscriber) + } ]) } @@ -268,7 +288,11 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ 'request_5xx_total', 'traffic_2xx_total', 'traffic_4xx_total', - 'traffic_5xx_total' + 'traffic_5xx_total', + 'max_request_per_subscriber', + 'min_request_per_subscriber', + 'max_traffic_per_subscriber', + 'min_traffic_per_subscriber' ] }).then((response) => { const { code, data, msg } = response @@ -354,7 +378,13 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ body: 'py-[15px] px-[0px]' }} > - + ))}
@@ -378,7 +408,13 @@ const ServiceOverview = ({ serviceType }: { serviceType: 'aiService' | 'restServ > ) : ( - + )} ))} diff --git a/frontend/packages/core/src/pages/serviceOverview/utils.ts b/frontend/packages/core/src/pages/serviceOverview/utils.ts index 6ec42e3b..ad68a882 100644 --- a/frontend/packages/core/src/pages/serviceOverview/utils.ts +++ b/frontend/packages/core/src/pages/serviceOverview/utils.ts @@ -1,6 +1,6 @@ export type BarData = { title: string - value: string + value?: string date: string[] data: any[] showXAxis?: boolean diff --git a/frontend/packages/dashboard/src/pages/DashboardTotal.tsx b/frontend/packages/dashboard/src/pages/DashboardTotal.tsx index 316b0b57..f91f46bb 100644 --- a/frontend/packages/dashboard/src/pages/DashboardTotal.tsx +++ b/frontend/packages/dashboard/src/pages/DashboardTotal.tsx @@ -4,7 +4,7 @@ import ScrollableSection from '@common/components/aoplatform/ScrollableSection' import { TimeRange } from '@common/components/aoplatform/TimeRangeSelector' import { useEffect, useState } from 'react' import DateSelectFilter, { TimeOption } from '@core/pages/serviceOverview/filter/DateSelectFilter' -import { getTime } from '@dashboard/utils/dashboard' +import { abbreviateFloat, formatBytes, formatDuration, formatNumberWithUnit, getTime } from '@dashboard/utils/dashboard' import { $t } from '@common/locales/index.ts' import { LoadingOutlined } from '@ant-design/icons' import { Card, Spin } from 'antd' @@ -71,7 +71,11 @@ export default function DashboardTotal() { 'request_4xx_total', 'request_5xx_total', 'input_token_total', - 'output_token_total' + 'output_token_total', + 'max_request_per_subscriber', + 'min_request_per_subscriber', + 'max_token_per_subscriber', + 'min_token_per_subscriber' ] }).then((response) => { const { code, data, msg } = response @@ -109,7 +113,11 @@ export default function DashboardTotal() { 'request_5xx_total', 'traffic_2xx_total', 'traffic_4xx_total', - 'traffic_5xx_total' + 'traffic_5xx_total', + 'max_request_per_subscriber', + 'min_request_per_subscriber', + 'max_traffic_per_subscriber', + 'min_traffic_per_subscriber' ] }).then((response) => { const { code, data, msg } = response @@ -135,24 +143,24 @@ export default function DashboardTotal() { ...setBarChartInfoData({ title: $t('请求次数'), data: serviceOverview.requestOverview, - value: serviceOverview.requestTotal, + value: formatNumberWithUnit(serviceOverview.requestTotal), date: serviceOverview.date }), - request2xxTotal: serviceOverview.request2xxTotal, - request4xxTotal: serviceOverview.request4xxTotal, - request5xxTotal: serviceOverview.request5xxTotal + request2xxTotal: formatNumberWithUnit(serviceOverview.request2xxTotal), + request4xxTotal: formatNumberWithUnit(serviceOverview.request4xxTotal), + request5xxTotal: formatNumberWithUnit(serviceOverview.request5xxTotal) }, // 流量消耗总数 { ...setBarChartInfoData({ title: $t('网络流量'), data: serviceOverview.trafficOverview, - value: serviceOverview.trafficTotal, + value: formatBytes(serviceOverview.trafficTotal), date: serviceOverview.date }), - traffic2xxTotal: serviceOverview.traffic2xxTotal, - traffic4xxTotal: serviceOverview.traffic4xxTotal, - traffic5xxTotal: serviceOverview.traffic5xxTotal + traffic2xxTotal: formatBytes(serviceOverview.traffic2xxTotal), + traffic4xxTotal: formatBytes(serviceOverview.traffic4xxTotal), + traffic5xxTotal: formatBytes(serviceOverview.traffic5xxTotal) } ]) // 设置平均值数据 @@ -161,26 +169,33 @@ export default function DashboardTotal() { { title: $t('平均响应时间'), data: serviceOverview.avgResponseTimeOverview, - value: serviceOverview.avgResponseTime, + value: formatDuration(serviceOverview.avgResponseTime), + originValue: serviceOverview.avgResponseTime, date: serviceOverview.date, - min: serviceOverview.minResponseTime, - max: serviceOverview.maxResponseTime, + min: formatDuration(serviceOverview.minResponseTime), + max: formatDuration(serviceOverview.maxResponseTime), type: 'area' }, // 平均请求 - setBarChartInfoData({ - title: $t('平均每消费者的请求次数'), - data: serviceOverview.avgRequestPerSubscriberOverview, - value: serviceOverview.avgRequestPerSubscriber, - date: serviceOverview.date - }), + { + ...setBarChartInfoData({ + title: $t('平均每消费者的请求次数'), + data: serviceOverview.avgRequestPerSubscriberOverview, + date: serviceOverview.date + }), + max: abbreviateFloat(serviceOverview.maxRequestPerSubscriber), + min: abbreviateFloat(serviceOverview.minRequestPerSubscriber) + }, // 平均流量消耗 - setBarChartInfoData({ - title: $t('平均每消费者的网络流量'), - data: serviceOverview.avgTrafficPerSubscriberOverview, - value: serviceOverview.avgTrafficPerSubscriber, - date: serviceOverview.date - }) + { + ...setBarChartInfoData({ + title: $t('平均每消费者的网络流量'), + data: serviceOverview.avgTrafficPerSubscriberOverview, + date: serviceOverview.date + }), + max: formatBytes(serviceOverview.maxTrafficPerSubscriber), + min: formatBytes(serviceOverview.minTrafficPerSubscriber) + } ]) } @@ -195,12 +210,12 @@ export default function DashboardTotal() { ...setBarChartInfoData({ title: $t('请求次数'), data: serviceOverview.requestOverview, - value: serviceOverview.requestTotal, + value: formatNumberWithUnit(serviceOverview.requestTotal), date: serviceOverview.date }), - request2xxTotal: serviceOverview.request2xxTotal, - request4xxTotal: serviceOverview.request4xxTotal, - request5xxTotal: serviceOverview.request5xxTotal + request2xxTotal: formatNumberWithUnit(serviceOverview.request2xxTotal), + request4xxTotal: formatNumberWithUnit(serviceOverview.request4xxTotal), + request5xxTotal: formatNumberWithUnit(serviceOverview.request5xxTotal) }, // token 消耗总数 { @@ -210,11 +225,11 @@ export default function DashboardTotal() { inputToken: item.inputToken, outputToken: item.outputToken })), - value: serviceOverview.tokenTotal, + value: formatNumberWithUnit(serviceOverview.tokenTotal), date: serviceOverview.date }), - inputTokenTotal: serviceOverview.inputTokenTotal, - outputTokenTotal: serviceOverview.outputTokenTotal + inputTokenTotal: formatNumberWithUnit(serviceOverview.inputTokenTotal), + outputTokenTotal: formatNumberWithUnit(serviceOverview.outputTokenTotal) } ]) // 设置平均值数据 @@ -223,31 +238,38 @@ export default function DashboardTotal() { { title: $t('平均 Token 消耗'), data: serviceOverview.avgTokenOverview, - value: serviceOverview.avgToken, + value: formatNumberWithUnit(serviceOverview.avgToken) + ' Token/s', + originValue: serviceOverview.avgToken, date: serviceOverview.date, - min: serviceOverview.minToken, - max: serviceOverview.maxToken, + min: formatNumberWithUnit(serviceOverview.minToken) + ' Token/s', + max: formatNumberWithUnit(serviceOverview.maxToken) + ' Token/s', type: 'area' }, // 平均请求 - setBarChartInfoData({ - title: $t('平均每消费者的请求次数'), - data: serviceOverview.avgRequestPerSubscriberOverview, - value: serviceOverview.avgRequestPerSubscriber, - date: serviceOverview.date - }), + { + ...setBarChartInfoData({ + title: $t('平均每消费者的请求次数'), + data: serviceOverview.avgRequestPerSubscriberOverview, + date: serviceOverview.date + }), + max: abbreviateFloat(serviceOverview.maxRequestPerSubscriber), + min: abbreviateFloat(serviceOverview.minRequestPerSubscriber) + }, // 平均 token 消耗 - setBarChartInfoData({ - title: $t('平均每消费者的 Token 消耗'), - data: serviceOverview.avgTokenPerSubscriberOverview.map( - (item: { inputToken: number; outputToken: number }) => ({ - inputToken: item.inputToken, - outputToken: item.outputToken - }) - ), - value: serviceOverview.avgTokenPerSubscriber, - date: serviceOverview.date - }) + { + ...setBarChartInfoData({ + title: $t('平均每消费者的 Token 消耗'), + data: serviceOverview.avgTokenPerSubscriberOverview.map( + (item: { inputToken: number; outputToken: number }) => ({ + inputToken: item.inputToken, + outputToken: item.outputToken + }) + ), + date: serviceOverview.date + }), + max: abbreviateFloat(serviceOverview.maxTokenPerSubscriber), + min: abbreviateFloat(serviceOverview.minTokenPerSubscriber) + } ]) } @@ -394,7 +416,7 @@ export default function DashboardTotal() { diff --git a/frontend/packages/dashboard/src/utils/dashboard.ts b/frontend/packages/dashboard/src/utils/dashboard.ts index d81a0f60..58b20cb6 100644 --- a/frontend/packages/dashboard/src/utils/dashboard.ts +++ b/frontend/packages/dashboard/src/utils/dashboard.ts @@ -89,3 +89,114 @@ export function yUnitFormatter(value: number): string { } return res } + +/** + * 格式化数字并添加适当的单位后缀 + * 根据数字大小自动选择合适的单位: + * - 小于1000:原始数字 + * - 千级别(K): 1,000 - 999,999 + * - 百万级别(M): 1,000,000 - 999,999,999 + * - 十亿级别(B): 1,000,000,000 - 999,999,999,999 + * - 万亿级别(T): 1,000,000,000,000及以上 + * @param count 需要格式化的数字 + * @returns 格式化后的字符串,包含单位 + */ +export function formatNumberWithUnit(count: number) { + if (count < 1000) { + return count.toString() // 小于1000直接返回 + } else if (count < 1_000_000) { + return (count / 1000).toFixed(1) + 'K' // 千级别,如1.5K + } else if (count < 1_000_000_000) { + return (count / 1_000_000).toFixed(1) + 'M' // 百万级别,如2.3M + } else if (count < 1_000_000_000_000) { + return (count / 1_000_000_000).toFixed(1) + 'B' // 十亿级别,如4.5B + } else { + return (count / 1_000_000_000_000).toFixed(1) + 'T' // 万亿级别,如7.8T + } +} + +/** + * 格式化浮点数并缩写为带单位的形式 + * 与 formatNumberWithUnit 类似,但对小于1000的数字也进行保留1位小数的格式化 + * - 小于1000:保留1位小数 + * - 千级别(K): 1,000 - 999,999 + * - 百万级别(M): 1,000,000 - 999,999,999 + * - 十亿级别(B): 1,000,000,000 - 999,999,999,999 + * - 万亿级别(T): 1,000,000,000,000及以上 + * @param count 需要格式化的数字 + * @returns 格式化后的字符串,包含单位 + */ +export function abbreviateFloat(count: number) { + if (count < 1000) { + return count.toFixed(1) // 小于1000的数字保留1位小数,如5.0 + } else if (count < 1_000_000) { + return (count / 1000).toFixed(1) + 'K' // 千级别,如1.5K + } else if (count < 1_000_000_000) { + return (count / 1_000_000).toFixed(1) + 'M' // 百万级别,如2.3M + } else if (count < 1_000_000_000_000) { + return (count / 1_000_000_000).toFixed(1) + 'B' // 十亿级别,如4.5B + } else { + return (count / 1_000_000_000_000).toFixed(1) + 'T' // 万亿级别,如7.8T + } +} + +/** + * 格式化时间持续时间,自动选择合适的时间单位 + * 根据持续时间的长度自动选择不同的单位: + * - 毫秒(ms): < 1000 + * - 秒(s): 1,000 - 999,999 + * - 分钟(min): 1,000,000 - 999,999,999 + * - 小时(hour): 1,000,000,000 - 999,999,999,999 + * - 天(day): ≥ 1,000,000,000,000 + * @param durationNano 时间持续时间数值 + * @returns 格式化后的字符串,包含单位 + */ +export function formatDuration(durationNano: number) { + if (durationNano < 1000) { + return `${durationNano}ms` // 小于1000,返回毫秒 + } + if (durationNano < 1_000_000) { + return (durationNano / 1000).toFixed(1) + 's' // 转换为秒 + } + if (durationNano < 1_000_000_000) { + return (durationNano / 1_000_000).toFixed(1) + 'min' // 转换为分钟 + } + if (durationNano < 1_000_000_000_000) { + return (durationNano / 1_000_000_000).toFixed(1) + 'hour' // 转换为小时 + } + return (durationNano / 1_000_000_000_000).toFixed(1) + 'day' // 转换为天 +} + +/** + * 格式化数据大小,自动选择合适的单位 + * 根据字节数自动选择适当的单位进行显示: + * - 字节(B): < 1000 + * - 千字节(KB): 1,000 - 999,999 + * - 兆字节(MB): 1,000,000 - 999,999,999 + * - 吉字节(GB): 1,000,000,000 - 999,999,999,999 + * - 太字节(TB): 1,000,000,000,000 - 999,999,999,999,999 + * - 拉字节(PB): ≥ 1,000,000,000,000,000 + * @param bytes 字节数 + * @returns 格式化后的字符串,包含单位 + */ +export function formatBytes(bytes: number) { + const KB = 1000 // 千字节 + const MB = KB * 1000 // 兆字节 + const GB = MB * 1000 // 吉字节 + const TB = GB * 1000 // 太字节 + const PB = TB * 1000 // 拉字节 + + if (bytes < KB) { + return `${bytes}B` // 直接显示字节 + } else if (bytes < MB) { + return (bytes / KB).toFixed(1) + 'KB' // 转换为千字节 + } else if (bytes < GB) { + return (bytes / MB).toFixed(1) + 'MB' // 转换为兆字节 + } else if (bytes < TB) { + return (bytes / GB).toFixed(1) + 'GB' // 转换为吉字节 + } else if (bytes < PB) { + return (bytes / TB).toFixed(1) + 'TB' // 转换为太字节 + } else { + return (bytes / PB).toFixed(1) + 'PB' // 转换为拉字节 + } +}