From a219444953f2a2b08ae7893694947d3f1d843fcb Mon Sep 17 00:00:00 2001 From: MaysWind Date: Mon, 10 Jun 2024 23:26:16 +0800 Subject: [PATCH] trends analysis supports total expense / total income / total balance --- src/components/desktop/TrendsChart.vue | 16 +++-- src/consts/statistics.js | 21 +++++++ src/locales/en.js | 1 + src/locales/zh_Hans.js | 1 + src/stores/statistics.js | 59 +++++++++++++++++-- .../desktop/statistics/TransactionPage.vue | 18 +++++- 6 files changed, 104 insertions(+), 12 deletions(-) diff --git a/src/components/desktop/TrendsChart.vue b/src/components/desktop/TrendsChart.vue index 1fce382b..1ac27936 100644 --- a/src/components/desktop/TrendsChart.vue +++ b/src/components/desktop/TrendsChart.vue @@ -30,6 +30,7 @@ export default { 'valueField', 'colorField', 'hiddenField', + 'translateName', 'defaultCurrency', 'showValue', 'showTotalAmountInTooltip', @@ -58,7 +59,7 @@ export default { if (this.idField && item[this.idField]) { id = item[this.idField]; } else { - id = item[this.nameField]; + id = this.getItemName(item[this.nameField]); } map[id] = item; @@ -136,8 +137,8 @@ export default { } const finalItem = { - id: (this.idField && item[this.idField]) ? item[this.idField] : item[this.nameField], - name: (this.idField && item[this.idField]) ? item[this.idField] : item[this.nameField], + id: (this.idField && item[this.idField]) ? item[this.idField] : this.getItemName(item[this.nameField]), + name: (this.idField && item[this.idField]) ? item[this.idField] : this.getItemName(item[this.nameField]), itemStyle: { color: this.getColor(item[this.colorField] ? item[this.colorField] : colorConstants.defaultChartColors[i % colorConstants.defaultChartColors.length]), }, @@ -225,9 +226,9 @@ export default { for (let i = 0; i < params.length; i++) { const id = params[i].seriesId; - const name = self.itemsMap[id] && self.nameField && self.itemsMap[id][self.nameField] ? self.itemsMap[id][self.nameField] : id; + const name = self.itemsMap[id] && self.nameField && self.itemsMap[id][self.nameField] ? self.getItemName(self.itemsMap[id][self.nameField]) : id; - if (params[i].data !== 0) { + if (params.length === 1 || params[i].data !== 0) { const value = self.getDisplayCurrency(params[i].data, self.defaultCurrency); tooltip += '
'; tooltip += `${name}${value}
`; @@ -259,7 +260,7 @@ export default { color: self.isDarkMode ? '#eee' : '#333' }, formatter: id => { - return self.itemsMap[id] && self.nameField && self.itemsMap[id][self.nameField] ? self.itemsMap[id][self.nameField] : id; + return self.itemsMap[id] && self.nameField && self.itemsMap[id][self.nameField] ? self.getItemName(self.itemsMap[id][self.nameField]) : id; } }, grid: { @@ -322,6 +323,9 @@ export default { return color; }, + getItemName(name) { + return this.translateName ? this.$t(name) : name; + }, onLegendSelectChanged: function (e) { this.selectedLegends = e.selected; }, diff --git a/src/consts/statistics.js b/src/consts/statistics.js index 4dcf5d27..7655d52b 100644 --- a/src/consts/statistics.js +++ b/src/consts/statistics.js @@ -103,6 +103,27 @@ const allChartDataTypes = { availableAnalysisTypes: { [allAnalysisTypes.CategoricalAnalysis]: true } + }, + TotalExpense: { + type: 8, + name: 'Total Expense', + availableAnalysisTypes: { + [allAnalysisTypes.TrendAnalysis]: true + } + }, + TotalIncome: { + type: 9, + name: 'Total Income', + availableAnalysisTypes: { + [allAnalysisTypes.TrendAnalysis]: true + } + }, + TotalBalance: { + type: 10, + name: 'Total Balance', + availableAnalysisTypes: { + [allAnalysisTypes.TrendAnalysis]: true + } } }; diff --git a/src/locales/en.js b/src/locales/en.js index ee0d7cd2..4e45e9d4 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -1009,6 +1009,7 @@ export default { 'Total Liabilities': 'Total Liabilities', 'Total Expense': 'Total Expense', 'Total Income': 'Total Income', + 'Total Balance': 'Total Balance', 'Expense By Account': 'Expense By Account', 'Expense By Primary Category': 'Expense By Primary Category', 'Expense By Secondary Category': 'Expense By Secondary Category', diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index f9b52ce9..591d814d 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -1009,6 +1009,7 @@ export default { 'Total Liabilities': '总负债', 'Total Expense': '总支出', 'Total Income': '总收入', + 'Total Balance': '总结余', 'Expense By Account': '账户支出', 'Expense By Primary Category': '一级分类支出', 'Expense By Secondary Category': '二级分类支出', diff --git a/src/stores/statistics.js b/src/stores/statistics.js index 1d2c7d34..065708f9 100644 --- a/src/stores/statistics.js +++ b/src/stores/statistics.js @@ -88,16 +88,20 @@ function getCategoryTotalAmountItems(items, transactionStatisticsFilter) { if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type || transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type || - transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type) { + transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type || + transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) { if (item.category.type !== categoryConstants.allCategoryTypes.Expense) { continue; } } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type || transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type || - transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) { + transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type || + transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) { if (item.category.type !== categoryConstants.allCategoryTypes.Income) { continue; } + } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) { + // Do Nothing } else { continue; } @@ -194,6 +198,51 @@ function getCategoryTotalAmountItems(items, transactionStatisticsFilter) { allDataItems[item.category.id] = data; } + } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type || + transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type || + transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) { + if (isNumber(item.amountInDefaultCurrency)) { + let data = allDataItems['total']; + let amount = item.amountInDefaultCurrency; + + if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type && + item.category.type === categoryConstants.allCategoryTypes.Expense) { + amount = -amount; + } + + if (data) { + data.totalAmount += amount; + } else { + let name = ''; + + if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) { + name = statisticsConstants.allChartDataTypes.TotalExpense.name; + } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) { + name = statisticsConstants.allChartDataTypes.TotalIncome.name; + } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) { + name = statisticsConstants.allChartDataTypes.TotalBalance.name; + } + + data = { + name: name, + type: 'total', + id: 'total', + icon: '', + color: '', + hidden: false, + displayOrders: [1], + totalAmount: amount + } + } + + totalAmount += amount; + + if (item.amountInDefaultCurrency > 0) { + totalNonNegativeAmount += amount; + } + + allDataItems['total'] = data; + } } } @@ -719,11 +768,13 @@ export const useStatisticsStore = defineStore('statistics', { if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type - || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) { + || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type + || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) { querys.push('type=2'); } else if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type - || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type) { + || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type + || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) { querys.push('type=3'); } diff --git a/src/views/desktop/statistics/TransactionPage.vue b/src/views/desktop/statistics/TransactionPage.vue index 69217c81..1d6aee8b 100644 --- a/src/views/desktop/statistics/TransactionPage.vue +++ b/src/views/desktop/statistics/TransactionPage.vue @@ -239,10 +239,11 @@ :start-year-month="query.trendChartStartYearMonth" :end-year-month="query.trendChartEndYearMonth" :items="trendsAnalysisData && trendsAnalysisData.items && trendsAnalysisData.items.length ? trendsAnalysisData.items : []" + :translate-name="translateNameInTrendsChart" :show-value="showAmountInChart" :enable-click-item="true" :default-currency="defaultCurrency" - :show-total-amount-in-tooltip="true" + :show-total-amount-in-tooltip="showTotalAmountInTrendsChart" id-field="id" name-field="name" value-field="totalAmount" @@ -480,6 +481,16 @@ export default { trendsAnalysisData() { return this.statisticsStore.trendsAnalysisData; }, + translateNameInTrendsChart() { + return this.query.chartDataType === this.allChartDataTypes.TotalExpense.type || + this.query.chartDataType === this.allChartDataTypes.TotalIncome.type || + this.query.chartDataType === this.allChartDataTypes.TotalBalance.type; + }, + showTotalAmountInTrendsChart() { + return this.query.chartDataType !== this.allChartDataTypes.TotalExpense.type && + this.query.chartDataType !== this.allChartDataTypes.TotalIncome.type && + this.query.chartDataType !== this.allChartDataTypes.TotalBalance.type; + }, statisticsTextColor() { if (this.query.chartDataType === this.allChartDataTypes.ExpenseByAccount.type || this.query.chartDataType === this.allChartDataTypes.ExpenseByPrimaryCategory.type || @@ -584,7 +595,10 @@ export default { self.query.chartDataType === self.allChartDataTypes.ExpenseBySecondaryCategory.type || self.query.chartDataType === self.allChartDataTypes.IncomeByAccount.type || self.query.chartDataType === self.allChartDataTypes.IncomeByPrimaryCategory.type || - self.query.chartDataType === self.allChartDataTypes.IncomeBySecondaryCategory.type) { + self.query.chartDataType === self.allChartDataTypes.IncomeBySecondaryCategory.type || + self.query.chartDataType === self.allChartDataTypes.TotalExpense.type || + self.query.chartDataType === self.allChartDataTypes.TotalIncome.type || + self.query.chartDataType === self.allChartDataTypes.TotalBalance.type) { if (this.analysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis) { dispatchPromise = self.statisticsStore.loadCategoricalAnalysis({ force: force