From ece58b60ec3eae89889d80f022b4dab0c6b8858d Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sun, 21 Dec 2025 02:35:25 +0800 Subject: [PATCH] fix the month names were displayed incorrectly in the monthly income and expense trends chart when daylight saving time was involved (#392) --- src/models/transaction.ts | 29 ++++++++++--------- src/views/desktop/HomePage.vue | 19 +++++++----- .../cards/MonthlyIncomeAndExpenseCard.vue | 6 +++- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/models/transaction.ts b/src/models/transaction.ts index c3ad03f7..b37bce7c 100644 --- a/src/models/transaction.ts +++ b/src/models/transaction.ts @@ -677,20 +677,20 @@ export const ALL_TRANSACTION_AMOUNTS_REQUEST_TYPE = [ export type TransactionAmountsRequestType = typeof ALL_TRANSACTION_AMOUNTS_REQUEST_TYPE[number]; -export const LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES: TransactionAmountsRequestType[] = [ - 'monthBeforeLast10Months', - 'monthBeforeLast9Months', - 'monthBeforeLast8Months', - 'monthBeforeLast7Months', - 'monthBeforeLast6Months', - 'monthBeforeLast5Months', - 'monthBeforeLast4Months', - 'monthBeforeLast3Months', - 'monthBeforeLast2Months', - 'monthBeforeLastMonth', - 'lastMonth', - 'thisMonth' -]; +export const LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES: PartialRecord = { + 'monthBeforeLast10Months': 11, + 'monthBeforeLast9Months': 10, + 'monthBeforeLast8Months': 9, + 'monthBeforeLast7Months': 8, + 'monthBeforeLast6Months': 7, + 'monthBeforeLast5Months': 6, + 'monthBeforeLast4Months': 5, + 'monthBeforeLast3Months': 4, + 'monthBeforeLast2Months': 3, + 'monthBeforeLastMonth': 2, + 'lastMonth': 1, + 'thisMonth': 0 +}; export interface TransactionAmountsRequestParams extends PartialRecord { readonly useTransactionTimezone: boolean; @@ -1009,6 +1009,7 @@ export interface TransactionOverviewResponseItem { export interface TransactionMonthlyIncomeAndExpenseData { readonly monthStartTime: number; + readonly monthsBeforeCurrentMonth: number; readonly incomeAmount: number; readonly expenseAmount: number; readonly incompleteIncomeAmount: boolean; diff --git a/src/views/desktop/HomePage.vue b/src/views/desktop/HomePage.vue index c9970fb6..e32e9b96 100644 --- a/src/views/desktop/HomePage.vue +++ b/src/views/desktop/HomePage.vue @@ -202,10 +202,15 @@ import { useAccountsStore } from '@/stores/account.ts'; import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts'; import { useOverviewStore } from '@/stores/overview.ts'; +import { entries } from '@/core/base.ts'; import { type NumeralSystem } from '@/core/numeral.ts'; import { DateRange } from '@/core/datetime.ts'; import { ThemeType } from '@/core/theme.ts'; -import { type TransactionMonthlyIncomeAndExpenseData, LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES } from '@/models/transaction.ts'; +import { + type TransactionAmountsRequestType, + type TransactionMonthlyIncomeAndExpenseData, + LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES +} from '@/models/transaction.ts'; import { getUnixTimeBeforeUnixTime, getUnixTimeAfterUnixTime } from '@/lib/datetime.ts'; import { isUserLogined, isUserUnlocked } from '@/lib/userstate.ts'; @@ -275,27 +280,25 @@ const monthlyIncomeAndExpenseData = computed { - if (!Object.prototype.hasOwnProperty.call(transactionOverview.value, amountRequestType)) { - return; - } - + for (const [type, monthDiff] of entries(LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES)) { + const amountRequestType = type as TransactionAmountsRequestType; const dateRange = overviewStore.transactionDataRange[amountRequestType]; if (!dateRange) { - return; + continue; } const item = transactionOverview.value[amountRequestType]; data.push({ monthStartTime: dateRange.startTime, + monthsBeforeCurrentMonth: monthDiff, incomeAmount: item?.incomeAmount || 0, expenseAmount: item?.expenseAmount || 0, incompleteIncomeAmount: item ? item.incompleteIncomeAmount : true, incompleteExpenseAmount: item ? item.incompleteExpenseAmount : true }); - }); + } return data; }); diff --git a/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue b/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue index 6b58a5dc..a5c65cc6 100644 --- a/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue +++ b/src/views/desktop/overview/cards/MonthlyIncomeAndExpenseCard.vue @@ -41,6 +41,7 @@ import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numera import { type TransactionMonthlyIncomeAndExpenseData } from '@/models/transaction.ts'; +import { getUnixTimeBeforeUnixTime, getThisMonthFirstUnixTime } from '@/lib/datetime.ts'; import { getExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts'; export interface MonthlyIncomeAndExpenseCardClickEvent { @@ -97,8 +98,11 @@ const chartOptions = computed(() => { const expenseIncomeAmountColor = getExpenseAndIncomeAmountColor(userStore.currentUserExpenseAmountColor, userStore.currentUserIncomeAmountColor, props.isDarkMode); if (props.data) { + const currentMonthFirstUnixTime = getThisMonthFirstUnixTime(); + for (const item of props.data) { - const monthShortName = formatUnixTimeToGregorianLikeShortMonth(item.monthStartTime); + const monthFirstUnixTime = getUnixTimeBeforeUnixTime(currentMonthFirstUnixTime, item.monthsBeforeCurrentMonth, 'months'); + const monthShortName = formatUnixTimeToGregorianLikeShortMonth(monthFirstUnixTime); monthNames.push(monthShortName); incomeAmounts.push(item.incomeAmount);