support filter multiple accounts and categories in transaction list page

This commit is contained in:
MaysWind
2024-07-06 22:05:48 +08:00
parent c0cc9b5247
commit 3dd39defc1
13 changed files with 342 additions and 94 deletions
@@ -117,6 +117,7 @@
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useAccountsStore } from '@/stores/account.js';
import { useTransactionsStore } from '@/stores/transaction.js';
import { useStatisticsStore } from '@/stores/statistics.js';
import accountConstants from '@/consts/account.js';
@@ -142,23 +143,23 @@ export default {
return {
loading: true,
loadingError: null,
modifyDefault: false,
type: null,
filterAccountIds: {},
collapseStates: self.getCollapseStates(),
showMoreActionSheet: false
}
},
computed: {
...mapStores(useSettingsStore, useAccountsStore, useStatisticsStore),
...mapStores(useSettingsStore, useAccountsStore, useTransactionsStore, useStatisticsStore),
title() {
if (this.modifyDefault) {
if (this.type === 'statisticsDefault') {
return 'Default Account Filter';
} else {
return 'Filter Accounts';
}
},
applyText() {
if (this.modifyDefault) {
if (this.type === 'statisticsDefault') {
return 'Save';
} else {
return 'Apply';
@@ -178,7 +179,7 @@ export default {
const self = this;
const query = self.f7route.query;
self.modifyDefault = !!query.modifyDefault;
self.type = query.type;
self.accountsStore.loadAllAccounts({
force: false
@@ -193,13 +194,34 @@ export default {
}
const account = self.accountsStore.allAccountsMap[accountId];
allAccountIds[account.id] = false;
if (this.type === 'transactionListCurrent' && self.transactionsStore.allFilterAccountIdsCount > 0) {
allAccountIds[account.id] = true;
} else {
allAccountIds[account.id] = false;
}
}
if (self.modifyDefault) {
if (this.type === 'statisticsDefault') {
self.filterAccountIds = copyObjectTo(self.settingsStore.appSettings.statistics.defaultAccountFilter, allAccountIds);
} else {
} else if (this.type === 'statisticsCurrent') {
self.filterAccountIds = copyObjectTo(self.statisticsStore.transactionStatisticsFilter.filterAccountIds, allAccountIds);
} else if (this.type === 'transactionListCurrent') {
for (let accountId in self.transactionsStore.allFilterAccountIds) {
if (!Object.prototype.hasOwnProperty.call(self.transactionsStore.allFilterAccountIds, accountId)) {
continue;
}
const account = self.accountsStore.allAccountsMap[accountId];
if (account) {
selectAccountOrSubAccounts(allAccountIds, account, false);
}
}
self.filterAccountIds = allAccountIds;
} else {
self.$toast('Parameter Invalid');
self.loadingError = 'Parameter Invalid';
}
}).catch(error => {
if (error.processed) {
@@ -219,23 +241,37 @@ export default {
const router = self.f7router;
const filteredAccountIds = {};
let finalAccountIds = '';
for (let accountId in self.filterAccountIds) {
if (!Object.prototype.hasOwnProperty.call(self.filterAccountIds, accountId)) {
continue;
}
if (self.filterAccountIds[accountId]) {
const account = self.accountsStore.allAccountsMap[accountId];
if (!isAccountOrSubAccountsAllChecked(account, self.filterAccountIds)) {
filteredAccountIds[accountId] = true;
} else {
if (finalAccountIds.length > 0) {
finalAccountIds += ',';
}
finalAccountIds += accountId;
}
}
if (self.modifyDefault) {
if (this.type === 'statisticsDefault') {
self.settingsStore.setStatisticsDefaultAccountFilter(filteredAccountIds);
} else {
} else if (this.type === 'statisticsCurrent') {
self.statisticsStore.updateTransactionStatisticsFilter({
filterAccountIds: filteredAccountIds
});
} else if (this.type === 'transactionListCurrent') {
self.transactionsStore.updateTransactionListFilter({
accountIds: finalAccountIds
});
self.transactionsStore.updateTransactionListInvalidState(true);
}
router.back();
@@ -126,6 +126,7 @@
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
import { useTransactionsStore } from '@/stores/transaction.js';
import { useStatisticsStore } from '@/stores/statistics.js';
import categoryConstants from '@/consts/category.js';
@@ -138,6 +139,7 @@ import {
selectAll,
selectNone,
selectInvert,
isCategoryOrSubCategoriesAllChecked,
isSubCategoriesAllChecked,
isSubCategoriesHasButNotAllChecked
} from '@/lib/category.js';
@@ -153,23 +155,23 @@ export default {
return {
loading: true,
loadingError: null,
modifyDefault: false,
type: null,
filterCategoryIds: {},
collapseStates: self.getCollapseStates(),
showMoreActionSheet: false
}
},
computed: {
...mapStores(useSettingsStore, useTransactionCategoriesStore, useStatisticsStore),
...mapStores(useSettingsStore, useTransactionCategoriesStore, useTransactionsStore, useStatisticsStore),
title() {
if (this.modifyDefault) {
if (this.type === 'statisticsDefault') {
return 'Default Transaction Category Filter';
} else {
return 'Filter Transaction Categories';
}
},
applyText() {
if (this.modifyDefault) {
if (this.type === 'statisticsDefault') {
return 'Save';
} else {
return 'Apply';
@@ -189,7 +191,7 @@ export default {
const self = this;
const query = self.f7route.query;
self.modifyDefault = !!query.modifyDefault;
self.type = query.type;
self.transactionCategoriesStore.loadAllCategories({
force: false
@@ -204,13 +206,37 @@ export default {
}
const category = self.transactionCategoriesStore.allTransactionCategoriesMap[categoryId];
allCategoryIds[category.id] = false;
if (this.type === 'transactionListCurrent' && self.transactionsStore.allFilterCategoryIdsCount > 0) {
allCategoryIds[category.id] = true;
} else {
allCategoryIds[category.id] = false;
}
}
if (self.modifyDefault) {
if (this.type === 'statisticsDefault') {
self.filterCategoryIds = copyObjectTo(self.settingsStore.appSettings.statistics.defaultTransactionCategoryFilter, allCategoryIds);
} else {
} else if (this.type === 'statisticsCurrent') {
self.filterCategoryIds = copyObjectTo(self.statisticsStore.transactionStatisticsFilter.filterCategoryIds, allCategoryIds);
} else if (this.type === 'transactionListCurrent') {
for (let categoryId in self.transactionsStore.allFilterCategoryIds) {
if (!Object.prototype.hasOwnProperty.call(self.transactionsStore.allFilterCategoryIds, categoryId)) {
continue;
}
const category = self.transactionCategoriesStore.allTransactionCategoriesMap[categoryId];
if (category && (!category.subCategories || !category.subCategories.length)) {
allCategoryIds[category.id] = false;
} else if (category) {
selectSubCategories(allCategoryIds, category, false);
}
}
self.filterCategoryIds = allCategoryIds;
} else {
self.$toast('Parameter Invalid');
self.loadingError = 'Parameter Invalid';
}
}).catch(error => {
if (error.processed) {
@@ -230,23 +256,37 @@ export default {
const router = self.f7router;
const filteredCategoryIds = {};
let finalCategoryIds = '';
for (let categoryId in self.filterCategoryIds) {
if (!Object.prototype.hasOwnProperty.call(self.filterCategoryIds, categoryId)) {
continue;
}
if (self.filterCategoryIds[categoryId]) {
const category = self.transactionCategoriesStore.allTransactionCategoriesMap[categoryId];
if (!isCategoryOrSubCategoriesAllChecked(category, self.filterCategoryIds)) {
filteredCategoryIds[categoryId] = true;
} else {
if (finalCategoryIds.length > 0) {
finalCategoryIds += ',';
}
finalCategoryIds += categoryId;
}
}
if (self.modifyDefault) {
if (this.type === 'statisticsDefault') {
self.settingsStore.setStatisticsDefaultTransactionCategoryFilter(filteredCategoryIds);
} else {
} else if (this.type === 'statisticsCurrent') {
self.statisticsStore.updateTransactionStatisticsFilter({
filterCategoryIds: filteredCategoryIds
});
} else if (this.type === 'transactionListCurrent') {
self.transactionsStore.updateTransactionListFilter({
categoryIds: finalCategoryIds
});
self.transactionsStore.updateTransactionListInvalidState(true);
}
router.back();
+2 -2
View File
@@ -24,9 +24,9 @@
</select>
</f7-list-item>
<f7-list-item :title="$t('Default Account Filter')" link="/settings/filter/account?modifyDefault=1"></f7-list-item>
<f7-list-item :title="$t('Default Account Filter')" link="/settings/filter/account?type=statisticsDefault"></f7-list-item>
<f7-list-item :title="$t('Default Transaction Category Filter')" link="/settings/filter/category?modifyDefault=1"></f7-list-item>
<f7-list-item :title="$t('Default Transaction Category Filter')" link="/settings/filter/category?type=statisticsDefault"></f7-list-item>
<f7-list-item
:title="$t('Default Sort Order')"
@@ -534,10 +534,10 @@ export default {
this.f7router.navigate(this.getItemLinkUrl(item));
},
filterAccounts() {
this.f7router.navigate('/settings/filter/account');
this.f7router.navigate('/settings/filter/account?type=statisticsCurrent');
},
filterCategories() {
this.f7router.navigate('/settings/filter/category');
this.f7router.navigate('/settings/filter/category?type=statisticsCurrent');
},
settings() {
this.f7router.navigate('/statistic/settings');
+23 -17
View File
@@ -290,7 +290,7 @@
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="!query.categoryIds"></f7-icon>
</template>
</f7-list-item>
<f7-list-item :class="{ 'list-item-selected': query.categoryIds && queryAllFilterCategoryIdsCount > 1 }" :title="$t('Multiple Categories')" @click="showMultipleCategoriesPopup()">
<f7-list-item :class="{ 'list-item-selected': query.categoryIds && queryAllFilterCategoryIdsCount > 1 }" :title="$t('Multiple Categories')" @click="filterMultipleCategories()">
<template #media>
<f7-icon f7="rectangle_on_rectangle"></f7-icon>
</template>
@@ -317,16 +317,17 @@
</template>
<f7-accordion-content>
<f7-list dividers class="padding-left">
<f7-list-item :class="{ 'list-item-selected': queryAllFilterCategoryIds[category.id] }" :title="$t('All')" @click="changeCategoryFilter(category.id)">
<f7-list-item :class="{ 'list-item-selected': query.categoryIds === category.id, 'item-in-multiple-selection': queryAllFilterCategoryIdsCount > 1 && queryAllFilterCategoryIds[category.id] }"
:title="$t('All')" @click="changeCategoryFilter(category.id)">
<template #media>
<f7-icon f7="rectangle_grid_2x2"></f7-icon>
</template>
<template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="queryAllFilterCategoryIds[category.id]"></f7-icon>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="query.categoryIds === category.id"></f7-icon>
</template>
</f7-list-item>
<f7-list-item :title="subCategory.name"
:class="{ 'list-item-selected': queryAllFilterCategoryIds[subCategory.id] }"
:class="{ 'list-item-selected': query.categoryIds === subCategory.id, 'item-in-multiple-selection': queryAllFilterCategoryIdsCount > 1 && queryAllFilterCategoryIds[subCategory.id] }"
:key="subCategory.id"
v-for="subCategory in category.subCategories"
v-show="!subCategory.hidden"
@@ -338,7 +339,7 @@
<template #after>
<f7-icon class="list-item-checked-icon"
f7="checkmark_alt"
v-if="queryAllFilterCategoryIds[subCategory.id]">
v-if="query.categoryIds === subCategory.id">
</f7-icon>
</template>
</f7-list-item>
@@ -360,7 +361,7 @@
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="!query.accountIds"></f7-icon>
</template>
</f7-list-item>
<f7-list-item :class="{ 'list-item-selected': query.accountIds && queryAllFilterAccountIdsCount > 1 }" :title="$t('Multiple Accounts')" @click="showMultipleAccountsPopup()">
<f7-list-item :class="{ 'list-item-selected': query.accountIds && queryAllFilterAccountIdsCount > 1 }" :title="$t('Multiple Accounts')" @click="filterMultipleAccounts()">
<template #media>
<f7-icon f7="rectangle_on_rectangle"></f7-icon>
</template>
@@ -369,7 +370,7 @@
</template>
</f7-list-item>
<f7-list-item :title="account.name"
:class="{ 'list-item-selected': queryAllFilterAccountIds[account.id] }"
:class="{ 'list-item-selected': query.accountIds === account.id, 'item-in-multiple-selection': queryAllFilterAccountIdsCount > 1 && queryAllFilterAccountIds[account.id] }"
:key="account.id"
v-for="account in allAccounts"
v-show="!account.hidden"
@@ -381,7 +382,7 @@
<template #after>
<f7-icon class="list-item-checked-icon"
f7="checkmark_alt"
v-if="queryAllFilterAccountIds[account.id]">
v-if="query.accountIds === account.id">
</f7-icon>
</template>
</f7-list-item>
@@ -802,9 +803,11 @@ export default {
return;
}
let removeCategoryFilter = false;
let newCategoryFilter = undefined;
if (type && this.query.categoryIds) {
newCategoryFilter = '';
for (let categoryId in this.queryAllFilterCategoryIds) {
if (!Object.prototype.hasOwnProperty.call(this.queryAllFilterCategoryIds, categoryId)) {
continue;
@@ -812,16 +815,19 @@ export default {
const category = this.allCategories[categoryId];
if (category && category.type !== transactionTypeToCategoryType(type)) {
removeCategoryFilter = true;
break;
if (category && category.type === transactionTypeToCategoryType(type)) {
if (newCategoryFilter.length > 0) {
newCategoryFilter += ',';
}
newCategoryFilter += categoryId;
}
}
}
this.transactionsStore.updateTransactionListFilter({
type: type,
categoryIds: removeCategoryFilter ? '' : undefined
categoryIds: newCategoryFilter
});
this.showMorePopover = false;
@@ -880,11 +886,11 @@ export default {
this.reload(null);
},
showMultipleCategoriesPopup() {
filterMultipleCategories() {
this.f7router.navigate('/settings/filter/category?type=transactionListCurrent');
},
showMultipleAccountsPopup() {
filterMultipleAccounts() {
this.f7router.navigate('/settings/filter/account?type=transactionListCurrent');
},
duplicate(transaction) {
this.f7router.navigate(`/transaction/add?id=${transaction.id}&type=${transaction.type}`);