support setting account/transaction category filter for statistics page

This commit is contained in:
MaysWind
2023-07-15 16:21:42 +08:00
parent 39451f0e37
commit 015725f88c
5 changed files with 798 additions and 14 deletions
+3
View File
@@ -11,6 +11,7 @@ import { VBtn } from 'vuetify/components/VBtn';
import { VBtnGroup } from 'vuetify/components/VBtnGroup';
import { VBtnToggle } from 'vuetify/components/VBtnToggle';
import { VCard, VCardActions, VCardItem, VCardSubtitle, VCardText, VCardTitle } from 'vuetify/components/VCard';
import { VCheckbox, VCheckboxBtn } from 'vuetify/components/VCheckbox';
import { VChip } from 'vuetify/components/VChip';
import { VDialog } from 'vuetify/components/VDialog';
import { VDivider } from 'vuetify/components/VDivider';
@@ -109,6 +110,8 @@ const vuetify = createVuetify({
VCardSubtitle,
VCardText,
VCardTitle,
VCheckbox,
VCheckboxBtn,
VChip,
VDialog,
VDivider,
@@ -62,15 +62,11 @@
</v-col>
<v-col cols="12">
<v-card :title="$t('Default Account Filter')">
</v-card>
<account-filter-settings-card :auto-save="true" :modify-default="true" />
</v-col>
<v-col cols="12">
<v-card :title="$t('Default Transaction Category Filter')">
</v-card>
<category-filter-settings-card :auto-save="true" :modify-default="true" />
</v-col>
</v-row>
</template>
@@ -81,7 +77,14 @@ import { useSettingsStore } from '@/stores/setting.js';
import statisticsConstants from '@/consts/statistics.js';
import AccountFilterSettingsCard from '@/views/desktop/statistics/AccountFilterSettingsCard.vue';
import CategoryFilterSettingsCard from '@/views/desktop/statistics/CategoryFilterSettingsCard.vue';
export default {
components: {
AccountFilterSettingsCard,
CategoryFilterSettingsCard
},
computed: {
...mapStores(useSettingsStore),
allChartTypes() {
@@ -0,0 +1,366 @@
<template>
<v-card>
<v-toolbar color="primary" v-if="dialogMode">
<v-toolbar-title>{{ $t('Default Account Filter') }}</v-toolbar-title>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
:disabled="loading" :icon="true">
<v-icon :icon="icons.more" />
<v-menu activator="parent">
<v-list>
<v-list-item :prepend-icon="icons.selectAll"
:title="$t('Select All')"
@click="selectAll"></v-list-item>
<v-list-item :prepend-icon="icons.selectNone"
:title="$t('Select None')"
@click="selectNone"></v-list-item>
<v-list-item :prepend-icon="icons.selectInverse"
:title="$t('Invert Selection')"
@click="selectInvert"></v-list-item>
</v-list>
</v-menu>
</v-btn>
</v-toolbar>
<template #title v-if="!dialogMode">
<div class="d-flex align-center">
<span>{{ $t('Default Account Filter') }}</span>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
:disabled="loading" :icon="true">
<v-icon :icon="icons.more" />
<v-menu activator="parent">
<v-list>
<v-list-item :prepend-icon="icons.selectAll"
:title="$t('Select All')"
@click="selectAll"></v-list-item>
<v-list-item :prepend-icon="icons.selectNone"
:title="$t('Select None')"
@click="selectNone"></v-list-item>
<v-list-item :prepend-icon="icons.selectInverse"
:title="$t('Invert Selection')"
@click="selectInvert"></v-list-item>
</v-list>
</v-menu>
</v-btn>
</div>
</template>
<v-card-text v-if="loading">
<v-skeleton-loader type="paragraph" :loading="loading"
:key="itemIdx" v-for="itemIdx in [ 1, 2, 3 ]"></v-skeleton-loader>
</v-card-text>
<v-card-text v-if="!loading && !hasAnyAvailableAccount">
<span class="text-subtitle-1">{{ $t('No available account') }}</span>
</v-card-text>
<v-card-text v-else-if="!loading && hasAnyAvailableAccount">
<v-expansion-panels class="account-categories" multiple v-model="expandAccountCategories">
<v-expansion-panel :key="accountCategory.category"
:value="accountCategory.category"
class="border"
v-for="accountCategory in allVisibleCategorizedAccounts">
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
<span class="ml-3">{{ $t(accountCategory.name) }}</span>
</v-expansion-panel-title>
<v-expansion-panel-text>
<v-list rounded density="comfortable" class="pa-0">
<template :key="account.id"
v-for="(account, idx) in accountCategory.visibleAccounts">
<v-list-item>
<template #prepend>
<v-checkbox :model-value="isAccountOrSubAccountsAllChecked(account, filterAccountIds)"
:indeterminate="isAccountOrSubAccountsHasButNotAllChecked(account, filterAccountIds)"
@update:model-value="selectAccountOrSubAccounts(account, $event)">
<template #label>
<ItemIcon class="d-flex" icon-type="account"
:icon-id="account.icon" :color="account.color"></ItemIcon>
<span class="ml-3">{{ account.name }}</span>
</template>
</v-checkbox>
</template>
</v-list-item>
<v-divider v-if="account.type === allAccountTypes.MultiSubAccounts && accountCategory.visibleSubAccounts[account.id]"/>
<v-list rounded density="comfortable" class="pa-0 ml-4"
v-if="account.type === allAccountTypes.MultiSubAccounts && accountCategory.visibleSubAccounts[account.id]">
<template :key="subAccount.id"
v-for="(subAccount, subIdx) in accountCategory.visibleSubAccounts[account.id]">
<v-list-item>
<template #prepend>
<v-checkbox :model-value="isAccountChecked(subAccount, filterAccountIds)"
@update:model-value="selectAccount(subAccount, $event)">
<template #label>
<ItemIcon class="d-flex" icon-type="account"
:icon-id="subAccount.icon" :color="subAccount.color"></ItemIcon>
<span class="ml-3">{{ subAccount.name }}</span>
</template>
</v-checkbox>
</template>
</v-list-item>
<v-divider v-if="subIdx !== accountCategory.visibleSubAccounts[account.id].length - 1"/>
</template>
</v-list>
<v-divider v-if="idx !== accountCategory.visibleAccounts.length - 1"/>
</template>
</v-list>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</v-card-text>
<v-card-actions class="mt-3" v-if="dialogMode">
<v-spacer></v-spacer>
<v-btn color="gray" @click="cancel">{{ $t('Cancel') }}</v-btn>
<v-btn color="primary" @click="save">{{ $t('OK') }}</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useAccountsStore } from '@/stores/account.js';
import { useStatisticsStore } from '@/stores/statistics.js';
import accountConstants from '@/consts/account.js';
import { copyObjectTo } from '@/lib/common.js';
import { getVisibleCategorizedAccounts } from '@/lib/account.js';
import {
mdiSelectAll,
mdiSelect,
mdiSelectInverse,
mdiDotsVertical
} from '@mdi/js';
export default {
props: [
'dialogMode',
'modifyDefault',
'autoSave'
],
emits: [
'settings:change'
],
data: function () {
return {
loading: true,
expandAccountCategories: accountConstants.allCategories.map(category => category.id),
filterAccountIds: {},
icons: {
selectAll: mdiSelectAll,
selectNone: mdiSelect,
selectInverse: mdiSelectInverse,
more: mdiDotsVertical
}
}
},
computed: {
...mapStores(useSettingsStore, useAccountsStore, useStatisticsStore),
title() {
if (this.modifyDefault) {
return 'Default Account Filter';
} else {
return 'Filter Accounts';
}
},
applyText() {
if (this.modifyDefault) {
return 'Save';
} else {
return 'Apply';
}
},
allAccountTypes() {
return accountConstants.allAccountTypes;
},
allVisibleCategorizedAccounts() {
return getVisibleCategorizedAccounts(this.accountsStore.allCategorizedAccounts);
},
hasAnyAvailableAccount() {
return this.accountsStore.allVisibleAccountsCount > 0;
}
},
created() {
const self = this;
self.accountsStore.loadAllAccounts({
force: false
}).then(() => {
self.loading = false;
const allAccountIds = {};
for (let accountId in self.accountsStore.allAccountsMap) {
if (!Object.prototype.hasOwnProperty.call(self.accountsStore.allAccountsMap, accountId)) {
continue;
}
const account = self.accountsStore.allAccountsMap[accountId];
allAccountIds[account.id] = false;
}
if (self.modifyDefault) {
self.filterAccountIds = copyObjectTo(self.settingsStore.appSettings.statistics.defaultAccountFilter, allAccountIds);
} else {
self.filterAccountIds = copyObjectTo(self.statisticsStore.transactionStatisticsFilter.filterAccountIds, allAccountIds);
}
}).catch(error => {
self.loading = false;
if (!error.processed) {
self.$refs.snackbar.showError(error);
}
});
},
methods: {
save() {
const self = this;
const filteredAccountIds = {};
for (let accountId in self.filterAccountIds) {
if (!Object.prototype.hasOwnProperty.call(self.filterAccountIds, accountId)) {
continue;
}
if (self.filterAccountIds[accountId]) {
filteredAccountIds[accountId] = true;
}
}
if (self.modifyDefault) {
self.settingsStore.setStatisticsDefaultAccountFilter(filteredAccountIds);
} else {
self.statisticsStore.updateTransactionStatisticsFilter({
filterAccountIds: filteredAccountIds
});
}
this.$emit('settings:change', true);
},
cancel() {
this.$emit('settings:change', false);
},
selectAccountOrSubAccounts(account, value) {
if (account.type === this.allAccountTypes.SingleAccount) {
this.filterAccountIds[account.id] = !value;
} else if (account.type === this.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] = !value;
}
}
if (this.autoSave) {
this.save();
}
},
selectAccount(account, value) {
this.filterAccountIds[account.id] = !value;
if (this.autoSave) {
this.save();
}
},
selectAll() {
for (let accountId in this.filterAccountIds) {
if (!Object.prototype.hasOwnProperty.call(this.filterAccountIds, accountId)) {
continue;
}
const account = this.accountsStore.allAccountsMap[accountId];
if (account && account.type === this.allAccountTypes.SingleAccount) {
this.filterAccountIds[account.id] = false;
}
}
if (this.autoSave) {
this.save();
}
},
selectNone() {
for (let accountId in this.filterAccountIds) {
if (!Object.prototype.hasOwnProperty.call(this.filterAccountIds, accountId)) {
continue;
}
const account = this.accountsStore.allAccountsMap[accountId];
if (account && account.type === this.allAccountTypes.SingleAccount) {
this.filterAccountIds[account.id] = true;
}
}
if (this.autoSave) {
this.save();
}
},
selectInvert() {
for (let accountId in this.filterAccountIds) {
if (!Object.prototype.hasOwnProperty.call(this.filterAccountIds, accountId)) {
continue;
}
const account = this.accountsStore.allAccountsMap[accountId];
if (account && account.type === this.allAccountTypes.SingleAccount) {
this.filterAccountIds[account.id] = !this.filterAccountIds[account.id];
}
}
if (this.autoSave) {
this.save();
}
},
isAccountChecked(account, filterAccountIds) {
return !filterAccountIds[account.id];
},
isAccountOrSubAccountsAllChecked(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;
},
isAccountOrSubAccountsHasButNotAllChecked(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>
<style>
.account-categories .v-expansion-panel-text__wrapper {
padding: 0 0 0 20px;
}
</style>
@@ -0,0 +1,396 @@
<template>
<v-card>
<v-toolbar color="primary" v-if="dialogMode">
<v-toolbar-title>{{ $t('Default Transaction Category Filter') }}</v-toolbar-title>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
:disabled="loading" :icon="true">
<v-icon :icon="icons.more" />
<v-menu activator="parent">
<v-list>
<v-list-item :prepend-icon="icons.selectAll"
:title="$t('Select All')"
@click="selectAll"></v-list-item>
<v-list-item :prepend-icon="icons.selectNone"
:title="$t('Select None')"
@click="selectNone"></v-list-item>
<v-list-item :prepend-icon="icons.selectInverse"
:title="$t('Invert Selection')"
@click="selectInvert"></v-list-item>
</v-list>
</v-menu>
</v-btn>
</v-toolbar>
<template #title v-if="!dialogMode">
<div class="d-flex align-center">
<span>{{ $t('Default Transaction Category Filter') }}</span>
<v-spacer/>
<v-btn density="comfortable" color="default" variant="text" class="ml-2"
:disabled="loading" :icon="true">
<v-icon :icon="icons.more" />
<v-menu activator="parent">
<v-list>
<v-list-item :prepend-icon="icons.selectAll"
:title="$t('Select All')"
@click="selectAll"></v-list-item>
<v-list-item :prepend-icon="icons.selectNone"
:title="$t('Select None')"
@click="selectNone"></v-list-item>
<v-list-item :prepend-icon="icons.selectInverse"
:title="$t('Invert Selection')"
@click="selectInvert"></v-list-item>
</v-list>
</v-menu>
</v-btn>
</div>
</template>
<v-card-text v-if="loading">
<v-skeleton-loader type="paragraph" :loading="loading"
:key="itemIdx" v-for="itemIdx in [ 1, 2, 3 ]"></v-skeleton-loader>
</v-card-text>
<v-card-text v-else-if="!loading">
<v-expansion-panels class="category-types" multiple v-model="expandCategoryTypes">
<v-expansion-panel :key="transactionType.type"
:value="transactionType.type"
class="border"
v-for="transactionType in allVisibleTransactionCategories">
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
<span class="ml-3">{{ getCategoryTypeName(transactionType.type) }}</span>
</v-expansion-panel-title>
<v-expansion-panel-text>
<v-list rounded density="comfortable" class="pa-0">
<div class="py-3" v-if="!hasAvailableCategory[transactionType.type]">{{ $t('No available category') }}</div>
<template :key="category.id"
v-for="(category, idx) in transactionType.visibleCategories">
<v-list-item>
<template #prepend>
<v-checkbox :model-value="isSubCategoriesAllChecked(category, filterCategoryIds)"
:indeterminate="isSubCategoriesHasButNotAllChecked(category, filterCategoryIds)"
@update:model-value="selectSubCategories(category, $event)">
<template #label>
<ItemIcon class="d-flex" icon-type="category"
:icon-id="category.icon" :color="category.color"></ItemIcon>
<span class="ml-3">{{ category.name }}</span>
</template>
</v-checkbox>
</template>
</v-list-item>
<v-divider v-if="transactionType.visibleSubCategories[category.id]"/>
<v-list rounded density="comfortable" class="pa-0 ml-4"
v-if="transactionType.visibleSubCategories[category.id]">
<template :key="subCategory.id"
v-for="(subCategory, subIdx) in transactionType.visibleSubCategories[category.id]">
<v-list-item>
<template #prepend>
<v-checkbox :model-value="isCategoryChecked(subCategory, filterCategoryIds)"
@update:model-value="selectCategory(subCategory, $event)">
<template #label>
<ItemIcon class="d-flex" icon-type="category"
:icon-id="subCategory.icon" :color="subCategory.color"></ItemIcon>
<span class="ml-3">{{ subCategory.name }}</span>
</template>
</v-checkbox>
</template>
</v-list-item>
<v-divider v-if="subIdx !== transactionType.visibleSubCategories[category.id].length - 1"/>
</template>
</v-list>
<v-divider v-if="idx !== transactionType.visibleCategories - 1"/>
</template>
</v-list>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</v-card-text>
<v-card-actions class="mt-3" v-if="dialogMode">
<v-spacer></v-spacer>
<v-btn color="gray" @click="cancel">{{ $t('Cancel') }}</v-btn>
<v-btn color="primary" @click="save">{{ $t('OK') }}</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
import { useStatisticsStore } from '@/stores/statistics.js';
import categoryConstants from '@/consts/category.js';
import { copyObjectTo } from '@/lib/common.js';
import { allVisibleTransactionCategories } from '@/lib/category.js';
import {
mdiSelectAll,
mdiSelect,
mdiSelectInverse,
mdiDotsVertical
} from '@mdi/js';
export default {
props: [
'dialogMode',
'modifyDefault',
'autoSave'
],
emits: [
'settings:change'
],
data: function () {
return {
loading: true,
expandCategoryTypes: [
categoryConstants.allCategoryTypes.Income.toString(),
categoryConstants.allCategoryTypes.Expense.toString(),
categoryConstants.allCategoryTypes.Transfer.toString()
],
filterCategoryIds: {},
icons: {
selectAll: mdiSelectAll,
selectNone: mdiSelect,
selectInverse: mdiSelectInverse,
more: mdiDotsVertical
}
}
},
computed: {
...mapStores(useSettingsStore, useTransactionCategoriesStore, useStatisticsStore),
title() {
if (this.modifyDefault) {
return 'Default Transaction Category Filter';
} else {
return 'Filter Transaction Categories';
}
},
applyText() {
if (this.modifyDefault) {
return 'Save';
} else {
return 'Apply';
}
},
allVisibleTransactionCategories() {
return allVisibleTransactionCategories(this.transactionCategoriesStore.allTransactionCategories);
},
hasAnyAvailableCategory() {
for (let type in this.allVisibleTransactionCategories) {
if (!Object.prototype.hasOwnProperty.call(this.allVisibleTransactionCategories, type)) {
continue;
}
const categoryType = this.allVisibleTransactionCategories[type];
if (categoryType.visibleCategories && categoryType.visibleCategories.length > 0) {
return true;
}
}
return false;
},
hasAvailableCategory() {
const result = {};
for (let type in this.allVisibleTransactionCategories) {
if (!Object.prototype.hasOwnProperty.call(this.allVisibleTransactionCategories, type)) {
continue;
}
const categoryType = this.allVisibleTransactionCategories[type];
result[type] = categoryType.visibleCategories && categoryType.visibleCategories.length > 0;
}
return result;
}
},
created() {
const self = this;
self.transactionCategoriesStore.loadAllCategories({
force: false
}).then(() => {
self.loading = false;
const allCategoryIds = {};
for (let categoryId in self.transactionCategoriesStore.allTransactionCategoriesMap) {
if (!Object.prototype.hasOwnProperty.call(self.transactionCategoriesStore.allTransactionCategoriesMap, categoryId)) {
continue;
}
const category = self.transactionCategoriesStore.allTransactionCategoriesMap[categoryId];
allCategoryIds[category.id] = false;
}
if (self.modifyDefault) {
self.filterCategoryIds = copyObjectTo(self.settingsStore.appSettings.statistics.defaultTransactionCategoryFilter, allCategoryIds);
} else {
self.filterCategoryIds = copyObjectTo(self.statisticsStore.transactionStatisticsFilter.filterCategoryIds, allCategoryIds);
}
}).catch(error => {
self.loading = false;
if (!error.processed) {
self.$refs.snackbar.showError(error);
}
});
},
methods: {
save() {
const self = this;
const filteredCategoryIds = {};
for (let categoryId in self.filterCategoryIds) {
if (!Object.prototype.hasOwnProperty.call(self.filterCategoryIds, categoryId)) {
continue;
}
if (self.filterCategoryIds[categoryId]) {
filteredCategoryIds[categoryId] = true;
}
}
if (self.modifyDefault) {
self.settingsStore.setStatisticsDefaultTransactionCategoryFilter(filteredCategoryIds);
} else {
self.statisticsStore.updateTransactionStatisticsFilter({
filterCategoryIds: filteredCategoryIds
});
}
this.$emit('settings:change', true);
},
cancel() {
this.$emit('settings:change', false);
},
selectCategory(category, value) {
if (!category) {
return;
}
this.filterCategoryIds[category.id] = !value;
if (this.autoSave) {
this.save();
}
},
selectSubCategories(category, value) {
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] = !value;
}
if (this.autoSave) {
this.save();
}
},
selectAll() {
for (let categoryId in this.filterCategoryIds) {
if (!Object.prototype.hasOwnProperty.call(this.filterCategoryIds, categoryId)) {
continue;
}
const category = this.transactionCategoriesStore.allTransactionCategoriesMap[categoryId];
if (category) {
this.filterCategoryIds[category.id] = false;
}
}
if (this.autoSave) {
this.save();
}
},
selectNone() {
for (let categoryId in this.filterCategoryIds) {
if (!Object.prototype.hasOwnProperty.call(this.filterCategoryIds, categoryId)) {
continue;
}
const category = this.transactionCategoriesStore.allTransactionCategoriesMap[categoryId];
if (category) {
this.filterCategoryIds[category.id] = true;
}
}
if (this.autoSave) {
this.save();
}
},
selectInvert() {
for (let categoryId in this.filterCategoryIds) {
if (!Object.prototype.hasOwnProperty.call(this.filterCategoryIds, categoryId)) {
continue;
}
const category = this.transactionCategoriesStore.allTransactionCategoriesMap[categoryId];
if (category) {
this.filterCategoryIds[category.id] = !this.filterCategoryIds[category.id];
}
}
if (this.autoSave) {
this.save();
}
},
getCategoryTypeName(categoryType) {
switch (categoryType) {
case categoryConstants.allCategoryTypes.Income.toString():
return this.$t('Income Categories');
case categoryConstants.allCategoryTypes.Expense.toString():
return this.$t('Expense Categories');
case categoryConstants.allCategoryTypes.Transfer.toString():
return this.$t('Transfer Categories');
default:
return this.$t('Transaction Categories');
}
},
isCategoryChecked(category, filterCategoryIds) {
return !filterCategoryIds[category.id];
},
isSubCategoriesAllChecked(category, filterCategoryIds) {
for (let i = 0; i < category.subCategories.length; i++) {
const subCategory = category.subCategories[i];
if (filterCategoryIds[subCategory.id]) {
return false;
}
}
return true;
},
isSubCategoriesHasButNotAllChecked(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>
<style>
.category-types .v-expansion-panel-text__wrapper {
padding: 0 0 0 20px;
}
</style>
@@ -105,10 +105,10 @@
<v-list>
<v-list-item :prepend-icon="icons.filter"
:title="$t('Filter Accounts')"
@click="filterAccounts"></v-list-item>
@click="showFilterAccountDialog = true"></v-list-item>
<v-list-item :prepend-icon="icons.filter"
:title="$t('Filter Transaction Categories')"
@click="filterCategories"></v-list-item>
@click="showFilterCategoryDialog = true"></v-list-item>
<v-divider class="my-2"/>
<v-list-item :prepend-icon="icons.filterSettings"
:title="$t('Settings')"
@@ -199,6 +199,19 @@
:max-time="query.endTime"
v-model:show="showCustomDateRangeDialog"
@dateRange:change="setCustomDateFilter" />
<v-dialog scrollable max-width="600" max-height="600" v-model="showFilterAccountDialog">
<account-filter-settings-card
:dialog-mode="true" :modify-default="false"
@settings:change="showFilterAccountDialog = false" />
</v-dialog>
<v-dialog scrollable max-width="600" max-height="600" v-model="showFilterCategoryDialog">
<category-filter-settings-card
:dialog-mode="true" :modify-default="false"
@settings:change="showFilterCategoryDialog = false" />
</v-dialog>
<snack-bar ref="snackbar" />
</template>
@@ -234,13 +247,22 @@ import {
mdiDotsVertical,
} from '@mdi/js';
import AccountFilterSettingsCard from '@/views/desktop/statistics/AccountFilterSettingsCard.vue';
import CategoryFilterSettingsCard from '@/views/desktop/statistics/CategoryFilterSettingsCard.vue';
export default {
components: {
AccountFilterSettingsCard,
CategoryFilterSettingsCard
},
data() {
return {
activeTab: 'statisticsPage',
initing: true,
loading: true,
showCustomDateRangeDialog: false,
showFilterAccountDialog: false,
showFilterCategoryDialog: false,
icons: {
check: mdiCheck,
left: mdiArrowLeft,
@@ -576,12 +598,6 @@ export default {
},
clickPieChartItem(item) {
this.$router.push(this.getItemLinkUrl(item));
},
filterAccounts() {
},
filterCategories() {
},
settings() {
this.$router.push('/app/settings?tab=statisticsSetting');