trend analysis supports aggregating amounts by month / quarter / year
This commit is contained in:
@@ -11,11 +11,17 @@ import { useSettingsStore } from '@/stores/setting.js';
|
||||
import { useUserStore } from '@/stores/user.js';
|
||||
|
||||
import colorConstants from '@/consts/color.js';
|
||||
import datetimeConstants from '@/consts/datetime.js';
|
||||
import statisticsConstants from '@/consts/statistics.js';
|
||||
import { isNumber } from '@/lib/common.js';
|
||||
import {
|
||||
getYearMonthStringFromObject,
|
||||
getAllYearMonthUnixTimesBetweenStartYearMonthAndEndYearMonth
|
||||
isArray,
|
||||
isNumber
|
||||
} from '@/lib/common.js';
|
||||
import {
|
||||
getAllYearsStartAndEndUnixTimes,
|
||||
getAllQuartersStartAndEndUnixTimes,
|
||||
getAllMonthsStartAndEndUnixTimes,
|
||||
getDateTypeByDateRange
|
||||
} from '@/lib/datetime.js';
|
||||
import {
|
||||
sortStatisticsItems
|
||||
@@ -29,6 +35,7 @@ export default {
|
||||
'startYearMonth',
|
||||
'endYearMonth',
|
||||
'sortingType',
|
||||
'dateAggregationType',
|
||||
'idField',
|
||||
'nameField',
|
||||
'valueField',
|
||||
@@ -67,15 +74,21 @@ export default {
|
||||
id = this.getItemName(item[this.nameField]);
|
||||
}
|
||||
|
||||
map[id] = item;
|
||||
map[id] = {
|
||||
[this.idField || 'id']: id,
|
||||
[this.nameField || 'name']: item[this.nameField],
|
||||
[this.hiddenField || 'hidden']: item[this.hiddenField],
|
||||
[this.displayOrdersField || 'displayOrders']: item[this.displayOrdersField]
|
||||
};
|
||||
}
|
||||
|
||||
return map;
|
||||
},
|
||||
allYearMonthTimes: function () {
|
||||
if (this.startYearMonth && this.endYearMonth) {
|
||||
return getAllYearMonthUnixTimesBetweenStartYearMonthAndEndYearMonth(this.startYearMonth, this.endYearMonth);
|
||||
} else if (this.items && this.items.length) {
|
||||
allDateRanges: function () {
|
||||
let startYearMonth = this.startYearMonth;
|
||||
let endYearMonth = this.endYearMonth;
|
||||
|
||||
if ((!this.startYearMonth || !this.endYearMonth) && this.items && this.items.length) {
|
||||
let minYear = Number.MAX_SAFE_INTEGER, minMonth = Number.MAX_SAFE_INTEGER, maxYear = 0, maxMonth = 0;
|
||||
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
@@ -96,20 +109,37 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
return getAllYearMonthUnixTimesBetweenStartYearMonthAndEndYearMonth(`${minYear}-${minMonth}`, `${maxYear}-${maxMonth}`);
|
||||
startYearMonth = `${minYear}-${minMonth}`;
|
||||
endYearMonth = `${maxYear}-${maxMonth}`;
|
||||
}
|
||||
|
||||
return [];
|
||||
if (!startYearMonth || !endYearMonth) {
|
||||
return [];
|
||||
}
|
||||
if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Year.type) {
|
||||
return getAllYearsStartAndEndUnixTimes(startYearMonth, endYearMonth);
|
||||
} else if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Quarter.type) {
|
||||
return getAllQuartersStartAndEndUnixTimes(startYearMonth, endYearMonth);
|
||||
} else { // if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Month.type) {
|
||||
return getAllMonthsStartAndEndUnixTimes(startYearMonth, endYearMonth);
|
||||
}
|
||||
},
|
||||
allDisplayMonths: function () {
|
||||
const allDisplayMonths = [];
|
||||
allDisplayDateRanges: function () {
|
||||
const allDisplayDateRanges = [];
|
||||
|
||||
for (let i = 0; i < this.allYearMonthTimes.length; i++) {
|
||||
const yearMonthTime = this.allYearMonthTimes[i];
|
||||
allDisplayMonths.push(this.$locale.formatUnixTimeToShortYearMonth(this.userStore, yearMonthTime.minUnixTime));
|
||||
for (let i = 0; i < this.allDateRanges.length; i++) {
|
||||
const dateRange = this.allDateRanges[i];
|
||||
|
||||
if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Year.type) {
|
||||
allDisplayDateRanges.push(this.$locale.formatUnixTimeToShortYear(this.userStore, dateRange.minUnixTime));
|
||||
} else if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Quarter.type) {
|
||||
allDisplayDateRanges.push(this.$locale.formatYearQuarter(dateRange.year, dateRange.quarter));
|
||||
} else { // if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Month.type) {
|
||||
allDisplayDateRanges.push(this.$locale.formatUnixTimeToShortYearMonth(this.userStore, dateRange.minUnixTime));
|
||||
}
|
||||
}
|
||||
|
||||
return allDisplayMonths;
|
||||
return allDisplayDateRanges;
|
||||
},
|
||||
allSeries: function () {
|
||||
const allSeries = [];
|
||||
@@ -122,20 +152,49 @@ export default {
|
||||
}
|
||||
|
||||
const allAmounts = [];
|
||||
const yearMonthDataMap = {};
|
||||
const dateRangeAmountMap = {};
|
||||
|
||||
for (let j = 0; j < item.items.length; j++) {
|
||||
const dataItem = item.items[j];
|
||||
yearMonthDataMap[`${dataItem.year}-${dataItem.month}`] = dataItem;
|
||||
let dateRangeKey = '';
|
||||
|
||||
if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Year.type) {
|
||||
dateRangeKey = dataItem.year;
|
||||
} else if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Quarter.type) {
|
||||
dateRangeKey = `${dataItem.year}-${Math.floor((dataItem.month - 1) / 3) + 1}`;
|
||||
} else { // if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Month.type) {
|
||||
dateRangeKey = `${dataItem.year}-${dataItem.month}`;
|
||||
}
|
||||
|
||||
const dataItems = dateRangeAmountMap[dateRangeKey] || [];
|
||||
dataItems.push(dataItem);
|
||||
|
||||
dateRangeAmountMap[dateRangeKey] = dataItems;
|
||||
}
|
||||
|
||||
for (let j = 0; j < this.allYearMonthTimes.length; j++) {
|
||||
const yearMonth = getYearMonthStringFromObject(this.allYearMonthTimes[j]);
|
||||
const dataItem = yearMonthDataMap[yearMonth];
|
||||
let amount = 0;
|
||||
for (let j = 0; j < this.allDateRanges.length; j++) {
|
||||
const dateRange = this.allDateRanges[j];
|
||||
let dateRangeKey = '';
|
||||
|
||||
if (dataItem && isNumber(dataItem[this.valueField])) {
|
||||
amount = dataItem[this.valueField];
|
||||
if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Year.type) {
|
||||
dateRangeKey = dateRange.year;
|
||||
} else if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Quarter.type) {
|
||||
dateRangeKey = `${dateRange.year}-${dateRange.quarter}`;
|
||||
} else { // if (this.dateAggregationType === statisticsConstants.allDateAggregationTypes.Month.type) {
|
||||
dateRangeKey = `${dateRange.year}-${dateRange.month + 1}`;
|
||||
}
|
||||
|
||||
let amount = 0;
|
||||
const dataItems = dateRangeAmountMap[dateRangeKey];
|
||||
|
||||
if (isArray(dataItems)) {
|
||||
for (let i = 0; i < dataItems.length; i++) {
|
||||
const dataItem = dataItems[i];
|
||||
|
||||
if (isNumber(dataItem[this.valueField])) {
|
||||
amount += dataItem[this.valueField];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allAmounts.push(amount);
|
||||
@@ -293,7 +352,7 @@ export default {
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: self.allDisplayMonths
|
||||
data: self.allDisplayDateRanges
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
@@ -332,11 +391,19 @@ export default {
|
||||
|
||||
const id = e.seriesId;
|
||||
const item = this.itemsMap[id];
|
||||
const yearMonthTime = this.allYearMonthTimes[e.dataIndex];
|
||||
const itemId = this.idField ? item[this.idField] : '';
|
||||
const dateRange = this.allDateRanges[e.dataIndex];
|
||||
const minUnixTime = dateRange.minUnixTime;
|
||||
const maxUnixTime = dateRange.maxUnixTime;
|
||||
const dateRangeType = getDateTypeByDateRange(minUnixTime, maxUnixTime, this.userStore.currentUserFirstDayOfWeek, datetimeConstants.allDateRangeScenes.Normal);
|
||||
|
||||
this.$emit('click', {
|
||||
yearMonth: getYearMonthStringFromObject(yearMonthTime),
|
||||
item: item
|
||||
itemId: itemId,
|
||||
dateRange: {
|
||||
minTime: minUnixTime,
|
||||
maxTime: maxUnixTime,
|
||||
type: dateRangeType
|
||||
}
|
||||
});
|
||||
},
|
||||
getColor: function (color) {
|
||||
|
||||
@@ -169,6 +169,29 @@ const allSortingTypesArray = [
|
||||
|
||||
const defaultSortingType = allSortingTypes.Amount.type;
|
||||
|
||||
const allDateAggregationTypes = {
|
||||
Month: {
|
||||
type: 0,
|
||||
name: 'Aggregate by Month'
|
||||
},
|
||||
Quarter: {
|
||||
type: 1,
|
||||
name: 'Aggregate by Quarter'
|
||||
},
|
||||
Year: {
|
||||
type: 2,
|
||||
name: 'Aggregate by Year'
|
||||
}
|
||||
};
|
||||
|
||||
const allDateAggregationTypesArray = [
|
||||
allDateAggregationTypes.Month,
|
||||
allDateAggregationTypes.Quarter,
|
||||
allDateAggregationTypes.Year
|
||||
]
|
||||
|
||||
const defaultDateAggregationType = allDateAggregationTypes.Month.type;
|
||||
|
||||
export default {
|
||||
allAnalysisTypes: allAnalysisTypes,
|
||||
allCategoricalChartTypes: allCategoricalChartTypes,
|
||||
@@ -185,4 +208,7 @@ export default {
|
||||
allSortingTypes: allSortingTypes,
|
||||
allSortingTypesArray: allSortingTypesArray,
|
||||
defaultSortingType: defaultSortingType,
|
||||
allDateAggregationTypes: allDateAggregationTypes,
|
||||
allDateAggregationTypesArray: allDateAggregationTypesArray,
|
||||
defaultDateAggregationType: defaultDateAggregationType,
|
||||
};
|
||||
|
||||
+79
-1
@@ -283,6 +283,22 @@ export function getSpecifiedDayFirstUnixTime(unixTime) {
|
||||
return moment.unix(unixTime).set({ hour: 0, minute: 0, second: 0, millisecond: 0 }).unix();
|
||||
}
|
||||
|
||||
export function getYearFirstUnixTime(year) {
|
||||
return moment().set({ year: year, month: 0, date: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }).unix();
|
||||
}
|
||||
|
||||
export function getYearLastUnixTime(year) {
|
||||
return moment.unix(getYearFirstUnixTime(year)).add(1, 'years').subtract(1, 'seconds').unix();
|
||||
}
|
||||
|
||||
export function getQuarterFirstUnixTime(yearQuarter) {
|
||||
return moment().set({ year: yearQuarter.year, month: (yearQuarter.quarter - 1) * 3, date: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }).unix();
|
||||
}
|
||||
|
||||
export function getQuarterLastUnixTime(yearQuarter) {
|
||||
return moment.unix(getQuarterFirstUnixTime(yearQuarter)).add(3, 'months').subtract(1, 'seconds').unix();
|
||||
}
|
||||
|
||||
export function getYearMonthFirstUnixTime(yearMonth) {
|
||||
if (isString(yearMonth)) {
|
||||
yearMonth = getYearMonthObjectFromString(yearMonth);
|
||||
@@ -301,7 +317,69 @@ export function getYearMonthLastUnixTime(yearMonth) {
|
||||
return moment.unix(getYearMonthFirstUnixTime(yearMonth)).add(1, 'months').subtract(1, 'seconds').unix();
|
||||
}
|
||||
|
||||
export function getAllYearMonthUnixTimesBetweenStartYearMonthAndEndYearMonth(startYearMonth, endYearMonth) {
|
||||
export function getAllYearsStartAndEndUnixTimes(startYearMonth, endYearMonth) {
|
||||
if (isString(startYearMonth)) {
|
||||
startYearMonth = getYearMonthObjectFromString(startYearMonth);
|
||||
}
|
||||
|
||||
if (isString(endYearMonth)) {
|
||||
endYearMonth = getYearMonthObjectFromString(endYearMonth);
|
||||
}
|
||||
|
||||
const allYearTimes = [];
|
||||
|
||||
for (let year = startYearMonth.year; year <= endYearMonth.year; year++) {
|
||||
const yearTime = {
|
||||
year: year
|
||||
};
|
||||
|
||||
yearTime.minUnixTime = getYearFirstUnixTime(year);
|
||||
yearTime.maxUnixTime = getYearLastUnixTime(year);
|
||||
|
||||
allYearTimes.push(yearTime);
|
||||
}
|
||||
|
||||
return allYearTimes;
|
||||
}
|
||||
|
||||
export function getAllQuartersStartAndEndUnixTimes(startYearMonth, endYearMonth) {
|
||||
if (isString(startYearMonth)) {
|
||||
startYearMonth = getYearMonthObjectFromString(startYearMonth);
|
||||
}
|
||||
|
||||
if (isString(endYearMonth)) {
|
||||
endYearMonth = getYearMonthObjectFromString(endYearMonth);
|
||||
}
|
||||
|
||||
const allYearQuarterTimes = [];
|
||||
|
||||
for (let year = startYearMonth.year, month = startYearMonth.month; year < endYearMonth.year || (year === endYearMonth.year && ((month / 3) <= (endYearMonth.month / 3))); ) {
|
||||
const yearQuarterTime = {
|
||||
year: year,
|
||||
quarter: Math.floor((month / 3)) + 1
|
||||
};
|
||||
|
||||
yearQuarterTime.minUnixTime = getQuarterFirstUnixTime(yearQuarterTime);
|
||||
yearQuarterTime.maxUnixTime = getQuarterLastUnixTime(yearQuarterTime);
|
||||
|
||||
allYearQuarterTimes.push(yearQuarterTime);
|
||||
|
||||
if (year === endYearMonth.year && month >= endYearMonth.month) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (month >= 9) {
|
||||
year++;
|
||||
month = 0;
|
||||
} else {
|
||||
month += 3;
|
||||
}
|
||||
}
|
||||
|
||||
return allYearQuarterTimes;
|
||||
}
|
||||
|
||||
export function getAllMonthsStartAndEndUnixTimes(startYearMonth, endYearMonth) {
|
||||
if (isString(startYearMonth)) {
|
||||
startYearMonth = getYearMonthObjectFromString(startYearMonth);
|
||||
}
|
||||
|
||||
@@ -451,6 +451,17 @@ function getI18nShortTimeFormat(translateFn, formatTypeValue) {
|
||||
return getDateTimeFormat(translateFn, datetimeConstants.allShortTimeFormat, datetimeConstants.allShortTimeFormatArray, 'format.shortTime', defaultShortTimeFormatTypeName, datetimeConstants.defaultShortTimeFormat, formatTypeValue);
|
||||
}
|
||||
|
||||
function formatYearQuarter(translateFn, year, quarter) {
|
||||
if (1 <= quarter && quarter <= 4) {
|
||||
return translateFn('format.yearQuarter.q' + quarter, {
|
||||
year: year,
|
||||
quarter: quarter
|
||||
});
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function isLongTime24HourFormat(translateFn, formatTypeValue) {
|
||||
const defaultLongTimeFormatTypeName = translateFn('default.longTimeFormat');
|
||||
const type = getDateTimeFormatType(datetimeConstants.allLongTimeFormat, datetimeConstants.allLongTimeFormatArray, defaultLongTimeFormatTypeName, datetimeConstants.defaultLongTimeFormat, formatTypeValue);
|
||||
@@ -1142,6 +1153,25 @@ function getAllStatisticsSortingTypes(translateFn) {
|
||||
return allSortingTypes;
|
||||
}
|
||||
|
||||
function getAllStatisticsDateAggregationTypes(translateFn) {
|
||||
const aggregationTypes = [];
|
||||
|
||||
for (const aggregationTypeField in statisticsConstants.allDateAggregationTypes) {
|
||||
if (!Object.prototype.hasOwnProperty.call(statisticsConstants.allDateAggregationTypes, aggregationTypeField)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const aggregationType = statisticsConstants.allDateAggregationTypes[aggregationTypeField];
|
||||
|
||||
aggregationTypes.push({
|
||||
type: aggregationType.type,
|
||||
displayName: translateFn(aggregationType.name)
|
||||
});
|
||||
}
|
||||
|
||||
return aggregationTypes;
|
||||
}
|
||||
|
||||
function getAllTransactionEditScopeTypes(translateFn) {
|
||||
const allEditScopeTypes = [];
|
||||
|
||||
@@ -1632,6 +1662,7 @@ export function i18nFunctions(i18nGlobal) {
|
||||
formatUnixTimeToShortMonthDay: (userStore, unixTime, utcOffset, currentUtcOffset) => formatUnixTime(unixTime, getI18nShortMonthDayFormat(i18nGlobal.t, userStore.currentUserShortDateFormat), 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),
|
||||
isLongDateMonthAfterYear: (userStore) => isLongDateMonthAfterYear(i18nGlobal.t, userStore.currentUserLongDateFormat),
|
||||
isShortDateMonthAfterYear: (userStore) => isShortDateMonthAfterYear(i18nGlobal.t, userStore.currentUserShortDateFormat),
|
||||
isLongTime24HourFormat: (userStore) => isLongTime24HourFormat(i18nGlobal.t, userStore.currentUserLongTimeFormat),
|
||||
@@ -1668,6 +1699,7 @@ export function i18nFunctions(i18nGlobal) {
|
||||
getAllTrendChartTypes: () => getAllTrendChartTypes(i18nGlobal.t),
|
||||
getAllStatisticsChartDataTypes: (analysisType) => getAllStatisticsChartDataTypes(i18nGlobal.t, analysisType),
|
||||
getAllStatisticsSortingTypes: () => getAllStatisticsSortingTypes(i18nGlobal.t),
|
||||
getAllStatisticsDateAggregationTypes: () => getAllStatisticsDateAggregationTypes(i18nGlobal.t),
|
||||
getAllTransactionEditScopeTypes: () => getAllTransactionEditScopeTypes(i18nGlobal.t),
|
||||
getAllTransactionScheduledFrequencyTypes: () => getAllTransactionScheduledFrequencyTypes(i18nGlobal.t),
|
||||
getAllTransactionDefaultCategories: (categoryType, locale) => getAllTransactionDefaultCategories(categoryType, locale, i18nGlobal.t),
|
||||
|
||||
@@ -71,6 +71,12 @@
|
||||
"a_hh_mm": "A hh:mm",
|
||||
"hh_mm_a": "hh:mm A"
|
||||
},
|
||||
"yearQuarter": {
|
||||
"q1": "{year}Q1",
|
||||
"q2": "{year}Q2",
|
||||
"q3": "{year}Q3",
|
||||
"q4": "{year}Q4"
|
||||
},
|
||||
"misc": {
|
||||
"multiTextJoinSeparator": ", ",
|
||||
"hoursBehindDefaultTimezone": "{hours} hour(s) behind default timezone",
|
||||
@@ -1632,6 +1638,9 @@
|
||||
"Sort by Amount": "Sort by Amount",
|
||||
"Sort by Display Order": "Sort by Display Order",
|
||||
"Sort by Name": "Sort by Name",
|
||||
"Aggregate by Month": "Aggregate by Month",
|
||||
"Aggregate by Quarter": "Aggregate by Quarter",
|
||||
"Aggregate by Year": "Aggregate by Year",
|
||||
"Filter Accounts": "Filter Accounts",
|
||||
"Filter Transaction Categories": "Filter Transaction Categories",
|
||||
"Filter Transaction Tags": "Filter Transaction Tags",
|
||||
|
||||
@@ -71,6 +71,12 @@
|
||||
"a_hh_mm": "A hh:mm",
|
||||
"hh_mm_a": "hh:mm A"
|
||||
},
|
||||
"yearQuarter": {
|
||||
"q1": "{year}Q1",
|
||||
"q2": "{year}Q2",
|
||||
"q3": "{year}Q3",
|
||||
"q4": "{year}Q4"
|
||||
},
|
||||
"misc": {
|
||||
"multiTextJoinSeparator": "、",
|
||||
"hoursBehindDefaultTimezone": "比默认时区晚{hours}小时",
|
||||
@@ -1632,6 +1638,9 @@
|
||||
"Sort by Amount": "按金额排序",
|
||||
"Sort by Display Order": "按显示顺序排序",
|
||||
"Sort by Name": "按名称排序",
|
||||
"Aggregate by Month": "按月聚合",
|
||||
"Aggregate by Quarter": "按季度聚合",
|
||||
"Aggregate by Year": "按年聚合",
|
||||
"Filter Accounts": "过滤账户",
|
||||
"Filter Transaction Categories": "过滤交易类型",
|
||||
"Filter Transaction Tags": "过滤交易标签",
|
||||
|
||||
@@ -121,7 +121,8 @@ const router = createRouter({
|
||||
initEndTime: route.query.endTime,
|
||||
initFilterAccountIds: route.query.filterAccountIds,
|
||||
initFilterCategoryIds: route.query.filterCategoryIds,
|
||||
initSortingType: route.query.sortingType
|
||||
initSortingType: route.query.sortingType,
|
||||
initTrendDateAggregationType: route.query.trendDateAggregationType
|
||||
})
|
||||
},
|
||||
{
|
||||
|
||||
@@ -754,7 +754,7 @@ export const useStatisticsStore = defineStore('statistics', {
|
||||
|
||||
return changed;
|
||||
},
|
||||
getTransactionStatisticsPageParams(analysisType) {
|
||||
getTransactionStatisticsPageParams(analysisType, trendDateAggregationType) {
|
||||
const querys = [];
|
||||
|
||||
querys.push('analysisType=' + analysisType);
|
||||
@@ -776,6 +776,10 @@ export const useStatisticsStore = defineStore('statistics', {
|
||||
querys.push('startTime=' + this.transactionStatisticsFilter.trendChartStartYearMonth);
|
||||
querys.push('endTime=' + this.transactionStatisticsFilter.trendChartEndYearMonth);
|
||||
}
|
||||
|
||||
if (trendDateAggregationType !== statisticsConstants.allDateAggregationTypes.Month.type) {
|
||||
querys.push('trendDateAggregationType=' + trendDateAggregationType);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.transactionStatisticsFilter.filterAccountIds) {
|
||||
@@ -798,7 +802,7 @@ export const useStatisticsStore = defineStore('statistics', {
|
||||
|
||||
return querys.join('&');
|
||||
},
|
||||
getTransactionListPageParams(analysisType, item, dateRange) {
|
||||
getTransactionListPageParams(analysisType, itemId, dateRange) {
|
||||
const accountsStore = useAccountsStore();
|
||||
const transactionCategoriesStore = useTransactionCategoriesStore();
|
||||
const querys = [];
|
||||
@@ -819,7 +823,7 @@ export const useStatisticsStore = defineStore('statistics', {
|
||||
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type
|
||||
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type
|
||||
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
|
||||
querys.push('accountIds=' + item.id);
|
||||
querys.push('accountIds=' + itemId);
|
||||
|
||||
if (!isObjectEmpty(this.transactionStatisticsFilter.filterCategoryIds)) {
|
||||
querys.push('categoryIds=' + getFinalCategoryIdsByFilteredCategoryIds(transactionCategoriesStore.allTransactionCategoriesMap, this.transactionStatisticsFilter.filterCategoryIds));
|
||||
@@ -828,7 +832,7 @@ export const useStatisticsStore = defineStore('statistics', {
|
||||
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type
|
||||
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type
|
||||
|| this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type) {
|
||||
querys.push('categoryIds=' + item.id);
|
||||
querys.push('categoryIds=' + itemId);
|
||||
|
||||
if (!isObjectEmpty(this.transactionStatisticsFilter.filterAccountIds)) {
|
||||
querys.push('accountIds=' + getFinalAccountIdsByFilteredAccountIds(accountsStore.allAccountsMap, this.transactionStatisticsFilter.filterAccountIds));
|
||||
|
||||
@@ -87,6 +87,22 @@
|
||||
@click="shiftDateRange(1)"/>
|
||||
</v-btn-group>
|
||||
|
||||
<v-menu location="bottom">
|
||||
<template #activator="{ props }">
|
||||
<v-btn class="ml-3" color="default" variant="outlined"
|
||||
:prepend-icon="icons.dateAggregation" :disabled="loading"
|
||||
v-bind="props">{{ queryTrendDateAggregationTypeName }}</v-btn>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item class="cursor-pointer" :key="aggregationType.type" :value="aggregationType.type"
|
||||
:append-icon="(trendDateAggregationType === aggregationType.type ? icons.check : null)"
|
||||
:title="aggregationType.displayName"
|
||||
v-for="aggregationType in allDateAggregationTypesArray"
|
||||
@click="setTrendDateAggregationType(aggregationType.type)">
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
<v-btn density="compact" color="default" variant="text" size="24"
|
||||
class="ml-2" :icon="true" :loading="loading" @click="reload">
|
||||
<template #loader>
|
||||
@@ -193,13 +209,13 @@
|
||||
v-for="(item, idx) in categoricalAnalysisData.items">
|
||||
<v-list-item class="pl-0" v-if="!item.hidden">
|
||||
<template #prepend>
|
||||
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item)">
|
||||
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item.id)">
|
||||
<ItemIcon :icon-type="queryChartDataCategory" size="34px"
|
||||
:icon-id="item.icon"
|
||||
:color="item.color"></ItemIcon>
|
||||
</router-link>
|
||||
</template>
|
||||
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item)">
|
||||
<router-link class="statistics-list-item" :to="getTransactionItemLinkUrl(item.id)">
|
||||
<div class="d-flex flex-column ml-2">
|
||||
<div class="d-flex">
|
||||
<span>{{ item.name }}</span>
|
||||
@@ -239,6 +255,7 @@
|
||||
:start-year-month="query.trendChartStartYearMonth"
|
||||
:end-year-month="query.trendChartEndYearMonth"
|
||||
:sorting-type="querySortingType"
|
||||
:date-aggregation-type="trendDateAggregationType"
|
||||
:items="trendsAnalysisData && trendsAnalysisData.items && trendsAnalysisData.items.length ? trendsAnalysisData.items : []"
|
||||
:translate-name="translateNameInTrendsChart"
|
||||
:show-value="showAmountInChart"
|
||||
@@ -303,6 +320,7 @@ import statisticsConstants from '@/consts/statistics.js';
|
||||
import {
|
||||
isDefined,
|
||||
limitText,
|
||||
getNameByKeyValue,
|
||||
arrayItemToObjectField
|
||||
} from '@/lib/common.js'
|
||||
import { formatPercent } from '@/lib/numeral.js';
|
||||
@@ -320,7 +338,7 @@ import {
|
||||
mdiCheck,
|
||||
mdiArrowLeft,
|
||||
mdiArrowRight,
|
||||
mdiSort,
|
||||
mdiCalendarRangeOutline,
|
||||
mdiRefresh,
|
||||
mdiSquareRounded,
|
||||
mdiMenu,
|
||||
@@ -347,7 +365,8 @@ export default {
|
||||
'initEndTime',
|
||||
'initFilterAccountIds',
|
||||
'initFilterCategoryIds',
|
||||
'initSortingType'
|
||||
'initSortingType',
|
||||
'initTrendDateAggregationType'
|
||||
],
|
||||
data() {
|
||||
const { mdAndUp } = useDisplay();
|
||||
@@ -359,6 +378,7 @@ export default {
|
||||
alwaysShowNav: mdAndUp.value,
|
||||
showNav: mdAndUp.value,
|
||||
analysisType: statisticsConstants.allAnalysisTypes.CategoricalAnalysis,
|
||||
trendDateAggregationType: statisticsConstants.allDateAggregationTypes.Month.type,
|
||||
showCustomDateRangeDialog: false,
|
||||
showCustomMonthRangeDialog: false,
|
||||
showFilterAccountDialog: false,
|
||||
@@ -367,7 +387,7 @@ export default {
|
||||
check: mdiCheck,
|
||||
left: mdiArrowLeft,
|
||||
right: mdiArrowRight,
|
||||
sort: mdiSort,
|
||||
dateAggregation: mdiCalendarRangeOutline,
|
||||
refresh: mdiRefresh,
|
||||
square: mdiSquareRounded,
|
||||
menu: mdiMenu,
|
||||
@@ -442,6 +462,9 @@ export default {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
queryTrendDateAggregationTypeName() {
|
||||
return getNameByKeyValue(this.allDateAggregationTypesArray, this.trendDateAggregationType, 'type', 'displayName', '');
|
||||
},
|
||||
queryStartTime() {
|
||||
if (this.queryAnalysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis) {
|
||||
return this.$locale.formatUnixTimeToLongDateTime(this.userStore, this.query.categoricalChartStartTime);
|
||||
@@ -484,6 +507,9 @@ export default {
|
||||
allSortingTypesArray() {
|
||||
return this.$locale.getAllStatisticsSortingTypes();
|
||||
},
|
||||
allDateAggregationTypesArray() {
|
||||
return this.$locale.getAllStatisticsDateAggregationTypes();
|
||||
},
|
||||
allDateRanges() {
|
||||
return datetimeConstants.allDateRanges;
|
||||
},
|
||||
@@ -574,6 +600,7 @@ export default {
|
||||
filterAccountIds: this.initFilterAccountIds,
|
||||
filterCategoryIds: this.initFilterCategoryIds,
|
||||
sortingType: this.initSortingType,
|
||||
trendDateAggregationType: this.initTrendDateAggregationType,
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
@@ -596,7 +623,8 @@ export default {
|
||||
endTime: to.query.endTime,
|
||||
filterAccountIds: to.query.filterAccountIds,
|
||||
filterCategoryIds: to.query.filterCategoryIds,
|
||||
sortingType: to.query.sortingType
|
||||
sortingType: to.query.sortingType,
|
||||
trendDateAggregationType: to.query.trendDateAggregationType
|
||||
});
|
||||
} else {
|
||||
this.init({});
|
||||
@@ -652,6 +680,10 @@ export default {
|
||||
self.analysisType = statisticsConstants.allAnalysisTypes.TrendAnalysis;
|
||||
needReload = true;
|
||||
}
|
||||
|
||||
if (query.trendDateAggregationType) {
|
||||
self.trendDateAggregationType = parseInt(query.trendDateAggregationType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDefined(query.analysisType)) {
|
||||
@@ -796,6 +828,14 @@ export default {
|
||||
this.$router.push(this.getFilterLinkUrl());
|
||||
}
|
||||
},
|
||||
setTrendDateAggregationType(aggregationType) {
|
||||
const changed = this.trendDateAggregationType !== aggregationType;
|
||||
this.trendDateAggregationType = aggregationType;
|
||||
|
||||
if (changed) {
|
||||
this.$router.push(this.getFilterLinkUrl());
|
||||
}
|
||||
},
|
||||
setDateFilter(dateType) {
|
||||
if (this.queryAnalysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis) {
|
||||
if (dateType === this.allDateRanges.Custom.type) { // Custom
|
||||
@@ -962,18 +1002,10 @@ export default {
|
||||
}
|
||||
},
|
||||
clickPieChartItem(item) {
|
||||
this.$router.push(this.getTransactionItemLinkUrl(item));
|
||||
this.$router.push(this.getTransactionItemLinkUrl(item.id));
|
||||
},
|
||||
clickTrendChartItem(item) {
|
||||
const minUnixTime = getYearMonthFirstUnixTime(item.yearMonth);
|
||||
const maxUnixTime = getYearMonthLastUnixTime(item.yearMonth);
|
||||
const dateRangeType = getDateTypeByDateRange(minUnixTime, maxUnixTime, this.firstDayOfWeek, datetimeConstants.allDateRangeScenes.Normal);
|
||||
|
||||
this.$router.push(this.getTransactionItemLinkUrl(item.item, {
|
||||
minTime: minUnixTime,
|
||||
maxTime: maxUnixTime,
|
||||
type: dateRangeType,
|
||||
}));
|
||||
this.$router.push(this.getTransactionItemLinkUrl(item.itemId, item.dateRange));
|
||||
},
|
||||
getDisplayAmount(amount, currency, textLimit) {
|
||||
amount = this.getDisplayCurrency(amount, currency);
|
||||
@@ -998,10 +1030,10 @@ export default {
|
||||
return formatPercent(value, precision, lowPrecisionValue);
|
||||
},
|
||||
getFilterLinkUrl() {
|
||||
return `/statistics/transaction?${this.statisticsStore.getTransactionStatisticsPageParams(this.queryAnalysisType)}`;
|
||||
return `/statistics/transaction?${this.statisticsStore.getTransactionStatisticsPageParams(this.queryAnalysisType, this.trendDateAggregationType)}`;
|
||||
},
|
||||
getTransactionItemLinkUrl(item, dateRange) {
|
||||
return `/transaction/list?${this.statisticsStore.getTransactionListPageParams(this.queryAnalysisType, item, dateRange)}`;
|
||||
getTransactionItemLinkUrl(itemId, dateRange) {
|
||||
return `/transaction/list?${this.statisticsStore.getTransactionListPageParams(this.queryAnalysisType, itemId, dateRange)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user