From acaad355ed31412345dce4dff75284043b2b11d4 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sat, 25 Jan 2025 23:02:40 +0800 Subject: [PATCH] migrate trends bar chart to composition API and typescript --- src/components/base/TrendsChartBase.ts | 64 ++ src/components/desktop/TrendsChart.vue | 725 +++++++++--------- src/components/mobile/TrendsBarChart.vue | 452 +++++------ src/lib/statistics.ts | 9 +- src/locales/helper.js | 14 - src/models/transaction.ts | 16 +- .../desktop/statistics/TransactionPage.vue | 2 + 7 files changed, 680 insertions(+), 602 deletions(-) create mode 100644 src/components/base/TrendsChartBase.ts diff --git a/src/components/base/TrendsChartBase.ts b/src/components/base/TrendsChartBase.ts new file mode 100644 index 00000000..80b7ddbb --- /dev/null +++ b/src/components/base/TrendsChartBase.ts @@ -0,0 +1,64 @@ +import { computed } from 'vue'; + +import { useI18n } from '@/locales/helpers.ts'; + +import type { + YearMonth, + TimeRangeAndDateType, + YearUnixTime, + YearQuarterUnixTime, + YearMonthUnixTime +} from '@/core/datetime.ts'; +import type { ColorValue } from '@/core/color.ts'; +import { DEFAULT_ICON_COLOR } from '@/consts/color.ts'; +import type { YearMonthItems } from '@/models/transaction.ts'; + +import { getAllDateRanges } from '@/lib/statistics.ts'; + +export interface CommonTrendsChartProps { + items: YearMonthItems[]; + startYearMonth: string; + endYearMonth: string; + sortingType: number; + dateAggregationType: number; + idField?: string; + nameField: string; + valueField: string; + colorField?: string; + hiddenField?: string; + displayOrdersField?: string; + translateName?: boolean; + defaultCurrency?: string; + enableClickItem?: boolean; +} + +export interface TrendsBarChartClickEvent { + itemId: string; + dateRange: TimeRangeAndDateType; +} + +export function useTrendsChartBase(props: CommonTrendsChartProps) { + const { tt } = useI18n(); + + const allDateRanges = computed(() => getAllDateRanges(props.items, props.startYearMonth, props.endYearMonth, props.dateAggregationType)); + + function getItemName(name: string): string { + return props.translateName ? tt(name) : name; + } + + function getColor(color: string): ColorValue { + if (color && color !== DEFAULT_ICON_COLOR) { + color = '#' + color; + } + + return color; + } + + return { + // computed states + allDateRanges, + // functions + getItemName, + getColor + } +} diff --git a/src/components/desktop/TrendsChart.vue b/src/components/desktop/TrendsChart.vue index 12f0f7a8..f6247d30 100644 --- a/src/components/desktop/TrendsChart.vue +++ b/src/components/desktop/TrendsChart.vue @@ -3,17 +3,24 @@ @click="clickItem" @legendselectchanged="onLegendSelectChanged" /> - diff --git a/src/components/mobile/TrendsBarChart.vue b/src/components/mobile/TrendsBarChart.vue index 86c9916a..b5aa2890 100644 --- a/src/components/mobile/TrendsBarChart.vue +++ b/src/components/mobile/TrendsBarChart.vue @@ -27,7 +27,7 @@ - + @@ -47,7 +47,6 @@ link="#" :key="idx" v-for="(item, idx) in allDisplayDataItems.data" - v-show="!item.hidden" @click="clickItem(item)" > - diff --git a/src/lib/statistics.ts b/src/lib/statistics.ts index 6cd7832c..09b0a18b 100644 --- a/src/lib/statistics.ts +++ b/src/lib/statistics.ts @@ -1,6 +1,9 @@ import type { YearMonth, YearUnixTime, YearQuarterUnixTime, YearMonthUnixTime } from '@/core/datetime.ts'; import { ChartSortingType, ChartDateAggregationType } from '@/core/statistics.ts'; -import type { TransactionStatisticDataItemBase } from '@/models/transaction.ts'; +import type { + YearMonthItems, + SortableTransactionStatisticDataItem +} from '@/models/transaction.ts'; import { getAllMonthsStartAndEndUnixTimes, @@ -8,7 +11,7 @@ import { getAllYearsStartAndEndUnixTimes } from '@/lib/datetime.ts'; -export function sortStatisticsItems(items: TransactionStatisticDataItemBase[], sortingType: number): void { +export function sortStatisticsItems(items: T[], sortingType: number): void { if (sortingType === ChartSortingType.DisplayOrder.type) { items.sort(function (data1, data2) { for (let i = 0; i < Math.min(data1.displayOrders.length, data2.displayOrders.length); i++) { @@ -43,7 +46,7 @@ export function sortStatisticsItems(items: TransactionStatisticDataItemBase[], s } } -export function getAllDateRanges(items: { items: YearMonth[] }[], startYearMonth: YearMonth | string, endYearMonth: YearMonth | string, dateAggregationType: number): YearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] { +export function getAllDateRanges(items: YearMonthItems[], startYearMonth: YearMonth | string, endYearMonth: YearMonth | string, dateAggregationType: number): YearUnixTime[] | YearQuarterUnixTime[] | YearMonthUnixTime[] { if ((!startYearMonth || !endYearMonth) && items && items.length) { let minYear = Number.MAX_SAFE_INTEGER, minMonth = Number.MAX_SAFE_INTEGER, maxYear = 0, maxMonth = 0; diff --git a/src/locales/helper.js b/src/locales/helper.js index 0b6a698f..c6424ded 100644 --- a/src/locales/helper.js +++ b/src/locales/helper.js @@ -195,17 +195,6 @@ function getI18nShortTimeFormat(translateFn, formatTypeValue) { return getDateTimeFormat(translateFn, ShortTimeFormat.all(), ShortTimeFormat.values(), 'format.shortTime', defaultShortTimeFormatTypeName, ShortTimeFormat.Default, formatTypeValue); } -function formatYearQuarter(translateFn, year, quarter) { - if (1 <= quarter && quarter <= 4) { - return translateFn('format.yearQuarter.q' + quarter, { - year: year, - quarter: quarter - }); - } else { - return ''; - } -} - function getDateTimeFormat(translateFn, allFormatMap, allFormatArray, localeFormatPathPrefix, localeDefaultFormatTypeName, systemDefaultFormatType, formatTypeValue) { const type = getDateTimeFormatType(allFormatMap, allFormatArray, formatTypeValue, localeDefaultFormatTypeName, systemDefaultFormatType); return translateFn(`${localeFormatPathPrefix}.${type.key}`); @@ -784,13 +773,10 @@ export function i18nFunctions(i18nGlobal) { formatUnixTimeToLongDateTime: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongDateFormat(i18nGlobal.t, userStore.currentUserLongDateFormat) + ' ' + getI18nLongTimeFormat(i18nGlobal.t, userStore.currentUserLongTimeFormat), utcOffset, currentUtcOffset), formatUnixTimeToLongDate: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongDateFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset), formatUnixTimeToLongYear: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongYearFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset), - formatUnixTimeToShortYear: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nShortYearFormat(i18nGlobal.t, userStore.currentUserShortDateFormat), utcOffset, currentUtcOffset), formatUnixTimeToLongYearMonth: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongYearMonthFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset), - formatUnixTimeToShortYearMonth: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nShortYearMonthFormat(i18nGlobal.t, userStore.currentUserShortDateFormat), utcOffset, currentUtcOffset), formatUnixTimeToLongMonthDay: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongMonthDayFormat(i18nGlobal.t, userStore.currentUserLongDateFormat), utcOffset, currentUtcOffset), formatUnixTimeToLongTime: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nLongTimeFormat(i18nGlobal.t, userStore.currentUserLongTimeFormat), utcOffset, currentUtcOffset), formatUnixTimeToShortTime: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nShortTimeFormat(i18nGlobal.t, userStore.currentUserShortTimeFormat), utcOffset, currentUtcOffset), - formatYearQuarter: (year, quarter) => formatYearQuarter(i18nGlobal.t, year, quarter), getAllTimezones: (includeSystemDefault) => getAllTimezones(includeSystemDefault, i18nGlobal.t), getTimezoneDifferenceDisplayText: (utcOffset) => getTimezoneDifferenceDisplayText(utcOffset, i18nGlobal.t), getAllDateRanges: (scene, includeCustom, includeBillingCycle) => getAllDateRanges(scene, includeCustom, includeBillingCycle, i18nGlobal.t), diff --git a/src/models/transaction.ts b/src/models/transaction.ts index b1e8d56b..d2e7dfe4 100644 --- a/src/models/transaction.ts +++ b/src/models/transaction.ts @@ -1,5 +1,5 @@ import type { PartialRecord } from '@/core/base.ts'; -import type { StartEndTime } from '@/core/datetime.ts'; +import type { YearMonth, StartEndTime } from '@/core/datetime.ts'; import type { AccountInfoResponse } from './account.ts'; import type { TransactionCategoryInfoResponse } from './transaction_category.ts'; @@ -256,9 +256,21 @@ export interface TransactionStatisticTrendsResponseItemWithInfo { readonly items: TransactionStatisticResponseItemWithInfo[]; } +export interface YearMonthDataItem extends YearMonth, Record {} + +export interface YearMonthItems extends Record { + readonly items: T[]; +} + +export interface SortableTransactionStatisticDataItem { + readonly name: string; + readonly displayOrders: number[]; + readonly totalAmount: number; +} + export type TransactionStatisticDataItemType = 'category' | 'account' | 'total'; -export interface TransactionStatisticDataItemBase { +export interface TransactionStatisticDataItemBase extends SortableTransactionStatisticDataItem { readonly name: string; readonly type: TransactionStatisticDataItemType; readonly id: string; diff --git a/src/views/desktop/statistics/TransactionPage.vue b/src/views/desktop/statistics/TransactionPage.vue index ea4b8f29..6908d634 100644 --- a/src/views/desktop/statistics/TransactionPage.vue +++ b/src/views/desktop/statistics/TransactionPage.vue @@ -245,6 +245,8 @@ :type="queryChartType" :start-year-month="query.trendChartStartYearMonth" :end-year-month="query.trendChartEndYearMonth" + :sorting-type="querySortingType" + :date-aggregation-type="trendDateAggregationType" :items="[]" :skeleton="true" id-field="id"