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:
@@ -20,13 +20,16 @@ import {
|
||||
Statistic as AStatistic,
|
||||
Tag as ATag,
|
||||
Typography,
|
||||
message,
|
||||
} from 'ant-design-vue';
|
||||
import { api } from '@/lib/api';
|
||||
import type { FinancialAccountDto, FinancialAccountType } 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 { parseMoneyNumber } from '@/lib/money';
|
||||
|
||||
const { Title: ATypographyTitle, Text: ATypographyText } = Typography;
|
||||
const { Text: ATypographyText } = Typography;
|
||||
const AListItem = AList.Item;
|
||||
const AListItemMeta = AList.Item.Meta;
|
||||
const ASelectOption = ASelect.Option;
|
||||
@@ -82,14 +85,19 @@ async function load() {
|
||||
accounts.value = data;
|
||||
}
|
||||
|
||||
function onFinishFailed() {
|
||||
message.warning('لطفاً فیلدهای الزامی را کامل کنید.');
|
||||
}
|
||||
|
||||
async function createAccount() {
|
||||
saving.value = true;
|
||||
error.value = '';
|
||||
ok.value = '';
|
||||
try {
|
||||
const openingBalance = parseMoneyNumber(String(form.value.openingBalance ?? ''), 0) ?? 0;
|
||||
await api.post('/treasury/accounts', {
|
||||
...form.value,
|
||||
openingBalance: form.value.openingBalance || 0,
|
||||
openingBalance,
|
||||
openingDate: form.value.openingDate || undefined,
|
||||
});
|
||||
openForm.value = false;
|
||||
@@ -117,11 +125,20 @@ async function sendTransfer() {
|
||||
error.value = '';
|
||||
ok.value = '';
|
||||
try {
|
||||
const amount = parseMoneyNumber(String(transfer.value.amount ?? ''), 0);
|
||||
if (amount == null || amount <= 0) {
|
||||
error.value = 'مبلغ انتقال معتبر نیست.';
|
||||
return;
|
||||
}
|
||||
await api.post('/treasury/transfers', {
|
||||
...transfer.value,
|
||||
fromAccountId: transfer.value.fromAccountId,
|
||||
toAccountId: transfer.value.toAccountId,
|
||||
amount,
|
||||
memo: transfer.value.memo || undefined,
|
||||
clientKey: crypto.randomUUID(),
|
||||
});
|
||||
transferOpen.value = false;
|
||||
transfer.value = { fromAccountId: '', toAccountId: '', amount: '', memo: '' };
|
||||
ok.value = 'انتقال ثبت شد و در درآمد یا هزینه نیامده است.';
|
||||
await load();
|
||||
} catch (e) {
|
||||
@@ -139,17 +156,7 @@ 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" />
|
||||
|
||||
@@ -192,15 +199,24 @@ onMounted(() => {
|
||||
|
||||
<template v-if="openForm">
|
||||
<a-divider orientation="right">حساب جدید</a-divider>
|
||||
<a-form layout="vertical" @finish="createAccount">
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:model="form"
|
||||
@finish="createAccount"
|
||||
@finishFailed="onFinishFailed"
|
||||
>
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="نام حساب" name="name">
|
||||
<a-form-item
|
||||
label="نام حساب"
|
||||
name="name"
|
||||
:rules="[{ required: true, message: 'نام حساب الزامی است' }]"
|
||||
>
|
||||
<a-input v-model:value="form.name" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="نوع" name="type">
|
||||
<a-form-item label="نوع" name="type" :rules="[{ required: true }]">
|
||||
<a-select v-model:value="form.type" style="width: 100%">
|
||||
<a-select-option value="cash">صندوق نقدی</a-select-option>
|
||||
<a-select-option value="bank">حساب بانکی</a-select-option>
|
||||
@@ -225,12 +241,12 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="موجودی اولیه" name="openingBalance">
|
||||
<a-input v-model:value="form.openingBalance" />
|
||||
<MoneyInput v-model="form.openingBalance" :decimals="0" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="تاریخ شروع" name="openingDate">
|
||||
<a-input v-model:value="form.openingDate" type="date" style="width: 100%" />
|
||||
<JalaliDateInput v-model="form.openingDate" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
@@ -245,12 +261,25 @@ onMounted(() => {
|
||||
|
||||
<template v-if="transferOpen">
|
||||
<a-divider orientation="right">انتقال بین حسابها</a-divider>
|
||||
<a-form layout="vertical" @finish="sendTransfer">
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:model="transfer"
|
||||
@finish="sendTransfer"
|
||||
@finishFailed="onFinishFailed"
|
||||
>
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="از حساب" name="fromAccountId">
|
||||
<a-select v-model:value="transfer.fromAccountId" style="width: 100%" placeholder="انتخاب">
|
||||
<a-select-option value="">انتخاب</a-select-option>
|
||||
<a-form-item
|
||||
label="از حساب"
|
||||
name="fromAccountId"
|
||||
:rules="[{ required: true, message: 'حساب مبدأ الزامی است' }]"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="transfer.fromAccountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب"
|
||||
>
|
||||
<a-select-option v-for="account in active" :key="account.id" :value="account.id">
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
@@ -258,18 +287,34 @@ onMounted(() => {
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="به حساب" name="toAccountId">
|
||||
<a-select v-model:value="transfer.toAccountId" style="width: 100%" placeholder="انتخاب">
|
||||
<a-select-option value="">انتخاب</a-select-option>
|
||||
<a-select-option v-for="account in active" :key="`to-${account.id}`" :value="account.id">
|
||||
<a-form-item
|
||||
label="به حساب"
|
||||
name="toAccountId"
|
||||
:rules="[{ required: true, message: 'حساب مقصد الزامی است' }]"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="transfer.toAccountId"
|
||||
allow-clear
|
||||
style="width: 100%"
|
||||
placeholder="انتخاب"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="account in active"
|
||||
:key="`to-${account.id}`"
|
||||
:value="account.id"
|
||||
>
|
||||
{{ account.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="8">
|
||||
<a-form-item label="مبلغ" name="amount">
|
||||
<a-input v-model:value="transfer.amount" />
|
||||
<a-form-item
|
||||
label="مبلغ"
|
||||
name="amount"
|
||||
:rules="[{ required: true, message: 'مبلغ الزامی است' }]"
|
||||
>
|
||||
<MoneyInput v-model="transfer.amount" :decimals="0" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
@@ -309,6 +354,5 @@ onMounted(() => {
|
||||
</template>
|
||||
</a-list>
|
||||
</a-card>
|
||||
</a-flex>
|
||||
</div>
|
||||
</a-flex>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user