@@ -94,6 +94,7 @@ export interface UsageDeskProjectedStats {
9494
9595export type UsageDeskChartUnit = 'count' | 'tokens' ;
9696export type UsageDeskRangeOption = 'TODAY' | '7D' | '14D' | '30D' | '全部' ;
97+ export type UsageDeskResolution = '1M' | '5M' | '15M' | '30M' | '60M' ;
9798
9899function isRecord ( value : unknown ) : value is Record < string , unknown > {
99100 return value !== null && typeof value === 'object' && ! Array . isArray ( value ) ;
@@ -114,16 +115,22 @@ function buildDayKey(date: Date) {
114115 return `${ date . getFullYear ( ) } -${ pad2 ( date . getMonth ( ) + 1 ) } -${ pad2 ( date . getDate ( ) ) } ` ;
115116}
116117
117- function buildMinuteKey ( date : Date ) {
118- return `${ buildDayKey ( date ) } ${ pad2 ( date . getHours ( ) ) } :${ pad2 ( date . getMinutes ( ) ) } ` ;
118+ function buildMinuteKey ( date : Date , resolution : UsageDeskResolution = '1M' ) {
119+ const mins = date . getMinutes ( ) ;
120+ const resValue = parseInt ( resolution ) ;
121+ const roundedMins = Math . floor ( mins / resValue ) * resValue ;
122+ return `${ buildDayKey ( date ) } ${ pad2 ( date . getHours ( ) ) } :${ pad2 ( roundedMins ) } ` ;
119123}
120124
121125function buildDayLabel ( dayKey : string ) {
122126 return dayKey . slice ( 5 ) ;
123127}
124128
125- function buildMinuteLabel ( date : Date ) {
126- return `${ pad2 ( date . getHours ( ) ) } :${ pad2 ( date . getMinutes ( ) ) } ` ;
129+ function buildMinuteLabel ( date : Date , resolution : UsageDeskResolution = '1M' ) {
130+ const mins = date . getMinutes ( ) ;
131+ const resValue = parseInt ( resolution ) ;
132+ const roundedMins = Math . floor ( mins / resValue ) * resValue ;
133+ return `${ pad2 ( date . getHours ( ) ) } :${ pad2 ( roundedMins ) } ` ;
127134}
128135
129136export function formatUsageDeskChartValue ( value : number , unit : UsageDeskChartUnit ) : string {
@@ -196,6 +203,14 @@ export function resolveUsageDeskLinkedRowKey(
196203 ] . join ( '|' ) ;
197204}
198205
206+ export function buildUsageDeskChartPointStyle ( x : number , y : number ) {
207+ return {
208+ left : `${ x } px` ,
209+ top : `${ y } px` ,
210+ transform : 'translate(-50%, -50%)' ,
211+ } ;
212+ }
213+
199214function formatUsageDeskCompactNumber ( value : number ) : string {
200215 const normalized = Math . round ( value * 10 ) / 10 ;
201216 if ( Number . isInteger ( normalized ) ) {
@@ -242,6 +257,7 @@ export function collectUsageDeskObservedDetails(usageData: unknown): UsageDeskOb
242257export function buildUsageDeskObservedSnapshot (
243258 usageData : unknown ,
244259 selectedDayKey ?: string | null ,
260+ resolution : UsageDeskResolution = '1M' ,
245261) : UsageDeskObservedSnapshot {
246262 const details = collectUsageDeskObservedDetails ( usageData ) ;
247263 if ( details . length === 0 ) {
@@ -304,10 +320,10 @@ export function buildUsageDeskObservedSnapshot(
304320 const date = parseTimestamp ( detail . timestamp ) ;
305321 if ( ! date || buildDayKey ( date ) !== resolvedDayKey ) return ;
306322
307- const minuteKey = buildMinuteKey ( date ) ;
323+ const minuteKey = buildMinuteKey ( date , resolution ) ;
308324 const minutePoint = minuteMap . get ( minuteKey ) ?? {
309325 minuteKey,
310- label : buildMinuteLabel ( date ) ,
326+ label : buildMinuteLabel ( date , resolution ) ,
311327 success : 0 ,
312328 failure : 0 ,
313329 } ;
@@ -320,7 +336,7 @@ export function buildUsageDeskObservedSnapshot(
320336 minuteMap . set ( minuteKey , minutePoint ) ;
321337
322338 const minuteRow = minuteRowMap . get ( minuteKey ) ?? {
323- timeLabel : buildMinuteLabel ( date ) ,
339+ timeLabel : buildMinuteLabel ( date , resolution ) ,
324340 provider : detail . provider ,
325341 success : 0 ,
326342 failure : 0 ,
@@ -343,7 +359,7 @@ export function buildUsageDeskObservedSnapshot(
343359 const minuteRows = Array . from ( minuteRowMap . entries ( ) )
344360 . sort ( ( a , b ) => b [ 0 ] . localeCompare ( a [ 0 ] ) )
345361 . map ( ( [ , row ] ) => {
346- if ( row . requests === 1 ) {
362+ if ( row . requests === 1 && resolution === '1M' ) {
347363 return {
348364 timeLabel : row . timeLabel ,
349365 provider : row . provider ,
@@ -406,6 +422,7 @@ export function collectUsageDeskProjectedDetails(payload: unknown): UsageDeskPro
406422export function buildUsageDeskProjectedSnapshot (
407423 payload : unknown ,
408424 selectedDayKey ?: string | null ,
425+ resolution : UsageDeskResolution = '1M' ,
409426) : UsageDeskProjectedSnapshot {
410427 const details = collectUsageDeskProjectedDetails ( payload ) ;
411428 if ( details . length === 0 ) {
@@ -473,10 +490,10 @@ export function buildUsageDeskProjectedSnapshot(
473490 const date = parseTimestamp ( detail . timestamp ) ;
474491 if ( ! date || buildDayKey ( date ) !== resolvedDayKey ) return ;
475492
476- const minuteKey = buildMinuteKey ( date ) ;
493+ const minuteKey = buildMinuteKey ( date , resolution ) ;
477494 const point = minuteMap . get ( minuteKey ) ?? {
478495 minuteKey,
479- label : buildMinuteLabel ( date ) ,
496+ label : buildMinuteLabel ( date , resolution ) ,
480497 requests : 0 ,
481498 totalTokens : 0 ,
482499 } ;
@@ -486,7 +503,7 @@ export function buildUsageDeskProjectedSnapshot(
486503 minuteMap . set ( minuteKey , point ) ;
487504
488505 const minuteRow = minuteRowMap . get ( minuteKey ) ?? {
489- timeLabel : buildMinuteLabel ( date ) ,
506+ timeLabel : buildMinuteLabel ( date , resolution ) ,
490507 provider : detail . provider ,
491508 totalTokens : 0 ,
492509 requests : 0 ,
0 commit comments