Show selected account balance beside the treasury account field.

Color the balance green, red, or gray on income and expense forms so users see cash position before posting.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-15 13:48:30 +03:30
co-authored by Cursor
parent 4409ded0ab
commit 1b08ab1230
3 changed files with 52 additions and 4 deletions
@@ -36,7 +36,7 @@ import {
uploadTreasuryDocumentPhotos,
type TreasuryPendingPhoto,
} from '@/lib/treasury-doc-photos';
import { partyNetPosition, toman } from './treasury-format';
import { accountBalanceTone, partyNetPosition, toman } from './treasury-format';
import { useTreasuryMobile } from './useTreasuryMobile';
import { parseMoneyNumber } from '@/lib/money';
@@ -281,6 +281,14 @@ const partyPosition = computed(() => {
return partyNetPosition(receivable, payable);
});
const selectedAccountBalance = computed(() => {
const id = form.value.accountId;
if (!id) return null;
const account = accounts.value.find((row) => row.id === id);
if (!account) return null;
return accountBalanceTone(account.balance);
});
onMounted(() => {
void load().catch(() => {
error.value = 'بارگذاری ناموفق بود.';
@@ -382,7 +390,18 @@ onMounted(() => {
</a-form-item>
</a-col>
<a-col :xs="24" :sm="12" :md="8">
<a-form-item label="حساب" name="accountId" :rules="accountRules">
<a-form-item name="accountId" :rules="accountRules">
<template #label>
<a-flex align="center" justify="space-between" gap="small" style="width: 100%">
<span>حساب</span>
<a-typography-text
v-if="selectedAccountBalance"
:type="selectedAccountBalance.type"
>
{{ selectedAccountBalance.text }}
</a-typography-text>
</a-flex>
</template>
<a-select
show-search
option-filter-prop="label"
@@ -37,7 +37,7 @@ import {
uploadTreasuryDocumentPhotos,
type TreasuryPendingPhoto,
} from '@/lib/treasury-doc-photos';
import { partyNetPosition, toman } from './treasury-format';
import { accountBalanceTone, partyNetPosition, toman } from './treasury-format';
import { parseMoneyNumber } from '@/lib/money';
const { Text: ATypographyText } = Typography;
@@ -132,6 +132,14 @@ const partyPosition = computed(() => {
return partyNetPosition(receivable, payable);
});
const selectedAccountBalance = computed(() => {
const id = form.value.accountId;
if (!id) return null;
const account = accounts.value.find((row) => row.id === id);
if (!account) return null;
return accountBalanceTone(account.balance);
});
watch(entryMode, () => {
settleMirror.reset();
form.value.amount = '';
@@ -383,7 +391,18 @@ onMounted(() => {
</a-form-item>
</a-col>
<a-col :xs="24" :sm="12" :md="8">
<a-form-item label="حساب" name="accountId" :rules="accountRules">
<a-form-item name="accountId" :rules="accountRules">
<template #label>
<a-flex align="center" justify="space-between" gap="small" style="width: 100%">
<span>حساب</span>
<a-typography-text
v-if="selectedAccountBalance"
:type="selectedAccountBalance.type"
>
{{ selectedAccountBalance.text }}
</a-typography-text>
</a-flex>
</template>
<a-select
show-search
option-filter-prop="label"
@@ -11,3 +11,13 @@ export function partyNetPosition(receivable: number, payable: number) {
if (net < 0) return { text: `بس ${toman(-net)}`, type: 'success' as const };
return { text: `مانده ${toman(0)}`, type: 'secondary' as const };
}
/** موجودی حساب: مثبت سبز، منفی قرمز، صفر خاکستری. */
export function accountBalanceTone(balance: string | number | null | undefined) {
const n = Number(balance ?? 0);
if (!Number.isFinite(n) || n === 0) {
return { text: `موجودی ${toman(0)}`, type: 'secondary' as const };
}
if (n > 0) return { text: `موجودی ${toman(n)}`, type: 'success' as const };
return { text: `موجودی ${toman(n)}`, type: 'danger' as const };
}