support duplicating / modifying / deleting transaction in reconciliation statement page

This commit is contained in:
MaysWind
2025-07-29 00:58:15 +08:00
parent e4cb66718d
commit ad4f5bd88d
@@ -73,7 +73,7 @@
class="skeleton-text margin-vertical transaction-info-list reconciliation-statement-list" class="skeleton-text margin-vertical transaction-info-list reconciliation-statement-list"
v-if="finishQuery && loading"> v-if="finishQuery && loading">
<ul> <ul>
<f7-list-item chevron-center media-item <f7-list-item chevron-center
:key="index" :key="index"
:class="{ 'transaction-info': type === 't', 'last-transaction-of-day': index === 2, 'reconciliation-statement-transaction-date': type === 'd' }" :class="{ 'transaction-info': type === 't', 'last-transaction-of-day': index === 2, 'reconciliation-statement-transaction-date': type === 'd' }"
:link="type === 't' ? '#' : null" :link="type === 't' ? '#' : null"
@@ -139,16 +139,18 @@
:virtual-list-params="{ items: allReconciliationStatementVirtualListItems, renderExternal, height: 'auto' }" :virtual-list-params="{ items: allReconciliationStatementVirtualListItems, renderExternal, height: 'auto' }"
v-if="finishQuery && !loading && allReconciliationStatementVirtualListItems && allReconciliationStatementVirtualListItems.length"> v-if="finishQuery && !loading && allReconciliationStatementVirtualListItems && allReconciliationStatementVirtualListItems.length">
<ul> <ul>
<f7-list-item <f7-list-item chevron-center
chevron-center
media-item
:key="item.index" :key="item.index"
:id="item.transaction ? getTransactionDomId(item.transaction) : undefined"
:class="{ 'transaction-info': item.type == 'transaction', 'last-transaction-of-day': allReconciliationStatementVirtualListItems[item.index + 1] && allReconciliationStatementVirtualListItems[item.index + 1].type === 'date', 'reconciliation-statement-transaction-date': item.type == 'date' }" :class="{ 'transaction-info': item.type == 'transaction', 'last-transaction-of-day': allReconciliationStatementVirtualListItems[item.index + 1] && allReconciliationStatementVirtualListItems[item.index + 1].type === 'date', 'reconciliation-statement-transaction-date': item.type == 'date' }"
:style="`top: ${virtualDataItems.topPosition}px`" :style="`top: ${virtualDataItems.topPosition}px`"
:virtual-list-index="item.index" :virtual-list-index="item.index"
:swipeout="item.type == 'transaction' && item.transaction"
:accordion-item="item.type == 'transaction' && item.transaction"
:link="item.type == 'transaction' && item.transaction && item.transaction.type !== TransactionType.ModifyBalance ? `/transaction/detail?id=${item.transaction?.id}&type=${item.transaction.type}` : null" :link="item.type == 'transaction' && item.transaction && item.transaction.type !== TransactionType.ModifyBalance ? `/transaction/detail?id=${item.transaction?.id}&type=${item.transaction.type}` : null"
v-for="item in virtualDataItems.items" v-for="item in virtualDataItems.items"
> >
<template #inner>
<div class="display-flex no-padding-horizontal" v-if="item.type == 'date' && item.displayDate"> <div class="display-flex no-padding-horizontal" v-if="item.type == 'date' && item.displayDate">
<div class="actual-item-inner"> <div class="actual-item-inner">
<div class="item-title-row"> <div class="item-title-row">
@@ -209,6 +211,22 @@
</div> </div>
</div> </div>
</div> </div>
</template>
<f7-swipeout-actions right v-if="item.type == 'transaction' && item.transaction">
<f7-swipeout-button color="primary" close
:text="tt('Duplicate')"
v-if="item.transaction.type !== TransactionType.ModifyBalance"
@click="duplicateTransaction(item.transaction)"></f7-swipeout-button>
<f7-swipeout-button color="orange" close
:text="tt('Edit')"
v-if="item.transaction.editable && item.transaction.type !== TransactionType.ModifyBalance"
@click="editTransaction(item.transaction)"></f7-swipeout-button>
<f7-swipeout-button color="red" class="padding-left padding-right"
v-if="item.transaction.editable"
@click="removeTransaction(item.transaction, false)">
<f7-icon f7="trash"></f7-icon>
</f7-swipeout-button>
</f7-swipeout-actions>
</f7-list-item> </f7-list-item>
</ul> </ul>
</f7-list> </f7-list>
@@ -231,6 +249,16 @@
<f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button> <f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button>
</f7-actions-group> </f7-actions-group>
</f7-actions> </f7-actions>
<f7-actions close-by-outside-click close-on-escape :opened="showDeleteActionSheet" @actions:closed="showDeleteActionSheet = false">
<f7-actions-group>
<f7-actions-label>{{ tt('Are you sure you want to delete this transaction?') }}</f7-actions-label>
<f7-actions-button color="red" @click="removeTransaction(transactionToDelete, true)">{{ tt('Delete') }}</f7-actions-button>
</f7-actions-group>
<f7-actions-group>
<f7-actions-button bold close>{{ tt('Cancel') }}</f7-actions-button>
</f7-actions-group>
</f7-actions>
</f7-page> </f7-page>
</template> </template>
@@ -239,7 +267,7 @@ import { ref, computed } from 'vue';
import type { Router } from 'framework7/types'; import type { Router } from 'framework7/types';
import { useI18n } from '@/locales/helpers.ts'; import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents } from '@/lib/ui/mobile.ts'; import { useI18nUIComponents, showLoading, hideLoading, onSwipeoutDeleted } from '@/lib/ui/mobile.ts';
import { useReconciliationStatementPageBase } from '@/views/base/accounts/ReconciliationStatementPageBase.ts'; import { useReconciliationStatementPageBase } from '@/views/base/accounts/ReconciliationStatementPageBase.ts';
import { useAccountsStore } from '@/stores/account.ts'; import { useAccountsStore } from '@/stores/account.ts';
@@ -278,7 +306,7 @@ const props = defineProps<{
}>(); }>();
const { tt, getAllDateRanges, formatUnixTimeToLongDateTime } = useI18n(); const { tt, getAllDateRanges, formatUnixTimeToLongDateTime } = useI18n();
const { showToast, routeBackOnError } = useI18nUIComponents(); const { showAlert, showToast, routeBackOnError } = useI18nUIComponents();
const { const {
accountId, accountId,
@@ -291,6 +319,7 @@ const {
isCurrentLiabilityAccount, isCurrentLiabilityAccount,
allCategoriesMap, allCategoriesMap,
currentAccount, currentAccount,
currentAccountCurrency,
displayStartDateTime, displayStartDateTime,
displayEndDateTime, displayEndDateTime,
displayTotalInflows, displayTotalInflows,
@@ -314,8 +343,10 @@ const finishQuery = ref<boolean>(false);
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const loadingError = ref<unknown | null>(null); const loadingError = ref<unknown | null>(null);
const queryDateRangeType = ref<number>(DateRange.ThisMonth.type); const queryDateRangeType = ref<number>(DateRange.ThisMonth.type);
const transactionToDelete = ref<TransactionReconciliationStatementResponseItem | null>(null);
const showCustomDateRangeSheet = ref<boolean>(false); const showCustomDateRangeSheet = ref<boolean>(false);
const showMoreActionSheet = ref<boolean>(false); const showMoreActionSheet = ref<boolean>(false);
const showDeleteActionSheet = ref<boolean>(false);
const virtualDataItems = ref<ReconciliationStatementVirtualListData>({ const virtualDataItems = ref<ReconciliationStatementVirtualListData>({
items: [], items: [],
topPosition: 0 topPosition: 0
@@ -359,6 +390,10 @@ const allReconciliationStatementVirtualListItems = computed<ReconciliationStatem
return ret; return ret;
}); });
function getTransactionDomId(transaction: TransactionReconciliationStatementResponseItem): string {
return 'transaction_' + transaction.id;
}
function init(): void { function init(): void {
const query = props.f7route.query; const query = props.f7route.query;
const defaultDateRange = getDateRangeByDateType(queryDateRangeType.value, firstDayOfWeek.value, fiscalYearStart.value); const defaultDateRange = getDateRangeByDateType(queryDateRangeType.value, firstDayOfWeek.value, fiscalYearStart.value);
@@ -447,6 +482,48 @@ function addTransaction(): void {
props.f7router.navigate(`/transaction/add?accountId=${accountId.value}`); props.f7router.navigate(`/transaction/add?accountId=${accountId.value}`);
} }
function duplicateTransaction(transaction: TransactionReconciliationStatementResponseItem): void {
props.f7router.navigate(`/transaction/add?id=${transaction.id}&type=${transaction.type}`);
}
function editTransaction(transaction: TransactionReconciliationStatementResponseItem): void {
props.f7router.navigate(`/transaction/edit?id=${transaction.id}&type=${transaction.type}`);
}
function removeTransaction(transaction: TransactionReconciliationStatementResponseItem | null, confirm: boolean): void {
if (!transaction) {
showAlert('An error occurred');
return;
}
if (!confirm) {
transactionToDelete.value = transaction;
showDeleteActionSheet.value = true;
return;
}
showDeleteActionSheet.value = false;
transactionToDelete.value = null;
showLoading();
transactionsStore.deleteTransaction({
transaction: transaction,
defaultCurrency: currentAccountCurrency.value,
beforeResolve: (done) => {
onSwipeoutDeleted(getTransactionDomId(transaction), done);
}
}).then(() => {
hideLoading();
reload(false);
}).catch(error => {
hideLoading();
if (!error.processed) {
showToast(error.message || error);
}
});
}
function renderExternal(vl: unknown, vlData: ReconciliationStatementVirtualListData): void { function renderExternal(vl: unknown, vlData: ReconciliationStatementVirtualListData): void {
virtualDataItems.value = vlData; virtualDataItems.value = vlData;
} }
@@ -490,7 +567,8 @@ init();
background-color: inherit; background-color: inherit;
} }
.list.reconciliation-statement-list li.transaction-info.last-transaction-of-day > .item-link > .item-content > .item-inner:after { .list.reconciliation-statement-list li.transaction-info.last-transaction-of-day > .item-link > .item-content > .item-inner:after,
.list.reconciliation-statement-list li.transaction-info.last-transaction-of-day > .swipeout-content > .item-link > .item-content > .item-inner:after {
background-color: inherit; background-color: inherit;
} }