diff --git a/src/components/desktop/AccountAndCategorySankeyChart.vue b/src/components/desktop/AccountAndCategorySankeyChart.vue new file mode 100644 index 00000000..4c9d1426 --- /dev/null +++ b/src/components/desktop/AccountAndCategorySankeyChart.vue @@ -0,0 +1,520 @@ + + + + + diff --git a/src/components/desktop/PieChart.vue b/src/components/desktop/PieChart.vue index 361466fc..f740836b 100644 --- a/src/components/desktop/PieChart.vue +++ b/src/components/desktop/PieChart.vue @@ -261,7 +261,7 @@ function onLegendSelectChanged(e: { selected: Record }): void { @media (min-width: 600px) { .pie-chart-container { - height: 560px; + height: 610px; } } diff --git a/src/components/desktop/RadarChart.vue b/src/components/desktop/RadarChart.vue index 9bcc736a..288ff655 100644 --- a/src/components/desktop/RadarChart.vue +++ b/src/components/desktop/RadarChart.vue @@ -188,7 +188,7 @@ const chartOptions = computed(() => { @media (min-width: 600px) { .radar-chart-container { - height: 560px; + height: 610px; } } diff --git a/src/core/statistics.ts b/src/core/statistics.ts index fd9805b9..528fa109 100644 --- a/src/core/statistics.ts +++ b/src/core/statistics.ts @@ -89,35 +89,41 @@ export class AccountBalanceTrendChartType implements TypeAndName { } export class ChartDataType implements TypeAndName { - private static readonly allInstances: ChartDataType[] = []; + private static readonly allInstancesForAll: ChartDataType[] = []; + private static readonly allInstancesForDesktop: ChartDataType[] = []; private static readonly allInstancesByType: Record = {}; - public static readonly OutflowsByAccount = new ChartDataType(11, 'Outflows By Account', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly ExpenseByAccount = new ChartDataType(0, 'Expense By Account', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly ExpenseByPrimaryCategory = new ChartDataType(1, 'Expense By Primary Category', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly ExpenseBySecondaryCategory = new ChartDataType(2, 'Expense By Secondary Category', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly InflowsByAccount = new ChartDataType(12, 'Inflows By Account', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly IncomeByAccount = new ChartDataType(3, 'Income By Account', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly IncomeByPrimaryCategory = new ChartDataType(4, 'Income By Primary Category', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly IncomeBySecondaryCategory = new ChartDataType(5, 'Income By Secondary Category', StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); - public static readonly AccountTotalAssets = new ChartDataType(6, 'Account Total Assets', StatisticsAnalysisType.CategoricalAnalysis); - public static readonly AccountTotalLiabilities = new ChartDataType(7, 'Account Total Liabilities', StatisticsAnalysisType.CategoricalAnalysis); - public static readonly TotalOutflows = new ChartDataType(13, 'Total Outflows', StatisticsAnalysisType.TrendAnalysis); - public static readonly TotalExpense = new ChartDataType(8, 'Total Expense', StatisticsAnalysisType.TrendAnalysis); - public static readonly TotalInflows = new ChartDataType(14, 'Total Inflows', StatisticsAnalysisType.TrendAnalysis); - public static readonly TotalIncome = new ChartDataType(9, 'Total Income', StatisticsAnalysisType.TrendAnalysis); - public static readonly NetCashFlow = new ChartDataType(15, 'Net Cash Flow', StatisticsAnalysisType.TrendAnalysis); - public static readonly NetIncome = new ChartDataType(10, 'Net Income', StatisticsAnalysisType.TrendAnalysis); + public static readonly Overview = new ChartDataType(16, 'Overview', true, true, StatisticsAnalysisType.CategoricalAnalysis); + public static readonly OutflowsByAccount = new ChartDataType(11, 'Outflows By Account', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly ExpenseByAccount = new ChartDataType(0, 'Expense By Account', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly ExpenseByPrimaryCategory = new ChartDataType(1, 'Expense By Primary Category', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly ExpenseBySecondaryCategory = new ChartDataType(2, 'Expense By Secondary Category', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly InflowsByAccount = new ChartDataType(12, 'Inflows By Account', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly IncomeByAccount = new ChartDataType(3, 'Income By Account', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly IncomeByPrimaryCategory = new ChartDataType(4, 'Income By Primary Category', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly IncomeBySecondaryCategory = new ChartDataType(5, 'Income By Secondary Category', false, false, StatisticsAnalysisType.CategoricalAnalysis, StatisticsAnalysisType.TrendAnalysis); + public static readonly AccountTotalAssets = new ChartDataType(6, 'Account Total Assets', false, false, StatisticsAnalysisType.CategoricalAnalysis); + public static readonly AccountTotalLiabilities = new ChartDataType(7, 'Account Total Liabilities', false, false, StatisticsAnalysisType.CategoricalAnalysis); + public static readonly TotalOutflows = new ChartDataType(13, 'Total Outflows', false, false, StatisticsAnalysisType.TrendAnalysis); + public static readonly TotalExpense = new ChartDataType(8, 'Total Expense', false, false, StatisticsAnalysisType.TrendAnalysis); + public static readonly TotalInflows = new ChartDataType(14, 'Total Inflows', false, false, StatisticsAnalysisType.TrendAnalysis); + public static readonly TotalIncome = new ChartDataType(9, 'Total Income', false, false, StatisticsAnalysisType.TrendAnalysis); + public static readonly NetCashFlow = new ChartDataType(15, 'Net Cash Flow', false, false, StatisticsAnalysisType.TrendAnalysis); + public static readonly NetIncome = new ChartDataType(10, 'Net Income', false, false, StatisticsAnalysisType.TrendAnalysis); public static readonly Default = ChartDataType.ExpenseByPrimaryCategory; public readonly type: number; public readonly name: string; + public readonly desktopOnly: boolean = false; + public readonly specialChart: boolean = false; private readonly availableAnalysisTypes: Record; - private constructor(type: number, name: string, ...availableAnalysisTypes: StatisticsAnalysisType[]) { + private constructor(type: number, name: string, desktopOnly: boolean, specialChart: boolean, ...availableAnalysisTypes: StatisticsAnalysisType[]) { this.type = type; this.name = name; + this.desktopOnly = desktopOnly; + this.specialChart = specialChart; this.availableAnalysisTypes = {}; if (availableAnalysisTypes) { @@ -126,7 +132,11 @@ export class ChartDataType implements TypeAndName { } } - ChartDataType.allInstances.push(this); + if (!desktopOnly) { + ChartDataType.allInstancesForAll.push(this); + } + + ChartDataType.allInstancesForDesktop.push(this); ChartDataType.allInstancesByType[type] = this; } @@ -134,14 +144,16 @@ export class ChartDataType implements TypeAndName { return this.availableAnalysisTypes[analysisType] || false; } - public static values(analysisType?: StatisticsAnalysisType): ChartDataType[] { + public static values(analysisType?: StatisticsAnalysisType, withDesktopOnlyChart?: boolean): ChartDataType[] { + const availableInstances: ChartDataType[] = withDesktopOnlyChart ? ChartDataType.allInstancesForDesktop : ChartDataType.allInstancesForAll; + if (analysisType === undefined) { - return ChartDataType.allInstances; + return availableInstances; } const ret: ChartDataType[] = []; - for (const chartDataType of ChartDataType.allInstances) { + for (const chartDataType of availableInstances) { if (chartDataType.isAvailableAnalysisType(analysisType)) { ret.push(chartDataType); } diff --git a/src/desktop-main.ts b/src/desktop-main.ts index 2b6aff6c..73397bfa 100644 --- a/src/desktop-main.ts +++ b/src/desktop-main.ts @@ -52,7 +52,7 @@ import 'vuetify/styles'; import * as echarts from 'echarts/core'; import { CanvasRenderer } from 'echarts/renderers'; -import { LineChart, BarChart, PieChart, CandlestickChart, RadarChart } from 'echarts/charts'; +import { LineChart, BarChart, PieChart, CandlestickChart, RadarChart, SankeyChart } from 'echarts/charts'; import { GridComponent, TooltipComponent, @@ -105,6 +105,7 @@ import DateRangeSelectionDialog from '@/components/desktop/DateRangeSelectionDia import MonthSelectionDialog from '@/components/desktop/MonthSelectionDialog.vue'; import MonthRangeSelectionDialog from '@/components/desktop/MonthRangeSelectionDialog.vue'; import AccountBalanceTrendsChart from '@/components/desktop/AccountBalanceTrendsChart.vue'; +import AccountAndCategorySankeyChart from '@/components/desktop/AccountAndCategorySankeyChart.vue'; import SwitchToMobileDialog from '@/components/desktop/SwitchToMobileDialog.vue'; import '@/styles/desktop/template/vuetify/index.scss'; @@ -498,6 +499,7 @@ echarts.use([ PieChart, CandlestickChart, RadarChart, + SankeyChart, GridComponent, TooltipComponent, LegendComponent @@ -544,6 +546,7 @@ app.component('DateRangeSelectionDialog', DateRangeSelectionDialog); app.component('MonthSelectionDialog', MonthSelectionDialog); app.component('MonthRangeSelectionDialog', MonthRangeSelectionDialog); app.component('AccountBalanceTrendsChart', AccountBalanceTrendsChart); +app.component('AccountAndCategorySankeyChart', AccountAndCategorySankeyChart); app.component('SwitchToMobileDialog', SwitchToMobileDialog); app.mount('#app'); diff --git a/src/locales/de.json b/src/locales/de.json index 435eb86b..205024d4 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1517,6 +1517,7 @@ "Area Chart": "Flächendiagramm", "Column Chart": "Säulendiagramm", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Sortieren nach", "Map": "Karte", "Provider": "Anbieter", diff --git a/src/locales/en.json b/src/locales/en.json index 93477428..c48cee8b 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1517,6 +1517,7 @@ "Area Chart": "Area Chart", "Column Chart": "Column Chart", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Sort by", "Map": "Map", "Provider": "Provider", diff --git a/src/locales/es.json b/src/locales/es.json index 96f7b2b4..7214707f 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1517,6 +1517,7 @@ "Area Chart": "Gráfico de área", "Column Chart": "Gráfico de columnas", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Ordenar por", "Map": "Mapa", "Provider": "Proveedor", diff --git a/src/locales/fr.json b/src/locales/fr.json index f38dfd33..31d74ac2 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1517,6 +1517,7 @@ "Area Chart": "Graphique en aires", "Column Chart": "Graphique en colonnes", "Candlestick Chart": "Graphique en chandelier", + "Sankey Chart": "Sankey Chart", "Sort by": "Trier par", "Map": "Carte", "Provider": "Fournisseur", diff --git a/src/locales/helpers.ts b/src/locales/helpers.ts index 0aed63aa..f09fc200 100644 --- a/src/locales/helpers.ts +++ b/src/locales/helpers.ts @@ -2352,7 +2352,7 @@ export function useI18n() { getAllCategoricalChartTypes: (withDesktopOnlyChart?: boolean) => getLocalizedDisplayNameAndType(CategoricalChartType.values(!!withDesktopOnlyChart)), getAllTrendChartTypes: () => getLocalizedDisplayNameAndType(TrendChartType.values()), getAllAccountBalanceTrendChartTypes: () => getLocalizedDisplayNameAndType(AccountBalanceTrendChartType.values()), - getAllStatisticsChartDataTypes: (analysisType: StatisticsAnalysisType) => getLocalizedDisplayNameAndType(ChartDataType.values(analysisType)), + getAllStatisticsChartDataTypes: (analysisType: StatisticsAnalysisType, withDesktopOnlyChart?: boolean) => getLocalizedDisplayNameAndType(ChartDataType.values(analysisType, withDesktopOnlyChart)), getAllStatisticsSortingTypes: () => getLocalizedDisplayNameAndType(ChartSortingType.values()), getAllStatisticsDateAggregationTypes: () => getLocalizedChartDateAggregationTypeAndDisplayName(true), getAllStatisticsDateAggregationTypesWithShortName: () => getLocalizedChartDateAggregationTypeAndDisplayName(false), diff --git a/src/locales/it.json b/src/locales/it.json index 69b8e7d0..08a78d15 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -1517,6 +1517,7 @@ "Area Chart": "Grafico ad area", "Column Chart": "Grafico a colonne", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Ordina per", "Map": "Mappa", "Provider": "Fornitore", diff --git a/src/locales/ja.json b/src/locales/ja.json index 909997a8..715330ff 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1517,6 +1517,7 @@ "Area Chart": "エリアチャート", "Column Chart": "列チャート", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "ソート順", "Map": "地図", "Provider": "プロバイダー", diff --git a/src/locales/ko.json b/src/locales/ko.json index c921819b..6c0ff826 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1517,6 +1517,7 @@ "Area Chart": "영역 차트", "Column Chart": "세로 막대 차트", "Candlestick Chart": "캠들스틱 차트", + "Sankey Chart": "Sankey Chart", "Sort by": "정렬 기준", "Map": "지도", "Provider": "제공자", diff --git a/src/locales/nl.json b/src/locales/nl.json index df88f923..6c4edfc8 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -1517,6 +1517,7 @@ "Area Chart": "Vlakdiagram", "Column Chart": "Kolomdiagram", "Candlestick Chart": "Candlestickdiagram", + "Sankey Chart": "Sankey Chart", "Sort by": "Sorteren op", "Map": "Kaart", "Provider": "Provider", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index d1c8e18e..902ed89a 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -1517,6 +1517,7 @@ "Area Chart": "Gráfico de Área", "Column Chart": "Gráfico de Colunas", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Ordenar por", "Map": "Mapa", "Provider": "Provedor", diff --git a/src/locales/ru.json b/src/locales/ru.json index 029c5002..4ac3fb89 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1517,6 +1517,7 @@ "Area Chart": "Диаграмма с областями", "Column Chart": "Столбчатая диаграмма", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Сортировать по", "Map": "Карта", "Provider": "Провайдер", diff --git a/src/locales/th.json b/src/locales/th.json index 8d6667f6..de6ba3f1 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -1517,6 +1517,7 @@ "Area Chart": "กราฟพื้นที่", "Column Chart": "กราฟคอลัมน์", "Candlestick Chart": "กราฟแท่งเทียน", + "Sankey Chart": "Sankey Chart", "Sort by": "จัดเรียงตาม", "Map": "แผนที่", "Provider": "ผู้ให้บริการ", diff --git a/src/locales/uk.json b/src/locales/uk.json index b375b507..7ec00ae8 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -1517,6 +1517,7 @@ "Area Chart": "Діаграма з областями", "Column Chart": "Стовпчикова діаграма", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Сортувати за", "Map": "Карта", "Provider": "Провайдер", diff --git a/src/locales/vi.json b/src/locales/vi.json index 36a4d403..ee19b667 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -1517,6 +1517,7 @@ "Area Chart": "Biểu đồ diện tích", "Column Chart": "Biểu đồ cột", "Candlestick Chart": "Candlestick Chart", + "Sankey Chart": "Sankey Chart", "Sort by": "Sắp xếp theo", "Map": "Bản đồ", "Provider": "Nhà cung cấp", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 69238aa5..59c5fcc5 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -1517,6 +1517,7 @@ "Area Chart": "面积图", "Column Chart": "柱状图", "Candlestick Chart": "K线图", + "Sankey Chart": "桑基图", "Sort by": "排序方式", "Map": "地图", "Provider": "提供者", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index b696e262..a9728368 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -1517,6 +1517,7 @@ "Area Chart": "面積圖", "Column Chart": "柱狀圖", "Candlestick Chart": "K線圖", + "Sankey Chart": "桑基圖", "Sort by": "排序方式", "Map": "地圖", "Provider": "提供者", diff --git a/src/models/transaction.ts b/src/models/transaction.ts index 905856e3..8eb3ef83 100644 --- a/src/models/transaction.ts +++ b/src/models/transaction.ts @@ -722,6 +722,33 @@ export interface SortableTransactionStatisticDataItem { readonly totalAmount: number; } +export interface TransactionStatisticResponseItemWithInfo extends TransactionStatisticResponseItem { + categoryId: string; + accountId: string; + relatedAccountId?: string; + amount: number; + account?: Account; + primaryAccount?: Account; + relatedAccount?: Account; + relatedPrimaryAccount?: Account; + relatedAccountType?: number; + category?: TransactionCategory; + primaryCategory?: TransactionCategory; + amountInDefaultCurrency: number | null; +} + +export interface TransactionStatisticResponseWithInfo { + readonly startTime: number; + readonly endTime: number; + readonly items: TransactionStatisticResponseItemWithInfo[]; +} + +export interface TransactionStatisticTrendsResponseItemWithInfo { + readonly year: number; + readonly month: number; // 1-based (1 = January, 12 = December) + readonly items: TransactionStatisticResponseItemWithInfo[]; +} + export type TransactionStatisticDataItemType = 'category' | 'account' | 'total'; export interface TransactionStatisticDataItemBase extends SortableTransactionStatisticDataItem { diff --git a/src/stores/statistics.ts b/src/stores/statistics.ts index 39d7ab27..0cbed52b 100644 --- a/src/stores/statistics.ts +++ b/src/stores/statistics.ts @@ -28,12 +28,13 @@ import { import { DEFAULT_ACCOUNT_ICON, DEFAULT_CATEGORY_ICON } from '@/consts/icon.ts'; import { DEFAULT_ACCOUNT_COLOR, DEFAULT_CATEGORY_COLOR } from '@/consts/color.ts'; -import type { Account } from '@/models/account.ts'; -import type { TransactionCategory } from '@/models/transaction_category.ts'; import type { TransactionStatisticResponse, TransactionStatisticResponseItem, TransactionStatisticTrendsResponseItem, + TransactionStatisticResponseItemWithInfo, + TransactionStatisticResponseWithInfo, + TransactionStatisticTrendsResponseItemWithInfo, TransactionStatisticDataItemType, TransactionStatisticDataItemBase, TransactionCategoricalAnalysisData, @@ -61,33 +62,6 @@ import { sortStatisticsItems } from '@/lib/statistics.ts'; import logger from '@/lib/logger.ts'; import services from '@/lib/services.ts'; -interface TransactionStatisticResponseItemWithInfo extends TransactionStatisticResponseItem { - categoryId: string; - accountId: string; - relatedAccountId?: string; - amount: number; - account?: Account; - primaryAccount?: Account; - relatedAccount?: Account; - relatedPrimaryAccount?: Account; - relatedAccountType?: number; - category?: TransactionCategory; - primaryCategory?: TransactionCategory; - amountInDefaultCurrency: number | null; -} - -interface TransactionStatisticResponseWithInfo { - readonly startTime: number; - readonly endTime: number; - readonly items: TransactionStatisticResponseItemWithInfo[]; -} - -interface TransactionStatisticTrendsResponseItemWithInfo { - readonly year: number; - readonly month: number; // 1-based (1 = January, 12 = December) - readonly items: TransactionStatisticResponseItemWithInfo[]; -} - interface WritableTransactionCategoricalAnalysisData { totalAmount: number; totalNonNegativeAmount: number; @@ -229,6 +203,36 @@ export const useStatisticsStore = defineStore('statistics', () => { return getCategoryTotalAmountItems(transactionCategoryStatisticsDataWithCategoryAndAccountInfo.value.items, transactionStatisticsFilter.value); }); + const categoricalAllAnalysisData = computed(() => { + if (!transactionCategoryStatisticsDataWithCategoryAndAccountInfo.value || !transactionCategoryStatisticsDataWithCategoryAndAccountInfo.value.items) { + return null; + } + + const allDataItems: TransactionStatisticResponseItemWithInfo[] = []; + + for (const item of transactionCategoryStatisticsDataWithCategoryAndAccountInfo.value.items) { + if (!item.primaryAccount || !item.account || !item.primaryCategory || !item.category) { + continue; + } + + if (transactionStatisticsFilter.value.filterAccountIds && transactionStatisticsFilter.value.filterAccountIds[item.account.id]) { + continue; + } + + if (transactionStatisticsFilter.value.filterCategoryIds && transactionStatisticsFilter.value.filterCategoryIds[item.category.id]) { + continue; + } + + allDataItems.push(item); + } + + return { + startTime: transactionCategoryStatisticsDataWithCategoryAndAccountInfo.value.startTime, + endTime: transactionCategoryStatisticsDataWithCategoryAndAccountInfo.value.endTime, + items: allDataItems + }; + }); + const accountTotalAmountAnalysisData = computed(() => { if (!accountsStore.allPlainAccounts) { return null; @@ -1043,7 +1047,48 @@ export const useStatisticsStore = defineStore('statistics', () => { querys.push('type=3'); } - if (itemId && (transactionStatisticsFilter.value.chartDataType === ChartDataType.InflowsByAccount.type + if (itemId && transactionStatisticsFilter.value.chartDataType === ChartDataType.Overview.type) { + const items = itemId.split('-'); + const sourceItems = (items[0] || '').split(':'); + const queryAccountIds: string[] = []; + const queryCategoryIds: string[] = []; + + if (sourceItems.length === 2) { + if (sourceItems[0] === 'account') { + queryAccountIds.push(sourceItems[1] as string); + } else if (sourceItems[0] === 'category') { + queryCategoryIds.push(sourceItems[1] as string); + } + } + + if (items.length === 2) { + const targetItems = (items[1] || '').split(':'); + + if (targetItems.length === 2) { + if (targetItems[0] === 'account') { + queryAccountIds.push(targetItems[1] as string); + } else if (targetItems[0] === 'category') { + queryCategoryIds.push(targetItems[1] as string); + } + } + } + + if (queryAccountIds.length) { + if (queryAccountIds.length === 2) { + querys.push('type=4'); + } + + querys.push('accountIds=' + queryAccountIds.join(',')); + } else { + querys.push('accountIds=' + getFinalAccountIdsByFilteredAccountIds(accountsStore.allAccountsMap, transactionStatisticsFilter.value.filterAccountIds)); + } + + if (queryCategoryIds.length) { + querys.push('categoryIds=' + queryCategoryIds.join(',')); + } else { + querys.push('categoryIds=' + getFinalCategoryIdsByFilteredCategoryIds(transactionCategoriesStore.allTransactionCategoriesMap, transactionStatisticsFilter.value.filterCategoryIds)); + } + } else if (itemId && (transactionStatisticsFilter.value.chartDataType === ChartDataType.InflowsByAccount.type || transactionStatisticsFilter.value.chartDataType === ChartDataType.IncomeByAccount.type || transactionStatisticsFilter.value.chartDataType === ChartDataType.OutflowsByAccount.type || transactionStatisticsFilter.value.chartDataType === ChartDataType.ExpenseByAccount.type @@ -1197,6 +1242,7 @@ export const useStatisticsStore = defineStore('statistics', () => { transactionStatisticsStateInvalid, // computed states categoricalAnalysisChartDataCategory, + categoricalAllAnalysisData, categoricalAnalysisData, trendsAnalysisData, // functions diff --git a/src/views/base/statistics/StatisticsTransactionPageBase.ts b/src/views/base/statistics/StatisticsTransactionPageBase.ts index c1f1bf4c..7b8c7f45 100644 --- a/src/views/base/statistics/StatisticsTransactionPageBase.ts +++ b/src/views/base/statistics/StatisticsTransactionPageBase.ts @@ -14,6 +14,7 @@ import { StatisticsAnalysisType, ChartDataType, ChartSortingType, ChartDateAggre import { DISPLAY_HIDDEN_AMOUNT } from '@/consts/numeral.ts'; import type { + TransactionStatisticResponseWithInfo, TransactionCategoricalAnalysisData, TransactionCategoricalAnalysisDataItem, TransactionTrendsAnalysisData @@ -230,6 +231,7 @@ export function useStatisticsTransactionPageBase() { }); const categoricalAnalysisData = computed(() => statisticsStore.categoricalAnalysisData); + const categoricalAllAnalysisData = computed(() => statisticsStore.categoricalAllAnalysisData); const trendsAnalysisData = computed(() => statisticsStore.trendsAnalysisData); function canShowCustomDateRange(dateRangeType: number): boolean { @@ -301,6 +303,7 @@ export function useStatisticsTransactionPageBase() { showTotalAmountInTrendsChart, translateNameInTrendsChart, categoricalAnalysisData, + categoricalAllAnalysisData, trendsAnalysisData, // functions canShowCustomDateRange, diff --git a/src/views/desktop/statistics/TransactionPage.vue b/src/views/desktop/statistics/TransactionPage.vue index 27c0c2a6..44d8364b 100644 --- a/src/views/desktop/statistics/TransactionPage.vue +++ b/src/views/desktop/statistics/TransactionPage.vue @@ -21,6 +21,17 @@ :disabled="loading" :items="allChartTypes" v-model="queryChartType" + v-show="!isQuerySpecialChartType" + /> +
@@ -38,7 +49,7 @@ {{ tt(dataType.name) }} {{ tt(dataType.name) }} @@ -48,7 +59,7 @@ - +