support creating transaction from template

This commit is contained in:
MaysWind
2024-08-04 00:58:25 +08:00
parent 889225301c
commit fcb954ff40
4 changed files with 94 additions and 11 deletions
+29 -4
View File
@@ -41,7 +41,18 @@
</v-btn> </v-btn>
<span>{{ $t('Transaction List') }}</span> <span>{{ $t('Transaction List') }}</span>
<v-btn class="ml-3" color="default" variant="outlined" <v-btn class="ml-3" color="default" variant="outlined"
:disabled="loading || !canAddTransaction" @click="add">{{ $t('Add') }}</v-btn> :disabled="loading || !canAddTransaction" @click="add">
{{ $t('Add') }}
<v-menu activator="parent" :open-on-hover="true" v-if="allTransactionTemplates && allTransactionTemplates.length">
<v-list>
<v-list-item :title="template.name"
:prepend-icon="icons.templates"
:key="template.id"
v-for="template in allTransactionTemplates"
@click="add(template)"></v-list-item>
</v-list>
</v-menu>
</v-btn>
<v-btn density="compact" color="default" variant="text" size="24" <v-btn density="compact" color="default" variant="text" size="24"
class="ml-2" :icon="true" :loading="loading" @click="reload"> class="ml-2" :icon="true" :loading="loading" @click="reload">
<template #loader> <template #loader>
@@ -516,11 +527,13 @@ import { useAccountsStore } from '@/stores/account.js';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js'; import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
import { useTransactionTagsStore } from '@/stores/transactionTag.js'; import { useTransactionTagsStore } from '@/stores/transactionTag.js';
import { useTransactionsStore } from '@/stores/transaction.js'; import { useTransactionsStore } from '@/stores/transaction.js';
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
import numeralConstants from '@/consts/numeral.js'; import numeralConstants from '@/consts/numeral.js';
import datetimeConstants from '@/consts/datetime.js'; import datetimeConstants from '@/consts/datetime.js';
import accountConstants from '@/consts/account.js'; import accountConstants from '@/consts/account.js';
import transactionConstants from '@/consts/transaction.js'; import transactionConstants from '@/consts/transaction.js';
import templateConstants from '@/consts/template.js';
import { isString, getNameByKeyValue } from '@/lib/common.js'; import { isString, getNameByKeyValue } from '@/lib/common.js';
import logger from '@/lib/logger.js'; import logger from '@/lib/logger.js';
import { import {
@@ -562,6 +575,7 @@ import {
mdiArrowLeft, mdiArrowLeft,
mdiArrowRight, mdiArrowRight,
mdiPound, mdiPound,
mdiTextBoxOutline,
mdiDotsVertical mdiDotsVertical
} from '@mdi/js'; } from '@mdi/js';
@@ -621,12 +635,13 @@ export default {
arrowLeft: mdiArrowLeft, arrowLeft: mdiArrowLeft,
arrowRight: mdiArrowRight, arrowRight: mdiArrowRight,
tag: mdiPound, tag: mdiPound,
templates: mdiTextBoxOutline,
more: mdiDotsVertical more: mdiDotsVertical
} }
}; };
}, },
computed: { computed: {
...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore), ...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore, useTransactionTemplatesStore),
defaultCurrency() { defaultCurrency() {
return getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(this.allAccounts, this.queryAllFilterAccountIds, this.userStore.currentUserDefaultCurrency); return getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(this.allAccounts, this.queryAllFilterAccountIds, this.userStore.currentUserDefaultCurrency);
}, },
@@ -907,6 +922,10 @@ export default {
allAvailableTagsCount() { allAvailableTagsCount() {
return this.transactionTagsStore.allAvailableTagsCount; return this.transactionTagsStore.allAvailableTagsCount;
}, },
allTransactionTemplates() {
const allVisibleTemplates = this.transactionTemplatesStore.allVisibleTemplates;
return allVisibleTemplates[templateConstants.allTemplateTypes.Normal] || [];
},
recentMonthDateRanges() { recentMonthDateRanges() {
return this.$locale.getAllRecentMonthDateRanges(this.userStore, true, true); return this.$locale.getAllRecentMonthDateRanges(this.userStore, true, true);
}, },
@@ -992,6 +1011,11 @@ export default {
this.currentPage = 1; this.currentPage = 1;
this.reload(false); this.reload(false);
this.transactionTemplatesStore.loadAllTemplates({
templateType: templateConstants.allTemplateTypes.Normal,
force: false
});
}, },
reload(force) { reload(force) {
const self = this; const self = this;
@@ -1307,14 +1331,15 @@ export default {
this.$router.push(this.getFilterLinkUrl()); this.$router.push(this.getFilterLinkUrl());
} }
}, },
add() { add(template) {
const self = this; const self = this;
self.$refs.editDialog.open({ self.$refs.editDialog.open({
type: self.query.type, type: self.query.type,
categoryId: self.queryAllFilterCategoryIdsCount === 1 ? self.query.categoryIds : '', categoryId: self.queryAllFilterCategoryIdsCount === 1 ? self.query.categoryIds : '',
accountId: self.queryAllFilterAccountIdsCount === 1 ? self.query.accountIds : '', accountId: self.queryAllFilterAccountIdsCount === 1 ? self.query.accountIds : '',
tagIds: self.query.tagIds || '' tagIds: self.query.tagIds || '',
template: template
}).then(result => { }).then(result => {
if (result && result.message) { if (result && result.message) {
self.$refs.snackbar.showMessage(result.message); self.$refs.snackbar.showMessage(result.message);
@@ -669,6 +669,10 @@ export default {
self.mode = 'add'; self.mode = 'add';
self.editId = null; self.editId = null;
if (options.template) {
self.setTransaction(options.template, options, false, false);
}
if (self.settingsStore.appSettings.autoGetCurrentGeoLocation if (self.settingsStore.appSettings.autoGetCurrentGeoLocation
&& !self.geoLocationStatus && !self.transaction.geoLocation) { && !self.geoLocationStatus && !self.transaction.geoLocation) {
self.updateGeoLocation(false); self.updateGeoLocation(false);
+46 -3
View File
@@ -172,7 +172,7 @@
<f7-icon f7="creditcard"></f7-icon> <f7-icon f7="creditcard"></f7-icon>
<span class="tabbar-label">{{ $t('Accounts') }}</span> <span class="tabbar-label">{{ $t('Accounts') }}</span>
</f7-link> </f7-link>
<f7-link class="link" href="/transaction/add"> <f7-link id="homepage-add-button" class="link" href="/transaction/add" @taphold="openTransactionTemplatePopover">
<f7-icon f7="plus_square" class="ebk-tarbar-big-icon"></f7-icon> <f7-icon f7="plus_square" class="ebk-tarbar-big-icon"></f7-icon>
</f7-link> </f7-link>
<f7-link class="link" href="/statistic/transaction"> <f7-link class="link" href="/statistic/transaction">
@@ -184,6 +184,19 @@
<span class="tabbar-label">{{ $t('Settings') }}</span> <span class="tabbar-label">{{ $t('Settings') }}</span>
</f7-link> </f7-link>
</f7-toolbar> </f7-toolbar>
<f7-popover class="template-popover-menu" target-el="#homepage-add-button"
v-model:opened="showTransactionTemplatePopover">
<f7-list dividers v-if="allTransactionTemplates">
<f7-list-item :title="template.name" :key="template.id"
v-for="template in allTransactionTemplates"
@click="addTransaction(template)">
<template #media>
<f7-icon f7="doc_plaintext"></f7-icon>
</template>
</f7-list-item>
</f7-list>
</f7-popover>
</f7-page> </f7-page>
</template> </template>
@@ -191,19 +204,25 @@
import { mapStores } from 'pinia'; import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/setting.js'; import { useSettingsStore } from '@/stores/setting.js';
import { useUserStore } from '@/stores/user.js'; import { useUserStore } from '@/stores/user.js';
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
import { useOverviewStore } from '@/stores/overview.js'; import { useOverviewStore } from '@/stores/overview.js';
import datetimeConstants from '@/consts/datetime.js'; import datetimeConstants from '@/consts/datetime.js';
import templateConstants from '@/consts/template.js';
import { formatUnixTime } from '@/lib/datetime.js'; import { formatUnixTime } from '@/lib/datetime.js';
export default { export default {
props: [
'f7router'
],
data() { data() {
return { return {
loading: true loading: true,
showTransactionTemplatePopover: false
}; };
}, },
computed: { computed: {
...mapStores(useSettingsStore, useUserStore, useOverviewStore), ...mapStores(useSettingsStore, useUserStore, useTransactionTemplatesStore, useOverviewStore),
showAmountInHomePage: { showAmountInHomePage: {
get: function() { get: function() {
return this.settingsStore.appSettings.showAmountInHomePage; return this.settingsStore.appSettings.showAmountInHomePage;
@@ -215,6 +234,10 @@ export default {
defaultCurrency() { defaultCurrency() {
return this.userStore.currentUserDefaultCurrency; return this.userStore.currentUserDefaultCurrency;
}, },
allTransactionTemplates() {
const allTemplates = this.transactionTemplatesStore.allVisibleTemplates;
return allTemplates[templateConstants.allTemplateTypes.Normal] || [];
},
allDateRanges() { allDateRanges() {
return datetimeConstants.allDateRanges; return datetimeConstants.allDateRanges;
}, },
@@ -260,6 +283,11 @@ export default {
self.$toast(error.message || error); self.$toast(error.message || error);
} }
}); });
self.transactionTemplatesStore.loadAllTemplates({
templateType: templateConstants.allTemplateTypes.Normal,
force: false
});
} }
}, },
methods: { methods: {
@@ -292,6 +320,16 @@ export default {
} }
}); });
}, },
addTransaction(template) {
if (template && template.id) {
this.f7router.navigate('/transaction/add?templateId=' + template.id);
}
},
openTransactionTemplatePopover() {
if (this.allTransactionTemplates && this.allTransactionTemplates.length) {
this.showTransactionTemplatePopover = true;
}
},
getDisplayCurrency(value, currencyCode) { getDisplayCurrency(value, currencyCode) {
return this.$locale.formatAmountWithCurrency(this.settingsStore, this.userStore, value, currencyCode); return this.$locale.formatAmountWithCurrency(this.settingsStore, this.userStore, value, currencyCode);
}, },
@@ -387,4 +425,9 @@ export default {
height: var(--ebk-big-icon-button-size); height: var(--ebk-big-icon-button-size);
line-height: var(--ebk-big-icon-button-size); line-height: var(--ebk-big-icon-button-size);
} }
.template-popover-menu .popover-inner{
max-height: 400px;
overflow-y: auto;
}
</style> </style>
+15 -4
View File
@@ -355,10 +355,12 @@ import { useAccountsStore } from '@/stores/account.js';
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js'; import { useTransactionCategoriesStore } from '@/stores/transactionCategory.js';
import { useTransactionTagsStore } from '@/stores/transactionTag.js'; import { useTransactionTagsStore } from '@/stores/transactionTag.js';
import { useTransactionsStore } from '@/stores/transaction.js'; import { useTransactionsStore } from '@/stores/transaction.js';
import { useTransactionTemplatesStore } from '@/stores/transactionTemplate.js';
import { useExchangeRatesStore } from '@/stores/exchangeRates.js'; import { useExchangeRatesStore } from '@/stores/exchangeRates.js';
import categoryConstants from '@/consts/category.js'; import categoryConstants from '@/consts/category.js';
import transactionConstants from '@/consts/transaction.js'; import transactionConstants from '@/consts/transaction.js';
import templateConstants from '@/consts/template.js';
import logger from '@/lib/logger.js'; import logger from '@/lib/logger.js';
import { import {
getNameByKeyValue getNameByKeyValue
@@ -413,7 +415,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore, useExchangeRatesStore), ...mapStores(useSettingsStore, useUserStore, useAccountsStore, useTransactionCategoriesStore, useTransactionTagsStore, useTransactionsStore, useTransactionTemplatesStore, useExchangeRatesStore),
title() { title() {
if (this.mode === 'add') { if (this.mode === 'add') {
return 'Add Transaction'; return 'Add Transaction';
@@ -654,7 +656,8 @@ export default {
const promises = [ const promises = [
self.accountsStore.loadAllAccounts({ force: false }), self.accountsStore.loadAllAccounts({ force: false }),
self.transactionCategoriesStore.loadAllCategories({ force: false }), self.transactionCategoriesStore.loadAllCategories({ force: false }),
self.transactionTagsStore.loadAllTags({ force: false }) self.transactionTagsStore.loadAllTags({ force: false }),
self.transactionTemplatesStore.loadAllTemplates({ force: false, templateType: templateConstants.allTemplateTypes.Normal })
]; ];
if (query.id) { if (query.id) {
@@ -676,15 +679,23 @@ export default {
} }
Promise.all(promises).then(function (responses) { Promise.all(promises).then(function (responses) {
if (query.id && !responses[3]) { if (query.id && !responses[4]) {
self.$toast('Unable to retrieve transaction'); self.$toast('Unable to retrieve transaction');
self.loadingError = 'Unable to retrieve transaction'; self.loadingError = 'Unable to retrieve transaction';
return; return;
} }
let fromTransaction = null;
if (query.id) {
fromTransaction = responses[4];
} else if (query.templateId && self.transactionTemplatesStore.allTransactionTemplatesMap && self.transactionTemplatesStore.allTransactionTemplatesMap[templateConstants.allTemplateTypes.Normal]) {
fromTransaction = self.transactionTemplatesStore.allTransactionTemplatesMap[templateConstants.allTemplateTypes.Normal][query.templateId];
}
setTransactionModelByTransaction( setTransactionModelByTransaction(
self.transaction, self.transaction,
query.id ? responses[3] : null, fromTransaction,
self.allCategories, self.allCategories,
self.allCategoriesMap, self.allCategoriesMap,
self.allVisibleAccounts, self.allVisibleAccounts,