feat: add admin transaction edit UI on payment detail page
Wire create and update flows to admin transaction endpoints with status, amount, and date fields.
This commit is contained in:
@@ -108,6 +108,13 @@
|
||||
<span class="white-space-pre-wrap">{{ data.notes || '—' }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column header="عملیات" style="width: 5rem">
|
||||
<template #body="{ data }">
|
||||
<PermissionGate permission="payments:update">
|
||||
<Button icon="pi pi-pencil" text rounded severity="secondary" size="small" @click="openEditTransaction(data)" />
|
||||
</PermissionGate>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
</div>
|
||||
@@ -118,14 +125,26 @@
|
||||
<div class="flex flex-column gap-3 py-2">
|
||||
<div class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">مبلغ واریزی (تومان) *</label>
|
||||
<InputNumber v-model="trxForm.amount" class="w-full text-sm" suffix=" تومان" />
|
||||
<InputNumber v-model="trxForm.amount" class="w-full text-sm" suffix=" تومان" :min="1" />
|
||||
</div>
|
||||
<div class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">وضعیت تراکنش *</label>
|
||||
<Dropdown v-model="trxForm.status" :options="statusOptions" optionLabel="label" optionValue="value" class="w-full text-sm" />
|
||||
</div>
|
||||
<div v-if="trxForm.status === 'paid'" class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">روش پرداخت *</label>
|
||||
<Dropdown v-model="trxForm.method" :options="methodOptions" optionLabel="label" optionValue="value" class="w-full text-sm" />
|
||||
</div>
|
||||
<div class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">شماره فیش / پیگیری *</label>
|
||||
<label class="font-semibold text-sm">تاریخ سررسید *</label>
|
||||
<DatePicker v-model="trxForm.dueDate" class="w-full text-sm" placeholder="1403/01/01" />
|
||||
</div>
|
||||
<div v-if="trxForm.status === 'paid'" class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">تاریخ پرداخت</label>
|
||||
<DatePicker v-model="trxForm.date" class="w-full text-sm" placeholder="1403/01/01" />
|
||||
</div>
|
||||
<div v-if="trxForm.status === 'paid'" class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">شماره فیش / پیگیری</label>
|
||||
<InputText v-model.trim="trxForm.receiptNumber" class="w-full text-sm" dir="ltr" />
|
||||
</div>
|
||||
<div class="flex flex-column gap-2">
|
||||
@@ -145,6 +164,51 @@
|
||||
<Button label="ثبت تراکنش" icon="pi pi-check" severity="success" :loading="isSubmittingTrx" @click="handleRecordTransaction" />
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<!-- Edit Transaction Modal -->
|
||||
<Dialog v-model:visible="showEditModal" header="ویرایش تراکنش" modal :style="{ width: '450px' }">
|
||||
<div class="flex flex-column gap-3 py-2">
|
||||
<div class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">مبلغ (تومان) *</label>
|
||||
<InputNumber v-model="editForm.amount" class="w-full text-sm" suffix=" تومان" :min="0" />
|
||||
</div>
|
||||
<div class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">وضعیت تراکنش *</label>
|
||||
<Dropdown v-model="editForm.status" :options="statusOptions" optionLabel="label" optionValue="value" class="w-full text-sm" />
|
||||
</div>
|
||||
<div v-if="editForm.status === 'paid'" class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">روش پرداخت</label>
|
||||
<Dropdown v-model="editForm.method" :options="methodOptions" optionLabel="label" optionValue="value" class="w-full text-sm" />
|
||||
</div>
|
||||
<div class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">تاریخ سررسید *</label>
|
||||
<DatePicker v-model="editForm.dueDate" class="w-full text-sm" placeholder="1403/01/01" />
|
||||
</div>
|
||||
<div v-if="editForm.status === 'paid'" class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">تاریخ پرداخت</label>
|
||||
<DatePicker v-model="editForm.date" class="w-full text-sm" placeholder="1403/01/01" />
|
||||
</div>
|
||||
<div v-if="editForm.status === 'paid'" class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm">شماره فیش / پیگیری</label>
|
||||
<InputText v-model.trim="editForm.receiptNumber" class="w-full text-sm" dir="ltr" />
|
||||
</div>
|
||||
<div class="flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm" for="edit-trx-notes">یادداشت</label>
|
||||
<Textarea
|
||||
id="edit-trx-notes"
|
||||
v-model="editForm.notes"
|
||||
rows="3"
|
||||
class="w-full text-sm"
|
||||
maxlength="5000"
|
||||
placeholder="یادداشت داخلی درباره این تراکنش…"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="انصراف" text severity="secondary" @click="showEditModal = false" />
|
||||
<Button label="ذخیره تغییرات" icon="pi pi-check" severity="success" :loading="isSubmittingEdit" @click="handleUpdateTransaction" />
|
||||
</template>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -167,6 +231,7 @@ import Dropdown from 'primevue/select';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import InputNumber from 'primevue/inputnumber';
|
||||
import Textarea from 'primevue/textarea';
|
||||
import DatePicker from 'vue3-persian-datetime-picker';
|
||||
|
||||
const route = useRoute();
|
||||
const paymentId = route.params.id;
|
||||
@@ -175,7 +240,10 @@ const { showSuccess, showError } = useToast();
|
||||
|
||||
const payment = ref(null);
|
||||
const showTransactionModal = ref(false);
|
||||
const showEditModal = ref(false);
|
||||
const isSubmittingTrx = ref(false);
|
||||
const isSubmittingEdit = ref(false);
|
||||
const editingTransactionId = ref(null);
|
||||
|
||||
const methodOptions = [
|
||||
{ label: 'کارت به کارت', value: 'card' },
|
||||
@@ -183,10 +251,30 @@ const methodOptions = [
|
||||
{ label: 'نقدی / شبا', value: 'cash' }
|
||||
];
|
||||
|
||||
const trxForm = reactive({
|
||||
const statusOptions = [
|
||||
{ label: 'پرداخت شده', value: 'paid' },
|
||||
{ label: 'در انتظار پرداخت', value: 'pending' }
|
||||
];
|
||||
|
||||
const defaultTrxForm = () => ({
|
||||
amount: 500000,
|
||||
status: 'paid',
|
||||
method: 'card',
|
||||
receiptNumber: '',
|
||||
dueDate: '',
|
||||
date: '',
|
||||
notes: ''
|
||||
});
|
||||
|
||||
const trxForm = reactive(defaultTrxForm());
|
||||
|
||||
const editForm = reactive({
|
||||
amount: 0,
|
||||
status: 'paid',
|
||||
method: 'card',
|
||||
receiptNumber: '',
|
||||
dueDate: '',
|
||||
date: '',
|
||||
notes: ''
|
||||
});
|
||||
|
||||
@@ -204,15 +292,31 @@ const fetchPayment = async () => {
|
||||
|
||||
const handleRecordTransaction = async () => {
|
||||
if (!trxForm.amount) { showError('لطفا مبلغ را وارد کنید'); return; }
|
||||
if (!trxForm.receiptNumber) { showError('لطفا شماره فیش یا پیگیری را وارد کنید'); return; }
|
||||
if (!trxForm.dueDate) { showError('لطفا تاریخ سررسید را وارد کنید'); return; }
|
||||
if (trxForm.status === 'paid' && !trxForm.receiptNumber) {
|
||||
showError('لطفا شماره فیش یا پیگیری را وارد کنید');
|
||||
return;
|
||||
}
|
||||
|
||||
isSubmittingTrx.value = true;
|
||||
try {
|
||||
await paymentApi.recordTransaction(paymentId, trxForm);
|
||||
const payload = {
|
||||
amount: trxForm.amount,
|
||||
status: trxForm.status,
|
||||
dueDate: trxForm.dueDate,
|
||||
notes: trxForm.notes || undefined
|
||||
};
|
||||
if (trxForm.status === 'paid') {
|
||||
payload.method = trxForm.method;
|
||||
payload.receiptNumber = trxForm.receiptNumber;
|
||||
if (trxForm.date) payload.date = trxForm.date;
|
||||
}
|
||||
|
||||
const res = await paymentApi.recordTransaction(paymentId, payload);
|
||||
payment.value = res.data || res;
|
||||
showSuccess('تراکنش جدید با موفقیت ثبت شد');
|
||||
showTransactionModal.value = false;
|
||||
trxForm.notes = '';
|
||||
fetchPayment();
|
||||
Object.assign(trxForm, defaultTrxForm());
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
@@ -220,6 +324,53 @@ const handleRecordTransaction = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const openEditTransaction = (trx) => {
|
||||
editingTransactionId.value = trx._id || trx.id;
|
||||
editForm.amount = trx.amount || 0;
|
||||
editForm.status = trx.status || (trx.date ? 'paid' : 'pending');
|
||||
editForm.method = trx.method || 'card';
|
||||
editForm.receiptNumber = trx.receiptNumber || '';
|
||||
editForm.dueDate = trx.dueDate || '';
|
||||
editForm.date = trx.date || '';
|
||||
editForm.notes = trx.notes || '';
|
||||
showEditModal.value = true;
|
||||
};
|
||||
|
||||
const handleUpdateTransaction = async () => {
|
||||
if (!editForm.amount && editForm.amount !== 0) {
|
||||
showError('لطفا مبلغ را وارد کنید');
|
||||
return;
|
||||
}
|
||||
if (!editForm.dueDate) {
|
||||
showError('لطفا تاریخ سررسید را وارد کنید');
|
||||
return;
|
||||
}
|
||||
|
||||
isSubmittingEdit.value = true;
|
||||
try {
|
||||
const payload = {
|
||||
amount: editForm.amount,
|
||||
status: editForm.status,
|
||||
dueDate: editForm.dueDate,
|
||||
notes: editForm.notes
|
||||
};
|
||||
if (editForm.status === 'paid') {
|
||||
payload.method = editForm.method;
|
||||
payload.receiptNumber = editForm.receiptNumber;
|
||||
payload.date = editForm.date || undefined;
|
||||
}
|
||||
|
||||
const res = await paymentApi.updateTransaction(editingTransactionId.value, payload);
|
||||
payment.value = res.data || res;
|
||||
showSuccess('تراکنش با موفقیت بهروزرسانی شد');
|
||||
showEditModal.value = false;
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
isSubmittingEdit.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchPayment();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user