fix(finance): shared treasury layout so tab switches stop jumping
Keep title and nav mounted in TreasuryLayout with stable header height, and finish Ant form chrome (MoneyInput, Jalali) on finance pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -19,15 +19,18 @@ import {
|
||||
Table as ATable,
|
||||
Tag as ATag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'ant-design-vue';
|
||||
import type { TableColumnsType } from 'ant-design-vue';
|
||||
import { api } from '@/lib/api';
|
||||
import type { FinancialAccountDto, FinancialReceivableDto } from '@mento/shared';
|
||||
import TreasuryNav from '@/components/treasury/TreasuryNav.vue';
|
||||
import MoneyInput from '@/components/MoneyInput.vue';
|
||||
import JalaliDateInput from '@/components/JalaliDateInput.vue';
|
||||
import { toman } from './treasury-format';
|
||||
import { formatJalaliNumeric } from '@/lib/jalali';
|
||||
import { parseMoneyNumber } from '@/lib/money';
|
||||
|
||||
const { Title: ATypographyTitle, Text: ATypographyText } = Typography;
|
||||
const { Text: ATypographyText } = Typography;
|
||||
const ASelectOption = ASelect.Option;
|
||||
|
||||
type InstallmentRow = FinancialReceivableDto['installments'][number];
|
||||
@@ -109,19 +112,35 @@ async function downloadExcel() {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
function onFinishFailed() {
|
||||
message.warning('لطفاً فیلدهای الزامی را کامل کنید.');
|
||||
}
|
||||
|
||||
async function createContract() {
|
||||
saving.value = true;
|
||||
error.value = '';
|
||||
ok.value = '';
|
||||
try {
|
||||
const totalAmount = parseMoneyNumber(String(form.value.totalAmount ?? ''), 0);
|
||||
if (totalAmount == null || totalAmount <= 0) {
|
||||
error.value = 'مبلغ کل معتبر نیست.';
|
||||
return;
|
||||
}
|
||||
const prepaidAmount = parseMoneyNumber(String(form.value.prepaidAmount ?? ''), 0) ?? 0;
|
||||
const installments = custom.value
|
||||
? customLines.value.map((line) => ({
|
||||
amount: parseMoneyNumber(String(line.amount ?? ''), 0) ?? 0,
|
||||
dueDate: line.dueDate,
|
||||
}))
|
||||
: undefined;
|
||||
await api.post('/treasury/receivables', {
|
||||
title: form.value.title,
|
||||
partyName: form.value.partyName || null,
|
||||
totalAmount: form.value.totalAmount,
|
||||
prepaidAmount: form.value.prepaidAmount || 0,
|
||||
totalAmount,
|
||||
prepaidAmount,
|
||||
accountId: form.value.accountId || null,
|
||||
...(custom.value
|
||||
? { installments: customLines.value }
|
||||
? { installments }
|
||||
: {
|
||||
count: Number(form.value.count),
|
||||
interval: form.value.interval,
|
||||
@@ -145,8 +164,13 @@ async function collectInstallment() {
|
||||
saving.value = true;
|
||||
error.value = '';
|
||||
try {
|
||||
const amount = parseMoneyNumber(String(collect.value.amount ?? ''), 0);
|
||||
if (amount == null || amount <= 0) {
|
||||
error.value = 'مبلغ دریافت معتبر نیست.';
|
||||
return;
|
||||
}
|
||||
await api.post(`/treasury/installments/${collect.value.installmentId}/collect`, {
|
||||
amount: collect.value.amount,
|
||||
amount,
|
||||
accountId: collect.value.accountId,
|
||||
clientKey: crypto.randomUUID(),
|
||||
});
|
||||
@@ -177,26 +201,25 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a-flex vertical :gap="16">
|
||||
<div>
|
||||
<a-typography-title :level="3" :style="{ margin: 0 }">اقساط و مطالبات</a-typography-title>
|
||||
<a-typography-text type="secondary">
|
||||
دریافت هر قسط فقط یک بار وارد حساب میشود و مانده همان قسط را کم میکند.
|
||||
</a-typography-text>
|
||||
</div>
|
||||
|
||||
<TreasuryNav />
|
||||
|
||||
<a-flex vertical :gap="16">
|
||||
<a-alert v-if="error" type="error" show-icon :message="error" />
|
||||
<a-alert v-if="ok" type="success" show-icon :message="ok" />
|
||||
|
||||
<a-card :bordered="false">
|
||||
<a-divider orientation="right">قرارداد جدید</a-divider>
|
||||
<a-form layout="vertical" @finish="createContract">
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:model="form"
|
||||
@finish="createContract"
|
||||
@finishFailed="onFinishFailed"
|
||||
>
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="عنوان" name="title">
|
||||
<a-form-item
|
||||
label="عنوان"
|
||||
name="title"
|
||||
:rules="[{ required: true, message: 'عنوان الزامی است' }]"
|
||||
>
|
||||
<a-input v-model:value="form.title" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
@@ -206,19 +229,27 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="مبلغ کل" name="totalAmount">
|
||||
<a-input v-model:value="form.totalAmount" />
|
||||
<a-form-item
|
||||
label="مبلغ کل"
|
||||
name="totalAmount"
|
||||
:rules="[{ required: true, message: 'مبلغ کل الزامی است' }]"
|
||||
>
|
||||
<MoneyInput v-model="form.totalAmount" :decimals="0" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="پیشپرداخت" name="prepaidAmount">
|
||||
<a-input v-model:value="form.prepaidAmount" />
|
||||
<MoneyInput v-model="form.prepaidAmount" :decimals="0" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="حساب پیشپرداخت" name="accountId">
|
||||
<a-select v-model:value="form.accountId" allow-clear style="width: 100%" placeholder="انتخاب">
|
||||
<a-select-option value="">انتخاب</a-select-option>
|
||||
<a-select
|
||||
v-model:value="form.accountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب"
|
||||
>
|
||||
<a-select-option v-for="account in accounts" :key="account.id" :value="account.id">
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
@@ -240,7 +271,7 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="شروع" name="startDate">
|
||||
<a-input v-model:value="form.startDate" type="date" :disabled="custom" style="width: 100%" />
|
||||
<JalaliDateInput v-model="form.startDate" :disabled="custom" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24">
|
||||
@@ -254,12 +285,12 @@ onMounted(() => {
|
||||
<a-row v-for="(line, index) in customLines" :key="index" :gutter="[16, 0]">
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item :label="`مبلغ قسط ${index + 1}`">
|
||||
<a-input v-model:value="line.amount" />
|
||||
<MoneyInput v-model="line.amount" :decimals="0" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="سررسید">
|
||||
<a-input v-model:value="line.dueDate" type="date" style="width: 100%" />
|
||||
<JalaliDateInput v-model="line.dueDate" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@@ -276,17 +307,39 @@ onMounted(() => {
|
||||
|
||||
<template v-if="collect.installmentId">
|
||||
<a-divider orientation="right">دریافت قسط</a-divider>
|
||||
<a-form layout="vertical" @finish="collectInstallment">
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:model="collect"
|
||||
@finish="collectInstallment"
|
||||
@finishFailed="onFinishFailed"
|
||||
>
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="مبلغ" name="amount">
|
||||
<a-input v-model:value="collect.amount" />
|
||||
<a-form-item
|
||||
label="مبلغ"
|
||||
name="amount"
|
||||
:rules="[{ required: true, message: 'مبلغ الزامی است' }]"
|
||||
>
|
||||
<MoneyInput v-model="collect.amount" :decimals="0" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="حساب مقصد" name="accountId">
|
||||
<a-select v-model:value="collect.accountId" style="width: 100%">
|
||||
<a-select-option v-for="account in accounts" :key="account.id" :value="account.id">
|
||||
<a-form-item
|
||||
label="حساب مقصد"
|
||||
name="accountId"
|
||||
:rules="[{ required: true, message: 'حساب الزامی است' }]"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="collect.accountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب حساب"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="account in accounts"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
@@ -337,6 +390,5 @@ onMounted(() => {
|
||||
</div>
|
||||
</template>
|
||||
</a-card>
|
||||
</a-flex>
|
||||
</div>
|
||||
</a-flex>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user