From 56ba4d88f4a08973fac44496be789c03d021b0d6 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Fri, 9 May 2025 01:14:35 +0800 Subject: [PATCH] add transaction calendar for mobile version --- src/styles/desktop/global.scss | 1 + src/styles/mobile/font-size-default.css | 2 + src/styles/mobile/font-size-large.css | 2 + src/styles/mobile/font-size-small.css | 2 + src/styles/mobile/font-size-x-large.css | 2 + src/styles/mobile/font-size-xx-large.css | 2 + src/styles/mobile/font-size-xxx-large.css | 2 + src/styles/mobile/font-size-xxxx-large.css | 2 + src/styles/mobile/global.css | 5 + .../transactions/TransactionListPageBase.ts | 44 ++- src/views/desktop/transactions/ListPage.vue | 48 +-- src/views/mobile/transactions/ListPage.vue | 274 +++++++++++++++++- 12 files changed, 336 insertions(+), 50 deletions(-) diff --git a/src/styles/desktop/global.scss b/src/styles/desktop/global.scss index 1eff2995..86c11d03 100644 --- a/src/styles/desktop/global.scss +++ b/src/styles/desktop/global.scss @@ -48,6 +48,7 @@ input[type=number] { /** Custom class **/ :root { --default-icon-color: #000; + --ebk-primary-color: 198, 126, 72; --v-expand-panel-title-bg: rgba(var(--v-theme-on-surface), var(--v-hover-opacity)); --v-card-title-bg: rgba(var(--v-theme-on-surface), var(--v-hover-opacity)); } diff --git a/src/styles/mobile/font-size-default.css b/src/styles/mobile/font-size-default.css index 7ef44be1..f0607427 100644 --- a/src/styles/mobile/font-size-default.css +++ b/src/styles/mobile/font-size-default.css @@ -75,6 +75,8 @@ --ebk-transaction-date-width: 25px; --ebk-transaction-day-font-size: 16px; --ebk-transaction-day-of-week-font-size: 12px; + --ebk-transaction-calendar-amount-font-size: 12px; + --ebk-transaction-calendar-daily-amounts-height: 65px; --ebk-transaction-account-arrow-font-size: 12px; --ebk-transaction-account-arrow-margin-top: -1px; --ebk-transaction-tag-icon-font-size: 22px; diff --git a/src/styles/mobile/font-size-large.css b/src/styles/mobile/font-size-large.css index c330a642..0ac3b607 100644 --- a/src/styles/mobile/font-size-large.css +++ b/src/styles/mobile/font-size-large.css @@ -75,6 +75,8 @@ --ebk-transaction-date-width: 28px; --ebk-transaction-day-font-size: 17px; --ebk-transaction-day-of-week-font-size: 13px; + --ebk-transaction-calendar-amount-font-size: 13px; + --ebk-transaction-calendar-daily-amounts-height: 65px; --ebk-transaction-account-arrow-font-size: 13px; --ebk-transaction-account-arrow-margin-top: -2px; --ebk-transaction-tag-icon-font-size: 24px; diff --git a/src/styles/mobile/font-size-small.css b/src/styles/mobile/font-size-small.css index 76056797..1d3ac9ca 100644 --- a/src/styles/mobile/font-size-small.css +++ b/src/styles/mobile/font-size-small.css @@ -75,6 +75,8 @@ --ebk-transaction-date-width: 25px; --ebk-transaction-day-font-size: 16px; --ebk-transaction-day-of-week-font-size: 12px; + --ebk-transaction-calendar-amount-font-size: 12px; + --ebk-transaction-calendar-daily-amounts-height: 65px; --ebk-transaction-account-arrow-font-size: 12px; --ebk-transaction-account-arrow-margin-top: -1px; --ebk-transaction-tag-icon-font-size: 20px; diff --git a/src/styles/mobile/font-size-x-large.css b/src/styles/mobile/font-size-x-large.css index 3a8a8844..735b6678 100644 --- a/src/styles/mobile/font-size-x-large.css +++ b/src/styles/mobile/font-size-x-large.css @@ -75,6 +75,8 @@ --ebk-transaction-date-width: 30px; --ebk-transaction-day-font-size: 18px; --ebk-transaction-day-of-week-font-size: 14px; + --ebk-transaction-calendar-amount-font-size: 14px; + --ebk-transaction-calendar-daily-amounts-height: 70px; --ebk-transaction-account-arrow-font-size: 14px; --ebk-transaction-account-arrow-margin-top: -2px; --ebk-transaction-tag-icon-font-size: 26px; diff --git a/src/styles/mobile/font-size-xx-large.css b/src/styles/mobile/font-size-xx-large.css index 11468eb4..f2c0aac4 100644 --- a/src/styles/mobile/font-size-xx-large.css +++ b/src/styles/mobile/font-size-xx-large.css @@ -75,6 +75,8 @@ --ebk-transaction-date-width: 32px; --ebk-transaction-day-font-size: 20px; --ebk-transaction-day-of-week-font-size: 15px; + --ebk-transaction-calendar-amount-font-size: 15px; + --ebk-transaction-calendar-daily-amounts-height: 75px; --ebk-transaction-account-arrow-font-size: 15px; --ebk-transaction-account-arrow-margin-top: -3px; --ebk-transaction-tag-icon-font-size: 28px; diff --git a/src/styles/mobile/font-size-xxx-large.css b/src/styles/mobile/font-size-xxx-large.css index 68446d5c..a648645e 100644 --- a/src/styles/mobile/font-size-xxx-large.css +++ b/src/styles/mobile/font-size-xxx-large.css @@ -75,6 +75,8 @@ --ebk-transaction-date-width: 36px; --ebk-transaction-day-font-size: 22px; --ebk-transaction-day-of-week-font-size: 17px; + --ebk-transaction-calendar-amount-font-size: 17px; + --ebk-transaction-calendar-daily-amounts-height: 80px; --ebk-transaction-account-arrow-font-size: 17px; --ebk-transaction-account-arrow-margin-top: -4px; --ebk-transaction-tag-icon-font-size: 30px; diff --git a/src/styles/mobile/font-size-xxxx-large.css b/src/styles/mobile/font-size-xxxx-large.css index 0ec9ddbc..928ba675 100644 --- a/src/styles/mobile/font-size-xxxx-large.css +++ b/src/styles/mobile/font-size-xxxx-large.css @@ -75,6 +75,8 @@ --ebk-transaction-date-width: 40px; --ebk-transaction-day-font-size: 24px; --ebk-transaction-day-of-week-font-size: 19px; + --ebk-transaction-calendar-amount-font-size: 19px; + --ebk-transaction-calendar-daily-amounts-height: 85px; --ebk-transaction-account-arrow-font-size: 19px; --ebk-transaction-account-arrow-margin-top: -4px; --ebk-transaction-tag-icon-font-size: 32px; diff --git a/src/styles/mobile/global.css b/src/styles/mobile/global.css index 6a39595e..f11f0796 100644 --- a/src/styles/mobile/global.css +++ b/src/styles/mobile/global.css @@ -108,6 +108,7 @@ i.icon.la, i.icon.las, i.icon.lab { /** custom class **/ :root { --default-icon-color: #000; + --ebk-primary-color: 198, 126, 72; --ebk-transaction-tag-chip-bg-color: rgba(0, 0, 0, 0.04); } @@ -535,6 +536,10 @@ i.icon.la, i.icon.las, i.icon.lab { border-radius: 0 0 var(--f7-list-inset-border-radius) var(--f7-list-inset-border-radius); } +.combination-list-wrapper.no-accordion-toggle .list.combination-list-content.inset > ul { + border-radius: var(--f7-list-inset-border-radius); +} + /** Nested List item for framework7 **/ .nested-list-item .item-title { width: 100%; diff --git a/src/views/base/transactions/TransactionListPageBase.ts b/src/views/base/transactions/TransactionListPageBase.ts index 9e16527f..fe81d330 100644 --- a/src/views/base/transactions/TransactionListPageBase.ts +++ b/src/views/base/transactions/TransactionListPageBase.ts @@ -23,9 +23,17 @@ import { getUtcOffsetByUtcOffsetMinutes, getTimezoneOffset, getTimezoneOffsetMinutes, + getBrowserTimezoneOffsetMinutes, + getLocalDatetimeFromUnixTime, + getActualUnixTimeForStore, + getDummyUnixTimeForLocalUsage, parseDateFromUnixTime, getUnixTime, - getYearMonthFirstUnixTime + getYear, + getMonth, + getDay, + getYearMonthFirstUnixTime, + isDateRangeMatchOneMonth } from '@/lib/datetime.ts'; import { @@ -162,6 +170,7 @@ export function useTransactionListPageBase() { }); const queryMinTime = computed(() => formatUnixTimeToLongDateTime(query.value.minTime)); const queryMaxTime = computed(() => formatUnixTimeToLongDateTime(query.value.maxTime)); + const queryMonthlyData = computed(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime)); const queryAllFilterCategoryIds = computed>(() => transactionsStore.allFilterCategoryIds); const queryAllFilterAccountIds = computed>(() => transactionsStore.allFilterAccountIds); const queryAllFilterTagIds = computed>(() => transactionsStore.allFilterTagIds); @@ -217,6 +226,34 @@ export function useTransactionListPageBase() { return displayAmount.join(' ~ '); }); + const transactionCalendarMinDate = computed(() => getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(query.value.minTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); + const transactionCalendarMaxDate = computed(() => getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(query.value.maxTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))); + + const currentMonthTransactionData = computed(() => { + const allTransactions = transactionsStore.transactions; + + if (!allTransactions || !allTransactions.length) { + return null; + } + + const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); + const currentYear = getYear(currentMonthMinDate); + const currentMonth = getMonth(currentMonthMinDate); + + for (let i = 0; i < allTransactions.length; i++) { + if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) { + return allTransactions[i]; + } + } + + return null; + }); + + function noTransactionInMonthDay(date: Date): boolean { + const dateTime = parseDateFromUnixTime(getActualUnixTimeForStore(getUnixTime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())); + return !currentMonthTransactionData.value || !currentMonthTransactionData.value.dailyTotalAmounts || !currentMonthTransactionData.value.dailyTotalAmounts[getDay(dateTime)]; + } + const canAddTransaction = computed(() => { if (query.value.accountIds && queryAllFilterAccountIdsCount.value === 1) { const account = allAccountsMap.value[query.value.accountIds]; @@ -335,6 +372,7 @@ export function useTransactionListPageBase() { queryDateRangeName, queryMinTime, queryMaxTime, + queryMonthlyData, queryAllFilterCategoryIds, queryAllFilterAccountIds, queryAllFilterTagIds, @@ -345,6 +383,10 @@ export function useTransactionListPageBase() { queryCategoryName, queryTagName, queryAmount, + transactionCalendarMinDate, + transactionCalendarMaxDate, + currentMonthTransactionData, + noTransactionInMonthDay, canAddTransaction, // functions getDisplayTime, diff --git a/src/views/desktop/transactions/ListPage.vue b/src/views/desktop/transactions/ListPage.vue index ca03f8ab..4d139b90 100644 --- a/src/views/desktop/transactions/ListPage.vue +++ b/src/views/desktop/transactions/ListPage.vue @@ -146,8 +146,8 @@ :month-change-on-arrows="false" :enable-time-picker="false" :hide-offset-dates="true" - :min-date="getShortDate(parseDateFromUnixTime(query.minTime))" - :max-date="getShortDate(parseDateFromUnixTime(query.maxTime))" + :min-date="transactionCalendarMinDate" + :max-date="transactionCalendarMaxDate" :disabled-dates="noTransactionInMonthDay" :prevent-min-max-navigation="true" :clearable="false" @@ -648,7 +648,7 @@ import { useSettingsStore } from '@/stores/setting.ts'; import { useAccountsStore } from '@/stores/account.ts'; import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts'; import { useTransactionTagsStore } from '@/stores/transactionTag.ts'; -import { type TransactionMonthList, useTransactionsStore } from '@/stores/transaction.ts'; +import { useTransactionsStore } from '@/stores/transaction.ts'; import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.ts'; import { useDesktopPageStore } from '@/stores/desktopPage.ts'; @@ -676,10 +676,8 @@ import { import { getCurrentUnixTime, parseDateFromUnixTime, - getShortDate, getYear, getMonth, - getDay, getSpecifiedDayFirstUnixTime, getBrowserTimezoneOffsetMinutes, getActualUnixTimeForStore, @@ -691,8 +689,7 @@ import { getDateRangeByBillingCycleDateType, getRecentDateRangeIndex, getFullMonthDateRange, - getMonthFirstDayOrCurrentDayShortDate, - isDateRangeMatchOneMonth + getMonthFirstDayOrCurrentDayShortDate } from '@/lib/datetime.ts'; import { categoryTypeToTransactionType, @@ -763,7 +760,6 @@ const { getAllLongWeekdayNames, getAllRecentMonthDateRanges, getAllTransactionTagFilterTypes, - getMonthShortName, getWeekdayLongName } = useI18n(); @@ -790,6 +786,7 @@ const { query, queryMinTime, queryMaxTime, + queryMonthlyData, queryAllFilterCategoryIds, queryAllFilterAccountIds, queryAllFilterTagIds, @@ -800,6 +797,10 @@ const { queryCategoryName, queryTagName, queryAmount, + transactionCalendarMinDate, + transactionCalendarMaxDate, + currentMonthTransactionData, + noTransactionInMonthDay, canAddTransaction, getDisplayTime, getDisplayLongDate, @@ -930,26 +931,6 @@ const transactions = computed(() => { } }); -const currentMonthTransactionData = computed(() => { - const allTransactions = transactionsStore.transactions; - - if (!allTransactions || !allTransactions.length) { - return null; - } - - const currentMonthMinDate = parseDateFromUnixTime(query.value.minTime); - const currentYear = getYear(currentMonthMinDate); - const currentMonth = getMonth(currentMonthMinDate); - - for (let i = 0; i < allTransactions.length; i++) { - if (allTransactions[i].year === currentYear && allTransactions[i].month === currentMonth) { - return allTransactions[i]; - } - } - - return null; -}); - const recentDateRangeIndex = computed({ get: () => getRecentDateRangeIndex(recentMonthDateRanges.value, query.value.dateType, query.value.minTime, query.value.maxTime, firstDayOfWeek.value), set: (value) => { @@ -1001,8 +982,6 @@ const queryAllSelectedFilterTagIds = computed(() => { } }); -const queryMonthlyData = computed(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime)); - const countPerPage = computed({ get: () => { if (temporaryCountPerPage.value) { @@ -1066,10 +1045,6 @@ const currentMonthTotalAmount = computed): Record { if (queryCategoryIds && queryCategoryIds[category.id]) { return { @@ -1150,6 +1125,7 @@ function init(initProps: TransactionListProps): void { }); if (changed) { + currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(query.value.minTime); updateUrlWhenChanged(changed); return; } @@ -1243,6 +1219,7 @@ function changePageType(type: number): void { maxTime: dateRange.maxTime, minTime: dateRange.minTime }); + currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(query.value.minTime); } } @@ -1281,6 +1258,7 @@ function changeDateFilter(dateRange: TimeRangeAndDateType | number | null): void if (fullMonthDateRange) { dateRange = fullMonthDateRange; + currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(dateRange.minTime); } } @@ -1316,6 +1294,7 @@ function changeCustomDateFilter(minTime: number, maxTime: number): void { minTime = dateRange.minTime; maxTime = dateRange.maxTime; dateType = dateRange.dateType; + currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(minTime); } } @@ -1355,6 +1334,7 @@ function shiftDateRange(startTime: number, endTime: number, scale: number): void if (fullMonthDateRange) { newDateRange = fullMonthDateRange; + currentCalendarDate.value = getMonthFirstDayOrCurrentDayShortDate(newDateRange.minTime); } } diff --git a/src/views/mobile/transactions/ListPage.vue b/src/views/mobile/transactions/ListPage.vue index 069bca46..31a7bb90 100644 --- a/src/views/mobile/transactions/ListPage.vue +++ b/src/views/mobile/transactions/ListPage.vue @@ -9,7 +9,12 @@ @infinite="loadMore(true)"> - + + + {{ displayPageTypeName }} + + + @@ -25,6 +30,21 @@ + + + + + + + + @@ -46,10 +66,41 @@ + + + + + +
- + - + @@ -122,12 +173,12 @@ - - + - + {{ tt('Load More') }} @@ -266,6 +318,7 @@ :class="{ 'list-item-selected': query.dateType === dateRange.type }" :key="dateRange.type" v-for="dateRange in allDateRanges" + v-show="pageType === TransactionListPageType.List.type || dateRange.type === DateRange.ThisMonth.type || dateRange.type === DateRange.LastMonth.type || dateRange.type === DateRange.Custom.type" @click="changeDateFilter(dateRange.type)">