add asset trends in statistics & analysis (#314)

This commit is contained in:
MaysWind
2025-11-09 22:51:46 +08:00
parent d3abb279e3
commit 4c8bb5a0b7
52 changed files with 1917 additions and 266 deletions
@@ -10,6 +10,7 @@ import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
import type { TypeAndDisplayName } from '@/core/base.ts';
import type { WeekDayValue } from '@/core/datetime.ts';
import { TransactionType } from '@/core/transaction.ts';
import { StatisticsAnalysisType } from '@/core/statistics.ts';
import { KnownFileType } from '@/core/file.ts';
import type { Account } from '@/models/account.ts';
import type { TransactionCategory } from '@/models/transaction_category.ts';
@@ -55,7 +56,7 @@ export function useReconciliationStatementPageBase() {
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
const allChartTypes = computed<TypeAndDisplayName[]>(() => getAllAccountBalanceTrendChartTypes());
const allDateAggregationTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsDateAggregationTypesWithShortName());
const allDateAggregationTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsDateAggregationTypesWithShortName(StatisticsAnalysisType.AssetTrends));
const currentAccount = computed(() => allAccountsMap.value[accountId.value]);
const currentAccountCurrency = computed<string>(() => currentAccount.value?.currency ?? defaultCurrency.value);
@@ -88,6 +88,14 @@ export const ALL_APPLICATION_CLOUD_SETTINGS: CategorizedApplicationCloudSettingI
{ settingKey: 'statistics.defaultTrendChartType', settingName: 'Default Chart Type', mobile: false, desktop: true },
{ settingKey: 'statistics.defaultTrendChartDataRangeType', settingName: 'Default Date Range', mobile: true, desktop: true }
]
},
{
categoryName: 'Statistics Settings',
categorySubName: 'Asset Trends Settings',
items: [
{ settingKey: 'statistics.defaultAssetTrendsChartType', settingName: 'Default Chart Type', mobile: false, desktop: true },
{ settingKey: 'statistics.defaultAssetTrendsChartDataRangeType', settingName: 'Default Date Range', mobile: true, desktop: true }
]
}
];
@@ -27,6 +27,7 @@ export function useStatisticsSettingPageBase() {
const allCategoricalChartDateRanges = computed<LocalizedDateRange[]>(() => getAllDateRanges(DateRangeScene.Normal, false));
const allTrendChartTypes = computed<TypeAndDisplayName[]>(() => getAllTrendChartTypes());
const allTrendChartDateRanges = computed<LocalizedDateRange[]>(() => getAllDateRanges(DateRangeScene.TrendAnalysis, false));
const allAssetTrendsChartDateRanges = computed<LocalizedDateRange[]>(() => getAllDateRanges(DateRangeScene.AssetTrends, false));
const defaultChartDataType = computed<number>({
get: () => settingsStore.appSettings.statistics.defaultChartDataType,
@@ -63,6 +64,16 @@ export function useStatisticsSettingPageBase() {
set: (value: number) => settingsStore.setStatisticsDefaultTrendChartDateRange(value)
});
const defaultAssetTrendsChartType = computed<number>({
get: () => settingsStore.appSettings.statistics.defaultAssetTrendsChartType,
set: (value: number) => settingsStore.setStatisticsDefaultAssetTrendsChartType(value)
});
const defaultAssetTrendsChartDateRange = computed<number>({
get: () => settingsStore.appSettings.statistics.defaultAssetTrendsChartDataRangeType,
set: (value: number) => settingsStore.setStatisticsDefaultAssetTrendsChartDateRange(value)
});
return {
// computed states
allChartDataTypes,
@@ -72,12 +83,15 @@ export function useStatisticsSettingPageBase() {
allCategoricalChartDateRanges,
allTrendChartTypes,
allTrendChartDateRanges,
allAssetTrendsChartDateRanges,
defaultChartDataType,
defaultTimezoneType,
defaultSortingType,
defaultCategoricalChartType,
defaultCategoricalChartDateRange,
defaultTrendChartType,
defaultTrendChartDateRange
defaultTrendChartDateRange,
defaultAssetTrendsChartType,
defaultAssetTrendsChartDateRange
};
}
@@ -23,7 +23,8 @@ import type {
TransactionCategoricalOverviewAnalysisData,
TransactionCategoricalAnalysisData,
TransactionCategoricalAnalysisDataItem,
TransactionTrendsAnalysisData
TransactionTrendsAnalysisData,
TransactionAssetTrendsAnalysisData
} from '@/models/transaction.ts';
import { limitText, findNameByType, findDisplayNameByType } from '@/lib/common.ts';
@@ -49,6 +50,7 @@ export function useStatisticsTransactionPageBase() {
const loading = ref<boolean>(true);
const analysisType = ref<StatisticsAnalysisType>(StatisticsAnalysisType.CategoricalAnalysis);
const trendDateAggregationType = ref<number>(ChartDateAggregationType.Default.type);
const assetTrendsDateAggregationType = ref<number>(ChartDateAggregationType.Default.type);
const showAccountBalance = computed<boolean>(() => settingsStore.appSettings.showAccountBalance);
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
@@ -60,12 +62,15 @@ export function useStatisticsTransactionPageBase() {
return getAllDateRanges(DateRangeScene.Normal, true);
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
return getAllDateRanges(DateRangeScene.TrendAnalysis, true);
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return getAllDateRanges(DateRangeScene.AssetTrends, true);
} else {
return [];
}
});
const allSortingTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsSortingTypes());
const allDateAggregationTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsDateAggregationTypes());
const allTrendAnalysisDateAggregationTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsDateAggregationTypes(StatisticsAnalysisType.TrendAnalysis));
const allAssetTrendsDateAggregationTypes = computed<TypeAndDisplayName[]>(() => getAllStatisticsDateAggregationTypes(StatisticsAnalysisType.AssetTrends));
const query = computed<TransactionStatisticsFilter>(() => statisticsStore.transactionStatisticsFilter);
const queryChartDataCategory = computed<string>(() => statisticsStore.categoricalAnalysisChartDataCategory);
@@ -74,6 +79,8 @@ export function useStatisticsTransactionPageBase() {
return query.value.categoricalChartDateType;
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
return query.value.trendChartDateType;
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return query.value.assetTrendsChartDateType;
} else {
return null;
}
@@ -84,6 +91,8 @@ export function useStatisticsTransactionPageBase() {
return formatUnixTimeToLongDateTime(query.value.categoricalChartStartTime);
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
return formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthFirstUnixTime(query.value.trendChartStartYearMonth));
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return formatUnixTimeToLongDateTime(query.value.assetTrendsChartStartTime);
} else {
return '';
}
@@ -94,21 +103,25 @@ export function useStatisticsTransactionPageBase() {
return formatUnixTimeToLongDateTime(query.value.categoricalChartEndTime);
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
return formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthLastUnixTime(query.value.trendChartEndYearMonth));
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return formatUnixTimeToLongDateTime(query.value.assetTrendsChartEndTime);
} else {
return '';
}
});
const queryDateRangeName = computed<string>(() => {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type ||
query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
return tt(DateRange.All.name);
}
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type ||
query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
return tt(DateRange.All.name);
}
return formatDateRange(query.value.categoricalChartDateType, query.value.categoricalChartStartTime, query.value.categoricalChartEndTime);
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
return formatDateRange(query.value.trendChartDateType, getYearMonthFirstUnixTime(query.value.trendChartStartYearMonth), getYearMonthLastUnixTime(query.value.trendChartEndYearMonth));
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return formatDateRange(query.value.assetTrendsChartDateType, query.value.assetTrendsChartStartTime, query.value.assetTrendsChartEndTime);
} else {
return '';
}
@@ -124,7 +137,8 @@ export function useStatisticsTransactionPageBase() {
return tt(querySortingTypeName);
});
const queryTrendDateAggregationTypeName = computed<string>(() => findDisplayNameByType(allDateAggregationTypes.value, trendDateAggregationType.value) || '');
const queryTrendDateAggregationTypeName = computed<string>(() => findDisplayNameByType(allTrendAnalysisDateAggregationTypes.value, trendDateAggregationType.value) || '');
const queryAssetTrendsDateAggregationTypeName = computed<string>(() => findDisplayNameByType(allAssetTrendsDateAggregationTypes.value, assetTrendsDateAggregationType.value) || '');
const isQueryDateRangeChanged = computed<boolean>(() => {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
@@ -144,13 +158,31 @@ export function useStatisticsTransactionPageBase() {
}
return !!query.value.trendChartStartYearMonth || !!query.value.trendChartEndYearMonth;
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
if (query.value.assetTrendsChartDateType === settingsStore.appSettings.statistics.defaultAssetTrendsChartDataRangeType) {
return false;
}
return !!query.value.assetTrendsChartStartTime || !!query.value.assetTrendsChartEndTime;
} else {
return false;
}
});
const canChangeDateRange = computed<boolean>(() => {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
return false;
}
return true;
} else {
return true;
}
});
const canShiftDateRange = computed<boolean>(() => {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
if (!canChangeDateRange.value) {
return false;
}
@@ -158,13 +190,31 @@ export function useStatisticsTransactionPageBase() {
return query.value.categoricalChartDateType !== DateRange.All.type;
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
return query.value.trendChartDateType !== DateRange.All.type;
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return query.value.assetTrendsChartDateType !== DateRange.All.type;
} else {
return false;
}
});
const canUseCategoryFilter = computed<boolean>(() => {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
return false;
}
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return false;
}
return true;
});
const canUseServerCustomFilter = computed<boolean>(() => {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
return false;
}
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return false;
}
@@ -172,25 +222,19 @@ export function useStatisticsTransactionPageBase() {
});
const canUseTagFilter = computed<boolean>(() => {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
return false;
}
return true;
return canUseServerCustomFilter.value;
});
const canUseKeywordFilter = computed<boolean>(() => {
if (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type) {
return false;
}
return true;
return canUseServerCustomFilter.value;
});
const showAmountInChart = computed<boolean>(() => {
if (!showAccountBalance.value
&& (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type)) {
return false;
if (!showAccountBalance.value) {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis
&& (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type)) {
return false;
}
}
return true;
@@ -231,7 +275,8 @@ export function useStatisticsTransactionPageBase() {
query.value.chartDataType !== ChartDataType.TotalInflows.type &&
query.value.chartDataType !== ChartDataType.TotalIncome.type &&
query.value.chartDataType !== ChartDataType.NetCashFlow.type &&
query.value.chartDataType !== ChartDataType.NetIncome.type;
query.value.chartDataType !== ChartDataType.NetIncome.type &&
query.value.chartDataType !== ChartDataType.NetWorth.type;
});
const showStackedInTrendsChart = computed<boolean>(() => {
@@ -246,18 +291,22 @@ export function useStatisticsTransactionPageBase() {
query.value.chartDataType === ChartDataType.TotalInflows.type ||
query.value.chartDataType === ChartDataType.TotalIncome.type ||
query.value.chartDataType === ChartDataType.NetCashFlow.type ||
query.value.chartDataType === ChartDataType.NetIncome.type;
query.value.chartDataType === ChartDataType.NetIncome.type ||
query.value.chartDataType === ChartDataType.NetWorth.type;
});
const categoricalOverviewAnalysisData = computed<TransactionCategoricalOverviewAnalysisData | null>(() => statisticsStore.categoricalOverviewAnalysisData);
const categoricalAnalysisData = computed<TransactionCategoricalAnalysisData>(() => statisticsStore.categoricalAnalysisData);
const trendsAnalysisData = computed<TransactionTrendsAnalysisData | null>(() => statisticsStore.trendsAnalysisData);
const assetTrendsData = computed<TransactionAssetTrendsAnalysisData | null>(() => statisticsStore.assetTrendsData);
function canShowCustomDateRange(dateRangeType: number): boolean {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
return query.value.categoricalChartDateType === dateRangeType && !!query.value.categoricalChartStartTime && !!query.value.categoricalChartEndTime;
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
return query.value.trendChartDateType === dateRangeType && !!query.value.trendChartStartYearMonth && !!query.value.trendChartEndYearMonth;
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
return query.value.assetTrendsChartDateType === dateRangeType && !!query.value.assetTrendsChartStartTime && !!query.value.assetTrendsChartEndTime;
} else {
return false;
}
@@ -276,11 +325,11 @@ export function useStatisticsTransactionPageBase() {
function getDisplayAmount(amount: number, currency: string, textLimit?: number): string {
const finalAmount = formatAmountToLocalizedNumeralsWithCurrency(amount, currency);
if (!showAccountBalance.value
&& (query.value.chartDataType === ChartDataType.AccountTotalAssets.type
|| query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type)
) {
return DISPLAY_HIDDEN_AMOUNT;
if (!showAccountBalance.value) {
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis
&& (query.value.chartDataType === ChartDataType.AccountTotalAssets.type || query.value.chartDataType === ChartDataType.AccountTotalLiabilities.type)) {
return DISPLAY_HIDDEN_AMOUNT;
}
}
if (textLimit) {
@@ -295,6 +344,7 @@ export function useStatisticsTransactionPageBase() {
loading,
analysisType,
trendDateAggregationType,
assetTrendsDateAggregationType,
// computed states
showAccountBalance,
defaultCurrency,
@@ -302,7 +352,8 @@ export function useStatisticsTransactionPageBase() {
fiscalYearStart,
allDateRanges,
allSortingTypes,
allDateAggregationTypes,
allTrendAnalysisDateAggregationTypes,
allAssetTrendsDateAggregationTypes,
query,
queryChartDataCategory,
queryDateType,
@@ -312,7 +363,9 @@ export function useStatisticsTransactionPageBase() {
queryChartDataTypeName,
querySortingTypeName,
queryTrendDateAggregationTypeName,
queryAssetTrendsDateAggregationTypeName,
isQueryDateRangeChanged,
canChangeDateRange,
canShiftDateRange,
canUseCategoryFilter,
canUseTagFilter,
@@ -326,6 +379,7 @@ export function useStatisticsTransactionPageBase() {
categoricalOverviewAnalysisData,
categoricalAnalysisData,
trendsAnalysisData,
assetTrendsData,
// functions
canShowCustomDateRange,
getTransactionCategoricalAnalysisDataItemDisplayColor,