From dea36d4b808312647e61ae98ddf5efe8aa2ff4c2 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sun, 30 Jul 2023 23:00:00 +0800 Subject: [PATCH] add trend in income and expense card in overview page --- pkg/api/transactions.go | 2 +- public/img/desktop/card-background.png | Bin 0 -> 6538 bytes public/img/desktop/document.svg | 7 + src/consts/datetime.js | 16 ++ src/desktop-main.js | 5 +- src/lib/datetime.js | 5 + src/lib/services.js | 22 +- src/locales/en.js | 1 + src/locales/zh_Hans.js | 1 + src/stores/overview.js | 74 ++++- src/views/desktop/HomePage.vue | 86 +++++- .../overview/MonthlyIncomeAndExpenseCard.vue | 258 ++++++++++++++++++ third-patry-dependencies.json | 5 + 13 files changed, 462 insertions(+), 20 deletions(-) create mode 100644 public/img/desktop/card-background.png create mode 100644 public/img/desktop/document.svg create mode 100644 src/views/desktop/overview/MonthlyIncomeAndExpenseCard.vue diff --git a/pkg/api/transactions.go b/pkg/api/transactions.go index 9ee2065b..73a9272b 100644 --- a/pkg/api/transactions.go +++ b/pkg/api/transactions.go @@ -290,7 +290,7 @@ func (a *TransactionsApi) TransactionAmountsHandler(c *core.Context) (interface{ return nil, errs.ErrQueryItemsEmpty } - if len(requestItems) > 5 { + if len(requestItems) > 10 { log.WarnfWithRequestId(c, "[transactions.TransactionAmountsHandler] parse request failed, because there are too many items") return nil, errs.ErrQueryItemsTooMuch } diff --git a/public/img/desktop/card-background.png b/public/img/desktop/card-background.png new file mode 100644 index 0000000000000000000000000000000000000000..cb321bf396cdd22ae7abc11906c8005045f8f35c GIT binary patch literal 6538 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 literal 0 HcmV?d00001 diff --git a/public/img/desktop/document.svg b/public/img/desktop/document.svg new file mode 100644 index 00000000..41ba961c --- /dev/null +++ b/public/img/desktop/document.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/consts/datetime.js b/src/consts/datetime.js index ff98acc4..0e28f4d1 100644 --- a/src/consts/datetime.js +++ b/src/consts/datetime.js @@ -1,3 +1,18 @@ +const allMonthsArray = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' +]; + const allWeekDays = { Sunday: { type: 0, @@ -190,6 +205,7 @@ const defaultDateTimeFormatValue = 0; export default { allWeekDays: allWeekDays, allWeekDaysArray: allWeekDaysArray, + allMonthsArray: allMonthsArray, allLongDateFormat: allLongDateFormat, allLongDateFormatArray: allLongDateFormatArray, allShortDateFormat: allShortDateFormat, diff --git a/src/desktop-main.js b/src/desktop-main.js index 4ac4b6ec..1603ce34 100644 --- a/src/desktop-main.js +++ b/src/desktop-main.js @@ -46,8 +46,9 @@ import 'vuetify/styles'; import * as echarts from 'echarts/core'; import { CanvasRenderer } from 'echarts/renderers'; -import { PieChart } from 'echarts/charts'; +import { BarChart, PieChart } from 'echarts/charts'; import { + GridComponent, TooltipComponent, LegendComponent, } from 'echarts/components'; @@ -363,7 +364,9 @@ const vuetify = createVuetify({ echarts.use([ CanvasRenderer, + BarChart, PieChart, + GridComponent, TooltipComponent, LegendComponent ]); diff --git a/src/lib/datetime.js b/src/lib/datetime.js index 02ee4194..c9f8ef5f 100644 --- a/src/lib/datetime.js +++ b/src/lib/datetime.js @@ -133,6 +133,11 @@ export function getDayOfWeekName(date) { return dateTimeConstants.allWeekDaysArray[dayOfWeek].name; } +export function getMonthName(date) { + const dayOfWeek = moment(date).month(); + return dateTimeConstants.allMonthsArray[dayOfWeek]; +} + export function getHour(date) { return moment(date).hour(); } diff --git a/src/lib/services.js b/src/lib/services.js index 3334c938..be202737 100644 --- a/src/lib/services.js +++ b/src/lib/services.js @@ -258,7 +258,7 @@ export default { return axios.get('v1/transactions/statistics.json' + (queryParams.length ? '?' + queryParams.join('&') : '')); }, - getTransactionAmounts: ({ today, thisWeek, thisMonth, thisYear }) => { + getTransactionAmounts: ({ today, thisWeek, thisMonth, thisYear, lastMonth, monthBeforeLastMonth, monthBeforeLast2Months, monthBeforeLast3Months, monthBeforeLast4Months }) => { const queryParams = []; if (today) { @@ -277,6 +277,26 @@ export default { queryParams.push(`thisYear_${thisYear.startTime}_${thisYear.endTime}`); } + if (lastMonth) { + queryParams.push(`lastMonth_${lastMonth.startTime}_${lastMonth.endTime}`); + } + + if (monthBeforeLastMonth) { + queryParams.push(`monthBeforeLastMonth_${monthBeforeLastMonth.startTime}_${monthBeforeLastMonth.endTime}`); + } + + if (monthBeforeLast2Months) { + queryParams.push(`monthBeforeLast2Months_${monthBeforeLast2Months.startTime}_${monthBeforeLast2Months.endTime}`); + } + + if (monthBeforeLast3Months) { + queryParams.push(`monthBeforeLast3Months_${monthBeforeLast3Months.startTime}_${monthBeforeLast3Months.endTime}`); + } + + if (monthBeforeLast4Months) { + queryParams.push(`monthBeforeLast4Months_${monthBeforeLast4Months.startTime}_${monthBeforeLast4Months.endTime}`); + } + return axios.get('v1/transactions/amounts.json' + (queryParams.length ? '?query=' + queryParams.join('|') : '')); }, getTransaction: ({ id }) => { diff --git a/src/locales/en.js b/src/locales/en.js index 97004aaa..9c51cf04 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -837,6 +837,7 @@ export default { 'PIN code is wrong': 'PIN code is wrong', 'Sign Up': 'Sign Up', 'Overview': 'Overview', + 'Trend in Income and Expense': 'Trend in Income and Expense', 'View Details': 'View Details', 'Transaction List': 'Transaction List', 'Account List': 'Account List', diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index 0ef5e399..a1747981 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -837,6 +837,7 @@ export default { 'PIN code is wrong': 'PIN码错误', 'Sign Up': '注册', 'Overview': '总览', + 'Trend in Income and Expense': '收入与支出趋势', 'View Details': '查看详情', 'Transaction List': '交易列表', 'Account List': '账户列表', diff --git a/src/stores/overview.js b/src/stores/overview.js index 2e4b7066..ddf6ae80 100644 --- a/src/stores/overview.js +++ b/src/stores/overview.js @@ -5,6 +5,7 @@ import { useExchangeRatesStore } from './exchangeRates.js'; import { isNumber, isEquals } from '@/lib/common.js'; import { + getUnixTimeBeforeUnixTime, getTodayFirstUnixTime, getTodayLastUnixTime, getThisWeekFirstUnixTime, @@ -31,6 +32,21 @@ function updateTransactionDateRange(state) { state.transactionDataRange.thisYear.startTime = getThisYearFirstUnixTime(); state.transactionDataRange.thisYear.endTime = getThisYearLastUnixTime(); + + state.transactionDataRange.lastMonth.startTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 1, 'months'); + state.transactionDataRange.lastMonth.endTime = getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 1, 'months'); + + state.transactionDataRange.monthBeforeLastMonth.startTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 2, 'months'); + state.transactionDataRange.monthBeforeLastMonth.endTime = getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 2, 'months'); + + state.transactionDataRange.monthBeforeLast2Months.startTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 3, 'months'); + state.transactionDataRange.monthBeforeLast2Months.endTime = getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 3, 'months'); + + state.transactionDataRange.monthBeforeLast3Months.startTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 4, 'months'); + state.transactionDataRange.monthBeforeLast3Months.endTime = getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 4, 'months'); + + state.transactionDataRange.monthBeforeLast4Months.startTime = getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 5, 'months'); + state.transactionDataRange.monthBeforeLast4Months.endTime = getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 5, 'months'); } export const useOverviewStore = defineStore('overview', { @@ -51,8 +67,31 @@ export const useOverviewStore = defineStore('overview', { thisYear: { startTime: getThisYearFirstUnixTime(), endTime: getThisYearLastUnixTime() + }, + lastMonth: { + startTime: getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 1, 'months'), + endTime: getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 1, 'months') + }, + monthBeforeLastMonth: { + startTime: getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 2, 'months'), + endTime: getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 2, 'months') + }, + monthBeforeLast2Months: { + startTime: getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 3, 'months'), + endTime: getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 3, 'months') + }, + monthBeforeLast3Months: { + startTime: getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 4, 'months'), + endTime: getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 4, 'months') + }, + monthBeforeLast4Months: { + startTime: getUnixTimeBeforeUnixTime(getThisMonthFirstUnixTime(), 5, 'months'), + endTime: getUnixTimeBeforeUnixTime(getThisMonthLastUnixTime(), 5, 'months') } }, + transactionOverviewOptions: { + loadLast5Months: false + }, transactionOverviewData: {}, transactionOverviewStateInvalid: true }), @@ -78,7 +117,7 @@ export const useOverviewStore = defineStore('overview', { const finalOverviewData = {}; const defaultCurrency = userStore.currentUserDefaultCurrency; - [ 'today', 'thisWeek', 'thisMonth', 'thisYear' ].forEach(field => { + [ 'today', 'thisWeek', 'thisMonth', 'thisYear', 'lastMonth', 'monthBeforeLastMonth', 'monthBeforeLast2Months', 'monthBeforeLast3Months', 'monthBeforeLast4Months' ].forEach(field => { if (!Object.prototype.hasOwnProperty.call(overviewData, field)) { return; } @@ -139,31 +178,47 @@ export const useOverviewStore = defineStore('overview', { }, resetTransactionOverview() { updateTransactionDateRange(this); + this.transactionOverviewOptions.loadLast5Months = false; this.transactionOverviewData = {}; this.transactionOverviewStateInvalid = true; }, - loadTransactionOverview({ force }) { + loadTransactionOverview({ force, loadLast5Months }) { const self = this; let dateChanged = false; + let rangeChanged = false; if (self.transactionDataRange.today.startTime !== getTodayFirstUnixTime()) { dateChanged = true; updateTransactionDateRange(self); } - if (!dateChanged && !force && !self.transactionOverviewStateInvalid) { + if (loadLast5Months && !self.transactionOverviewOptions.loadLast5Months) { + rangeChanged = true; + } + + if (!dateChanged && !rangeChanged && !force && !self.transactionOverviewStateInvalid) { return new Promise((resolve) => { resolve(self.transactionOverviewData); }); } + const requestParams = { + today: self.transactionDataRange.today, + thisWeek: self.transactionDataRange.thisWeek, + thisMonth: self.transactionDataRange.thisMonth, + thisYear: self.transactionDataRange.thisYear + }; + + if (loadLast5Months) { + requestParams.lastMonth = self.transactionDataRange.lastMonth; + requestParams.monthBeforeLastMonth = self.transactionDataRange.monthBeforeLastMonth; + requestParams.monthBeforeLast2Months = self.transactionDataRange.monthBeforeLast2Months; + requestParams.monthBeforeLast3Months = self.transactionDataRange.monthBeforeLast3Months; + requestParams.monthBeforeLast4Months = self.transactionDataRange.monthBeforeLast4Months; + } + return new Promise((resolve, reject) => { - services.getTransactionAmounts({ - today: self.transactionDataRange.today, - thisWeek: self.transactionDataRange.thisWeek, - thisMonth: self.transactionDataRange.thisMonth, - thisYear: self.transactionDataRange.thisYear - }).then(response => { + services.getTransactionAmounts(requestParams).then(response => { const data = response.data; if (!data || !data.success || !data.result) { @@ -181,6 +236,7 @@ export const useOverviewStore = defineStore('overview', { } self.transactionOverviewData = data.result; + self.transactionOverviewOptions.loadLast5Months = loadLast5Months; resolve(data.result); }).catch(error => { diff --git a/src/views/desktop/HomePage.vue b/src/views/desktop/HomePage.vue index 0776a9a1..03649e4f 100644 --- a/src/views/desktop/HomePage.vue +++ b/src/views/desktop/HomePage.vue @@ -4,9 +4,11 @@ + + + + + + diff --git a/src/views/desktop/overview/MonthlyIncomeAndExpenseCard.vue b/src/views/desktop/overview/MonthlyIncomeAndExpenseCard.vue new file mode 100644 index 00000000..4ffb7507 --- /dev/null +++ b/src/views/desktop/overview/MonthlyIncomeAndExpenseCard.vue @@ -0,0 +1,258 @@ + + + + + diff --git a/third-patry-dependencies.json b/third-patry-dependencies.json index 8f25f71a..d85733cb 100644 --- a/third-patry-dependencies.json +++ b/third-patry-dependencies.json @@ -270,6 +270,11 @@ "url": "https://materialdesignicons.com", "licenseUrl": "https://github.com/Templarian/MaterialDesign-JS/blob/v7.2.96/LICENSE" }, + { + "name": "Solar Icons Set", + "url": "https://www.figma.com/community/file/1166831539721848736/Solar-Icons-Set", + "licenseUrl": "https://creativecommons.org/licenses/by/4.0" + }, { "name": "Hand drawn minimal background", "url": "https://www.freepik.com/free-vector/hand-drawn-minimal-background_15441932.htm",