diff --git a/src/pages/popup/components/Footer/DurationSelect.tsx b/src/pages/popup/components/Footer/DurationSelect.tsx index 3c471746..10d3abce 100644 --- a/src/pages/popup/components/Footer/DurationSelect.tsx +++ b/src/pages/popup/components/Footer/DurationSelect.tsx @@ -20,7 +20,7 @@ const cvt2Opt = (value: PopupDuration, n?: string | number): CascaderOption => ( const options = (reverse?: boolean): CascaderOption[] => { const result: CascaderOption[] = [ - ...(['today', 'thisWeek', 'thisMonth', 'yesterday'] satisfies PopupDuration[]).map(cvt2Opt), + ...(['today', 'yesterday', 'thisWeek', 'thisMonth'] satisfies PopupDuration[]).map(cvt2Opt), { ...cvt2Opt('lastDays', 'X'), children: [ diff --git a/src/pages/popup/components/Percentage/chart.ts b/src/pages/popup/components/Percentage/chart.ts index 672ce0df..55e8b616 100644 --- a/src/pages/popup/components/Percentage/chart.ts +++ b/src/pages/popup/components/Percentage/chart.ts @@ -73,12 +73,34 @@ function formatTotalStr(rows: timer.stat.Row[], type: timer.core.Dimension | und } function calculateSubTitleText(result: PercentageResult): string { - let { date, dataDate, rows, query: { dimension } = {} } = result + let { date, dataDate, rows, query: { dimension, duration } = {}, dateLength } = result const dateStr = dataDate ? formatDateStr(date, dataDate) : '' const totalStr = formatTotalStr(rows, dimension) - let parts = [totalStr, dateStr].filter(str => !!str) + + // Calculate average per day + let averageStr = '' + // Don't show averages for single-day durations (today/yesterday) + const isSingleDay = duration === 'today' || duration === 'yesterday' + + if (dateLength && dateLength > 0 && !isSingleDay) { // Changed: removed dimension check + if (dimension === 'focus') { + // Average time per day + const total = sum(rows.map(r => r?.focus ?? 0)) + const averagePerDay = total / dateLength + const averageTime = formatPeriodCommon(averagePerDay) + averageStr = '(' + t(msg => msg.content.percentage.averageTime, { value: averageTime }) + ')' + } else if (dimension === 'time') { + // Average visits per day + const totalCount = sum(rows.map(r => r.time ?? 0)) + const averagePerDay = totalCount / dateLength + const averageCount = averagePerDay.toFixed(1) + averageStr = '(' + t(msg => msg.content.percentage.averageCount, { value: averageCount }) + ')' + } + } + + let parts = [totalStr, dateStr, averageStr].filter(str => !!str) isRtl() && (parts = parts.reverse()) - return parts.join(' @ ') + return parts.join(' ') } export function generateTitleOption(result: PercentageResult, suffix?: string): TitleComponentOption { @@ -265,13 +287,11 @@ export function formatTooltip({ query, dateLength }: PercentageResult, params: T const format = (Array.isArray(params) ? params[0] : params) const { name, value, percent, data } = format ?? {} const { row } = data as PieSeriesItemOption - const { dimension } = query + const { dimension, duration } = query const itemValue = typeof value === 'number' ? value as number : 0 - let valueLine = dimension === 'time' ? itemValue : formatPeriodCommon(itemValue) // Display percent only when query focus time dimension === 'focus' && (valueLine += ` (${percent}%)`) - let nameLine = name let averageLine: string | undefined = undefined if (!isOther(row)) { @@ -279,11 +299,13 @@ export function formatTooltip({ query, dateLength }: PercentageResult, params: T const { siteKey: { host } } = row nameLine = generateSiteLabel(host, name) } - if (dateLength && dateLength > 1) { + // Don't show averages for single-day durations (today/yesterday) + const isSingleDay = duration === 'today' || duration === 'yesterday' + + if (dateLength && dateLength > 1 && !isSingleDay) { // Changed: simplified condition averageLine = calculateAverageText(dimension, itemValue / dateLength) } } - return [nameLine, valueLine, averageLine].filter(l => !!l).join('
') } diff --git a/src/pages/popup/components/Percentage/query.ts b/src/pages/popup/components/Percentage/query.ts index 57bf2961..da3f0362 100644 --- a/src/pages/popup/components/Percentage/query.ts +++ b/src/pages/popup/components/Percentage/query.ts @@ -49,10 +49,20 @@ export const doQuery = async (query: PopupQuery, option: PopupOption): Promise

() + rows?.forEach(row => { + const dates = findAllDates(row) + dates.forEach(d => allDatesSet.add(d)) + }) + const dateLength = allDatesSet.size > 0 ? allDatesSet.size : (date instanceof Array ? getDayLength(date[0], date[1] ?? new Date()) : 1) + return { query, rows, - date, dataDate: findDateRange(rows), - dateLength: date instanceof Array ? getDayLength(date[0], date[1] ?? new Date()) : 1, + date, dataDate, + dateLength, displaySiteName, chartTitle: t(msg => msg.content.percentage.title[query?.duration], { n: query?.durationNum }), itemCount, diff --git a/src/util/time.ts b/src/util/time.ts index 2a0f0699..86a13eef 100644 --- a/src/util/time.ts +++ b/src/util/time.ts @@ -105,15 +105,15 @@ export function formatPeriod(milliseconds: number, message: Record<'dayMsg' | 'h */ export function formatPeriodCommon(milliseconds: number): string { const defaultMessage = isRtl() ? { - dayMsg: 's {second} m {minute} h {hour} d', - hourMsg: 's {second} m {minute} h {hour}', - minuteMsg: 's {second} m {minute}', - secondMsg: 's {second}', + dayMsg: 's{second} m{minute} h{hour} d', + hourMsg: 's{second} m{minute} h{hour}', + minuteMsg: 's{second} m{minute}', + secondMsg: 's{second}', } : { - dayMsg: '{day} d {hour} h {minute} m {second} s', - hourMsg: '{hour} h {minute} m {second} s', - minuteMsg: '{minute} m {second} s', - secondMsg: '{second} s', + dayMsg: '{day}d {hour}h {minute}m {second}s', + hourMsg: '{hour}h {minute}m {second}s', + minuteMsg: '{minute}m {second}s', + secondMsg: '{second}s', } return formatPeriod(milliseconds, defaultMessage) } diff --git a/test/util/time.test.ts b/test/util/time.test.ts index efab523e..40785c10 100644 --- a/test/util/time.test.ts +++ b/test/util/time.test.ts @@ -38,9 +38,9 @@ test('format', () => { } expect(formatPeriod(86400 * 1000, msg)).toEqual('1天0时0分0秒') expect(formatPeriod(3666 * 1000, msg)).toEqual('1时1分6秒') - expect(formatPeriodCommon(86400 * 1000)).toEqual('1 d 0 h 0 m 0 s') - expect(formatPeriodCommon(3666 * 1000)).toEqual('1 h 1 m 6 s') - expect(formatPeriodCommon(1)).toEqual('0 s') + expect(formatPeriodCommon(86400 * 1000)).toEqual('1d 0h 0m 0s') + expect(formatPeriodCommon(3666 * 1000)).toEqual('1h 1m 6s') + expect(formatPeriodCommon(1)).toEqual('0s') }) test('days ago', () => {