mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-18 00:34:28 +08:00
support filtering account or category in statistics page
This commit is contained in:
@@ -514,6 +514,9 @@ export default {
|
||||
'Accounts': 'Accounts',
|
||||
'Statistics': 'Statistics',
|
||||
'Settings': 'Settings',
|
||||
'Select All': 'Select All',
|
||||
'Select None': 'Select None',
|
||||
'Invert Selection': 'Invert Selection',
|
||||
'Back': 'Back',
|
||||
'Load More': 'Load More',
|
||||
'No data': 'No data',
|
||||
@@ -666,6 +669,8 @@ export default {
|
||||
'Default Chart Type': 'Default Chart Type',
|
||||
'Default Chart Data Type': 'Default Chart Data Type',
|
||||
'Default Date Range': 'Default Date Range',
|
||||
'Filter Accounts': 'Filter Accounts',
|
||||
'Filter Transaction Categories': 'Filter Transaction Categories',
|
||||
'User Profile': 'User Profile',
|
||||
'Language': 'Language',
|
||||
'Auto Update Exchange Rates Data': 'Auto Update Exchange Rates Data',
|
||||
|
||||
@@ -514,6 +514,9 @@ export default {
|
||||
'Accounts': '账户',
|
||||
'Statistics': '统计',
|
||||
'Settings': '设置',
|
||||
'Select All': '全部选择',
|
||||
'Select None': '全部不选',
|
||||
'Invert Selection': '反向选择',
|
||||
'Back': '返回',
|
||||
'Load More': '加载更多',
|
||||
'No data': '没有数据',
|
||||
@@ -666,6 +669,8 @@ export default {
|
||||
'Default Chart Type': '默认图表类型',
|
||||
'Default Chart Data Type': '默认图表数据类型',
|
||||
'Default Date Range': '默认时间范围',
|
||||
'Filter Accounts': '过滤账户',
|
||||
'Filter Transaction Categories': '过滤交易类型',
|
||||
'User Profile': '用户信息',
|
||||
'Language': '语言',
|
||||
'Auto Update Exchange Rates Data': '自动更新汇率数据',
|
||||
|
||||
@@ -13,6 +13,8 @@ import AccountEditPage from '../views/mobile/accounts/Edit.vue';
|
||||
|
||||
import StatisticsTransactionPage from '../views/mobile/statistics/Transaction.vue';
|
||||
import StatisticsSettingsPage from '../views/mobile/statistics/Settings.vue';
|
||||
import StatisticsAccountFilterSettingsPage from '../views/mobile/statistics/AccountFilterSettings.vue';
|
||||
import StatisticsCategoryFilterSettingsPage from '../views/mobile/statistics/CategoryFilterSettings.vue';
|
||||
|
||||
import SettingsPage from '../views/mobile/Settings.vue';
|
||||
import ApplicationLockPage from '../views/mobile/ApplicationLock.vue';
|
||||
@@ -181,6 +183,16 @@ const routes = [
|
||||
component: StatisticsSettingsPage,
|
||||
beforeEnter: checkLogin
|
||||
},
|
||||
{
|
||||
path: '/statistic/filter/account',
|
||||
component: StatisticsAccountFilterSettingsPage,
|
||||
beforeEnter: checkLogin
|
||||
},
|
||||
{
|
||||
path: '/statistic/filter/category',
|
||||
component: StatisticsCategoryFilterSettingsPage,
|
||||
beforeEnter: checkLogin
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
component: SettingsPage,
|
||||
|
||||
@@ -184,6 +184,8 @@ const stores = {
|
||||
endTime: 0,
|
||||
chartType: statisticsConstants.defaultChartType,
|
||||
chartDataType: statisticsConstants.defaultChartDataType,
|
||||
filterAccountIds: {},
|
||||
filterCategoryIds: {}
|
||||
},
|
||||
transactionStatistics: [],
|
||||
transactionStatisticsStateInvalid: true,
|
||||
@@ -244,6 +246,8 @@ const stores = {
|
||||
state.transactionStatisticsFilter.endTime = 0;
|
||||
state.transactionStatisticsFilter.chartType = statisticsConstants.defaultChartType;
|
||||
state.transactionStatisticsFilter.chartDataType = statisticsConstants.defaultChartDataType;
|
||||
state.transactionStatisticsFilter.filterAccountIds = {};
|
||||
state.transactionStatisticsFilter.filterCategoryIds = {};
|
||||
state.transactionStatistics = {};
|
||||
state.transactionStatisticsStateInvalid = true;
|
||||
|
||||
@@ -833,6 +837,18 @@ const stores = {
|
||||
} else {
|
||||
state.transactionStatisticsFilter.chartDataType = statisticsConstants.defaultChartDataType;
|
||||
}
|
||||
|
||||
if (filter && utils.isObject(filter.filterAccountIds)) {
|
||||
state.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds;
|
||||
} else {
|
||||
state.transactionStatisticsFilter.filterAccountIds = {};
|
||||
}
|
||||
|
||||
if (filter && utils.isObject(filter.filterCategoryIds)) {
|
||||
state.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds;
|
||||
} else {
|
||||
state.transactionStatisticsFilter.filterCategoryIds = {};
|
||||
}
|
||||
},
|
||||
[UPDATE_TRANSACTION_STATISTICS_FILTER] (state, filter) {
|
||||
if (filter && utils.isNumber(filter.dateType)) {
|
||||
@@ -854,6 +870,14 @@ const stores = {
|
||||
if (filter && utils.isNumber(filter.chartDataType)) {
|
||||
state.transactionStatisticsFilter.chartDataType = filter.chartDataType;
|
||||
}
|
||||
|
||||
if (filter && utils.isObject(filter.filterAccountIds)) {
|
||||
state.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds;
|
||||
}
|
||||
|
||||
if (filter && utils.isObject(filter.filterCategoryIds)) {
|
||||
state.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds;
|
||||
}
|
||||
},
|
||||
[UPDATE_TRANSACTION_STATISTICS_INVALID_STATE] (state, invalidState) {
|
||||
state.transactionStatisticsStateInvalid = invalidState;
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<f7-page>
|
||||
<f7-navbar>
|
||||
<f7-nav-left :back-link="$t('Back')"></f7-nav-left>
|
||||
<f7-nav-title :title="$t('Filter Accounts')"></f7-nav-title>
|
||||
<f7-nav-right>
|
||||
<f7-link icon-f7="ellipsis" @click="showMoreActionSheet = true"></f7-link>
|
||||
<f7-link :text="$t('Save')" @click="save"></f7-link>
|
||||
</f7-nav-right>
|
||||
</f7-navbar>
|
||||
|
||||
<f7-card class="skeleton-text" v-if="loading">
|
||||
<f7-card-header>
|
||||
<small :style="{ opacity: 0.6 }">
|
||||
<span>Account Category</span>
|
||||
</small>
|
||||
</f7-card-header>
|
||||
|
||||
<f7-card-content class="no-safe-areas" :padding="false">
|
||||
<f7-list>
|
||||
<f7-list-item checkbox class="disabled" title="Account Name">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
</f7-card>
|
||||
|
||||
<f7-card class="skeleton-text" v-if="loading">
|
||||
<f7-card-header>
|
||||
<small :style="{ opacity: 0.6 }">
|
||||
<span>Account Category 2</span>
|
||||
</small>
|
||||
</f7-card-header>
|
||||
|
||||
<f7-card-content class="no-safe-areas" :padding="false">
|
||||
<f7-list>
|
||||
<f7-list-item checkbox class="disabled" title="Account Name">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
<f7-list-item checkbox class="disabled" title="Account Name 2">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
</f7-card>
|
||||
|
||||
<f7-block class="no-padding no-margin" v-if="!loading">
|
||||
<f7-card v-for="accountCategory in allAccountCategories" :key="accountCategory.id" v-show="hasShownAccount(accountCategory)">
|
||||
<f7-card-header>
|
||||
<small :style="{ opacity: 0.6 }">
|
||||
<span>{{ $t(accountCategory.name) }}</span>
|
||||
</small>
|
||||
</f7-card-header>
|
||||
<f7-card-content class="no-safe-areas" :padding="false">
|
||||
<f7-list v-if="categorizedAccounts[accountCategory.id]">
|
||||
<f7-list-item checkbox v-for="account in categorizedAccounts[accountCategory.id].accounts"
|
||||
v-show="!account.hidden"
|
||||
:key="account.id"
|
||||
:title="account.name"
|
||||
:value="account.id"
|
||||
:checked="account | accountOrSubAccountsAllChecked(filterAccountIds)"
|
||||
:indeterminate="account | accountOrSubAccountsHasButNotAllChecked(filterAccountIds)"
|
||||
@change="selectAccountOrSubAccounts">
|
||||
<f7-icon slot="media"
|
||||
:icon="account.icon | accountIcon"
|
||||
:style="account.color | accountIconStyle('var(--default-icon-color)')">
|
||||
</f7-icon>
|
||||
|
||||
<ul slot="root" v-if="account.type === $constants.account.allAccountTypes.MultiSubAccounts" class="padding-left">
|
||||
<f7-list-item checkbox v-for="subAccount in account.subAccounts"
|
||||
v-show="!subAccount.hidden"
|
||||
:key="subAccount.id"
|
||||
:title="subAccount.name"
|
||||
:value="subAccount.id"
|
||||
:checked="subAccount | accountChecked(filterAccountIds) "
|
||||
@change="selectAccount">
|
||||
<f7-icon slot="media"
|
||||
:icon="subAccount.icon | accountIcon"
|
||||
:style="subAccount.color | accountIconStyle('var(--default-icon-color)')">
|
||||
</f7-icon>
|
||||
</f7-list-item>
|
||||
</ul>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
</f7-card>
|
||||
</f7-block>
|
||||
|
||||
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
|
||||
<f7-actions-group>
|
||||
<f7-actions-button @click="selectAll">{{ $t('Select All') }}</f7-actions-button>
|
||||
<f7-actions-button @click="selectNone">{{ $t('Select None') }}</f7-actions-button>
|
||||
<f7-actions-button @click="selectInvert">{{ $t('Invert Selection') }}</f7-actions-button>
|
||||
</f7-actions-group>
|
||||
<f7-actions-group>
|
||||
<f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button>
|
||||
</f7-actions-group>
|
||||
</f7-actions>
|
||||
</f7-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
loading: true,
|
||||
filterAccountIds: {},
|
||||
showMoreActionSheet: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
allAccountCategories() {
|
||||
return this.$constants.account.allCategories;
|
||||
},
|
||||
categorizedAccounts() {
|
||||
return this.$store.state.allCategorizedAccounts;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const self = this;
|
||||
const router = self.$f7router;
|
||||
|
||||
self.$store.dispatch('loadAllAccounts', {
|
||||
force: false
|
||||
}).then(() => {
|
||||
self.loading = false;
|
||||
|
||||
const allAccountIds = {};
|
||||
|
||||
for (let accountId in self.$store.state.allAccountsMap) {
|
||||
if (!Object.prototype.hasOwnProperty.call(self.$store.state.allAccountsMap, accountId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const account = self.$store.state.allAccountsMap[accountId];
|
||||
allAccountIds[account.id] = false;
|
||||
}
|
||||
|
||||
self.filterAccountIds = self.$utilities.copyObjectTo(self.$store.state.transactionStatisticsFilter.filterAccountIds, allAccountIds)
|
||||
}).catch(error => {
|
||||
self.logining = false;
|
||||
|
||||
if (!error.processed) {
|
||||
self.$toast(error.message || error);
|
||||
router.back();
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
const self = this;
|
||||
const router = self.$f7router;
|
||||
|
||||
const filteredAccountIds = {};
|
||||
|
||||
for (let accountId in self.filterAccountIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(self.filterAccountIds, accountId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self.filterAccountIds[accountId]) {
|
||||
filteredAccountIds[accountId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
self.$store.dispatch('updateTransactionStatisticsFilter', {
|
||||
filterAccountIds: filteredAccountIds
|
||||
});
|
||||
|
||||
router.back();
|
||||
},
|
||||
selectAccountOrSubAccounts(e) {
|
||||
const accountId = e.target.value;
|
||||
const account = this.$store.state.allAccountsMap[accountId];
|
||||
|
||||
if (!account) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (account.type === this.$constants.account.allAccountTypes.SingleAccount) {
|
||||
this.filterAccountIds[account.id] = !e.target.checked;
|
||||
} else if (account.type === this.$constants.account.allAccountTypes.MultiSubAccounts) {
|
||||
if (!account.subAccounts || !account.subAccounts.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < account.subAccounts.length; i++) {
|
||||
const subAccount = account.subAccounts[i];
|
||||
this.filterAccountIds[subAccount.id] = !e.target.checked;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectAccount(e) {
|
||||
const accountId = e.target.value;
|
||||
const account = this.$store.state.allAccountsMap[accountId];
|
||||
|
||||
if (!account) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filterAccountIds[account.id] = !e.target.checked;
|
||||
},
|
||||
selectAll() {
|
||||
for (let accountId in this.filterAccountIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.filterAccountIds, accountId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const account = this.$store.state.allAccountsMap[accountId];
|
||||
|
||||
if (account && account.type === this.$constants.account.allAccountTypes.SingleAccount) {
|
||||
this.filterAccountIds[account.id] = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectNone() {
|
||||
for (let accountId in this.filterAccountIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.filterAccountIds, accountId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const account = this.$store.state.allAccountsMap[accountId];
|
||||
|
||||
if (account && account.type === this.$constants.account.allAccountTypes.SingleAccount) {
|
||||
this.filterAccountIds[account.id] = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectInvert() {
|
||||
for (let accountId in this.filterAccountIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.filterAccountIds, accountId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const account = this.$store.state.allAccountsMap[accountId];
|
||||
|
||||
if (account && account.type === this.$constants.account.allAccountTypes.SingleAccount) {
|
||||
this.filterAccountIds[account.id] = !this.filterAccountIds[account.id];
|
||||
}
|
||||
}
|
||||
},
|
||||
hasShownAccount(accountCategory) {
|
||||
if (!this.categorizedAccounts[accountCategory.id] ||
|
||||
!this.categorizedAccounts[accountCategory.id].accounts ||
|
||||
!this.categorizedAccounts[accountCategory.id].accounts.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.categorizedAccounts[accountCategory.id].accounts.length; i++) {
|
||||
const account = this.categorizedAccounts[accountCategory.id].accounts[i];
|
||||
|
||||
if (!account.hidden) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
accountChecked(account, filterAccountIds) {
|
||||
return !filterAccountIds[account.id];
|
||||
},
|
||||
accountOrSubAccountsAllChecked(account, filterAccountIds) {
|
||||
if (!account.subAccounts) {
|
||||
return !filterAccountIds[account.id];
|
||||
}
|
||||
|
||||
for (let i = 0; i < account.subAccounts.length; i++) {
|
||||
const subAccount = account.subAccounts[i];
|
||||
if (filterAccountIds[subAccount.id]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
accountOrSubAccountsHasButNotAllChecked(account, filterAccountIds) {
|
||||
if (!account.subAccounts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let checkedCount = 0;
|
||||
|
||||
for (let i = 0; i < account.subAccounts.length; i++) {
|
||||
const subAccount = account.subAccounts[i];
|
||||
if (!filterAccountIds[subAccount.id]) {
|
||||
checkedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return checkedCount > 0 && checkedCount < account.subAccounts.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,277 @@
|
||||
<template>
|
||||
<f7-page>
|
||||
<f7-navbar>
|
||||
<f7-nav-left :back-link="$t('Back')"></f7-nav-left>
|
||||
<f7-nav-title :title="$t('Filter Transaction Categories')"></f7-nav-title>
|
||||
<f7-nav-right>
|
||||
<f7-link icon-f7="ellipsis" @click="showMoreActionSheet = true"></f7-link>
|
||||
<f7-link :text="$t('Save')" @click="save"></f7-link>
|
||||
</f7-nav-right>
|
||||
</f7-navbar>
|
||||
|
||||
<f7-card class="skeleton-text" v-if="loading">
|
||||
<f7-card-header>
|
||||
<small :style="{ opacity: 0.6 }">
|
||||
<span>Transaction Category</span>
|
||||
</small>
|
||||
</f7-card-header>
|
||||
<f7-card-content class="no-safe-areas" :padding="false">
|
||||
<f7-list>
|
||||
<f7-list-item checkbox class="disabled" title="Category Name">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
<ul slot="root" class="padding-left">
|
||||
<f7-list-item checkbox class="disabled" title="Sub Category Name">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
<f7-list-item checkbox class="disabled" title="Sub Category Name 2">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
<f7-list-item checkbox class="disabled" title="Sub Category Name 3">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
</ul>
|
||||
</f7-list-item>
|
||||
<f7-list-item checkbox class="disabled" title="Category Name 2">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
<ul slot="root" class="padding-left">
|
||||
<f7-list-item checkbox class="disabled" title="Sub Category Name">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
<f7-list-item checkbox class="disabled" title="Sub Category Name 2">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
<f7-list-item checkbox class="disabled" title="Sub Category Name 3">
|
||||
<f7-icon slot="media" f7="app_fill"></f7-icon>
|
||||
</f7-list-item>
|
||||
</ul>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
</f7-card>
|
||||
|
||||
<f7-block class="no-padding no-margin" v-if="!loading">
|
||||
<f7-card v-for="(categories, categoryType) in allTransactionCategories" :key="categoryType">
|
||||
<f7-card-header>
|
||||
<small :style="{ opacity: 0.6 }">
|
||||
<span>{{ categoryType | categoryTypeName($constants.category.allCategoryTypes) | localized }}</span>
|
||||
</small>
|
||||
</f7-card-header>
|
||||
<f7-card-content class="no-safe-areas" :padding="false">
|
||||
<f7-list>
|
||||
<f7-list-item checkbox v-for="category in categories"
|
||||
v-show="!category.hidden"
|
||||
:key="category.id"
|
||||
:title="category.name"
|
||||
:value="category.id"
|
||||
:checked="category | subCategoriesAllChecked(filterCategoryIds)"
|
||||
:indeterminate="category | subCategoriesHasButNotAllChecked(filterCategoryIds)"
|
||||
@change="selectSubCategories">
|
||||
<f7-icon slot="media"
|
||||
:icon="category.icon | categoryIcon"
|
||||
:style="category.color | categoryIconStyle('var(--default-icon-color)')">
|
||||
</f7-icon>
|
||||
|
||||
<ul slot="root" v-if="category.subCategories.length" class="padding-left">
|
||||
<f7-list-item checkbox v-for="subCategory in category.subCategories"
|
||||
v-show="!subCategory.hidden"
|
||||
:key="subCategory.id"
|
||||
:title="subCategory.name"
|
||||
:value="subCategory.id"
|
||||
:checked="subCategory | categoryChecked(filterCategoryIds) "
|
||||
@change="selectCategory">
|
||||
<f7-icon slot="media"
|
||||
:icon="subCategory.icon | categoryIcon"
|
||||
:style="subCategory.color | categoryIconStyle('var(--default-icon-color)')">
|
||||
</f7-icon>
|
||||
</f7-list-item>
|
||||
</ul>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
</f7-card>
|
||||
</f7-block>
|
||||
|
||||
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
|
||||
<f7-actions-group>
|
||||
<f7-actions-button @click="selectAll">{{ $t('Select All') }}</f7-actions-button>
|
||||
<f7-actions-button @click="selectNone">{{ $t('Select None') }}</f7-actions-button>
|
||||
<f7-actions-button @click="selectInvert">{{ $t('Invert Selection') }}</f7-actions-button>
|
||||
</f7-actions-group>
|
||||
<f7-actions-group>
|
||||
<f7-actions-button bold close>{{ $t('Cancel') }}</f7-actions-button>
|
||||
</f7-actions-group>
|
||||
</f7-actions>
|
||||
</f7-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
loading: true,
|
||||
filterCategoryIds: {},
|
||||
showMoreActionSheet: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
allTransactionCategories: function () {
|
||||
return this.$store.state.allTransactionCategories;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const self = this;
|
||||
const router = self.$f7router;
|
||||
|
||||
self.$store.dispatch('loadAllCategories', {
|
||||
force: false
|
||||
}).then(() => {
|
||||
self.loading = false;
|
||||
|
||||
const allCategoryIds = {};
|
||||
|
||||
for (let categoryId in self.$store.state.allTransactionCategoriesMap) {
|
||||
if (!Object.prototype.hasOwnProperty.call(self.$store.state.allTransactionCategoriesMap, categoryId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const category = self.$store.state.allTransactionCategoriesMap[categoryId];
|
||||
allCategoryIds[category.id] = false;
|
||||
}
|
||||
|
||||
self.filterCategoryIds = self.$utilities.copyObjectTo(self.$store.state.transactionStatisticsFilter.filterCategoryIds, allCategoryIds)
|
||||
}).catch(error => {
|
||||
self.logining = false;
|
||||
|
||||
if (!error.processed) {
|
||||
self.$toast(error.message || error);
|
||||
router.back();
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
const self = this;
|
||||
const router = self.$f7router;
|
||||
|
||||
const filteredCategoryIds = {};
|
||||
|
||||
for (let categoryId in self.filterCategoryIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(self.filterCategoryIds, categoryId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self.filterCategoryIds[categoryId]) {
|
||||
filteredCategoryIds[categoryId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
self.$store.dispatch('updateTransactionStatisticsFilter', {
|
||||
filterCategoryIds: filteredCategoryIds
|
||||
});
|
||||
|
||||
router.back();
|
||||
},
|
||||
selectCategory(e) {
|
||||
const categoryId = e.target.value;
|
||||
const category = this.$store.state.allTransactionCategoriesMap[categoryId];
|
||||
|
||||
if (!category) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filterCategoryIds[category.id] = !e.target.checked;
|
||||
},
|
||||
selectSubCategories(e) {
|
||||
const categoryId = e.target.value;
|
||||
const category = this.$store.state.allTransactionCategoriesMap[categoryId];
|
||||
|
||||
if (!category || !category.subCategories || !category.subCategories.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < category.subCategories.length; i++) {
|
||||
const subCategory = category.subCategories[i];
|
||||
this.filterCategoryIds[subCategory.id] = !e.target.checked;
|
||||
}
|
||||
},
|
||||
selectAll() {
|
||||
for (let categoryId in this.filterCategoryIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.filterCategoryIds, categoryId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const category = this.$store.state.allTransactionCategoriesMap[categoryId];
|
||||
|
||||
if (category) {
|
||||
this.filterCategoryIds[category.id] = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectNone() {
|
||||
for (let categoryId in this.filterCategoryIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.filterCategoryIds, categoryId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const category = this.$store.state.allTransactionCategoriesMap[categoryId];
|
||||
|
||||
if (category) {
|
||||
this.filterCategoryIds[category.id] = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
selectInvert() {
|
||||
for (let categoryId in this.filterCategoryIds) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.filterCategoryIds, categoryId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const category = this.$store.state.allTransactionCategoriesMap[categoryId];
|
||||
|
||||
if (category) {
|
||||
this.filterCategoryIds[category.id] = !this.filterCategoryIds[category.id];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
categoryTypeName(categoryType, allCategoryTypes) {
|
||||
switch (categoryType) {
|
||||
case allCategoryTypes.Income.toString():
|
||||
return 'Income Categories';
|
||||
case allCategoryTypes.Expense.toString():
|
||||
return 'Expense Categories';
|
||||
case allCategoryTypes.Transfer.toString():
|
||||
return 'Transfer Categories';
|
||||
default:
|
||||
return 'Transaction Categories';
|
||||
}
|
||||
},
|
||||
categoryChecked(category, filterCategoryIds) {
|
||||
return !filterCategoryIds[category.id];
|
||||
},
|
||||
subCategoriesAllChecked(category, filterCategoryIds) {
|
||||
for (let i = 0; i < category.subCategories.length; i++) {
|
||||
const subCategory = category.subCategories[i];
|
||||
if (filterCategoryIds[subCategory.id]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
subCategoriesHasButNotAllChecked(category, filterCategoryIds) {
|
||||
let checkedCount = 0;
|
||||
|
||||
for (let i = 0; i < category.subCategories.length; i++) {
|
||||
const subCategory = category.subCategories[i];
|
||||
if (!filterCategoryIds[subCategory.id]) {
|
||||
checkedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return checkedCount > 0 && checkedCount < category.subCategories.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -231,6 +231,10 @@
|
||||
</date-range-selection-sheet>
|
||||
|
||||
<f7-actions close-by-outside-click close-on-escape :opened="showMoreActionSheet" @actions:closed="showMoreActionSheet = false">
|
||||
<f7-actions-group>
|
||||
<f7-actions-button @click="filterAccounts">{{ $t('Filter Accounts') }}</f7-actions-button>
|
||||
<f7-actions-button @click="filterCategories">{{ $t('Filter Transaction Categories') }}</f7-actions-button>
|
||||
</f7-actions-group>
|
||||
<f7-actions-group>
|
||||
<f7-actions-button @click="settings">{{ $t('Settings') }}</f7-actions-button>
|
||||
</f7-actions-group>
|
||||
@@ -535,6 +539,12 @@ export default {
|
||||
clickPieChartItem(item) {
|
||||
this.$f7router.navigate(this.$options.filters.itemLinkUrl(item, this.query, this.$constants.statistics.allChartDataTypes));
|
||||
},
|
||||
filterAccounts() {
|
||||
this.$f7router.navigate('/statistic/filter/account');
|
||||
},
|
||||
filterCategories() {
|
||||
this.$f7router.navigate('/statistic/filter/category');
|
||||
},
|
||||
settings() {
|
||||
this.$f7router.navigate('/statistic/settings');
|
||||
},
|
||||
@@ -565,6 +575,14 @@ export default {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.query.filterAccountIds && this.query.filterAccountIds[item.account.id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.query.filterCategoryIds && this.query.filterCategoryIds[item.category.id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.query.chartDataType === this.$constants.statistics.allChartDataTypes.ExpenseByAccount.type ||
|
||||
this.query.chartDataType === this.$constants.statistics.allChartDataTypes.IncomeByAccount.type) {
|
||||
if (this.$utilities.isNumber(item.amountInDefaultCurrency)) {
|
||||
@@ -656,6 +674,10 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.query.filterAccountIds && this.query.filterAccountIds[account.id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let primaryAccount = this.$store.state.allAccountsMap[account.parentId];
|
||||
|
||||
if (!primaryAccount) {
|
||||
|
||||
Reference in New Issue
Block a user