Improve person assets UI and fix Tahesab asnad date/list.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,13 @@ import { computed, onMounted, ref, watch } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { api } from '@/lib/api';
|
||||
import { formatMoney } from '@/lib/money';
|
||||
import {
|
||||
dateToJalali,
|
||||
formatLocalDateInput,
|
||||
parseLocalInput,
|
||||
} from '@/lib/jalali';
|
||||
import MoneyInput from '@/components/MoneyInput.vue';
|
||||
import JalaliDateInput from '@/components/JalaliDateInput.vue';
|
||||
import type {
|
||||
PersonAccountingLinkDto,
|
||||
PersonAssetsDto,
|
||||
@@ -16,6 +22,10 @@ const props = defineProps<{
|
||||
personId: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
linkChanged: [moshtariCode: number | null];
|
||||
}>();
|
||||
|
||||
const loading = ref(false);
|
||||
const error = ref('');
|
||||
const ok = ref('');
|
||||
@@ -26,6 +36,7 @@ const assets = ref<PersonAssetsDto | null>(null);
|
||||
const activeTab = ref<'مانده حساب' | 'جزئیات حساب' | 'ثبت سند'>('مانده حساب');
|
||||
const asnadLoading = ref(false);
|
||||
const asnadItems = ref<Record<string, unknown>[]>([]);
|
||||
/** مدل JalaliDateInput = تاریخ محلی میلادی YYYY-MM-DD */
|
||||
const fromDate = ref('');
|
||||
const toDate = ref('');
|
||||
const manualCode = ref('');
|
||||
@@ -120,18 +131,28 @@ function formatMandehAmount(amount: string | number, unit: string) {
|
||||
return abs.toLocaleString('fa-IR', { maximumFractionDigits: 3 });
|
||||
}
|
||||
|
||||
/** تبدیل تاریخ محلی میلادی به شمسی YYYY-MM-DD برای API تهحساب */
|
||||
function toShamsiYmd(localIso: string): string | null {
|
||||
const d = parseLocalInput(localIso);
|
||||
if (!d) return null;
|
||||
const { jy, jm, jd } = dateToJalali(d);
|
||||
return `${jy}-${String(jm).padStart(2, '0')}-${String(jd).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function defaultJalaliRange() {
|
||||
// تقریبی: کاربر میتواند عوض کند؛ پیشفرض بازه یکماهه متنی
|
||||
const now = new Date();
|
||||
// بدون وابستگی سنگین: مقادیر نمونه قابل ویرایش
|
||||
toDate.value = `${now.getFullYear() - 621}-01-01`;
|
||||
// بهتر: از API تاریخ نخواهیم؛ فیلدها را خالیتر با placeholder بگذاریم
|
||||
const y = 1405;
|
||||
fromDate.value = `${y}-01-01`;
|
||||
toDate.value = `${y}-12-29`;
|
||||
sanad.value.year = y;
|
||||
sanad.value.month = 1;
|
||||
sanad.value.day = 1;
|
||||
const from = new Date(now);
|
||||
from.setMonth(from.getMonth() - 6);
|
||||
fromDate.value = formatLocalDateInput(from);
|
||||
toDate.value = formatLocalDateInput(now);
|
||||
const j = dateToJalali(now);
|
||||
sanad.value.year = j.jy;
|
||||
sanad.value.month = j.jm;
|
||||
sanad.value.day = j.jd;
|
||||
}
|
||||
|
||||
function emitLinkCode() {
|
||||
emit('linkChanged', currentLink.value?.moshtariCode ?? null);
|
||||
}
|
||||
|
||||
async function loadConnectionsAndLinks() {
|
||||
@@ -155,6 +176,12 @@ async function loadConnectionsAndLinks() {
|
||||
) {
|
||||
connectionId.value = def?.id ?? '';
|
||||
}
|
||||
if (!currentLink.value && links.value.length) {
|
||||
const preferred =
|
||||
links.value.find((l) => l.isDefaultConnection) ?? links.value[0];
|
||||
if (preferred) connectionId.value = preferred.connectionId;
|
||||
}
|
||||
emitLinkCode();
|
||||
} catch (e) {
|
||||
error.value = axios.isAxiosError(e)
|
||||
? String(
|
||||
@@ -162,6 +189,7 @@ async function loadConnectionsAndLinks() {
|
||||
'بارگذاری اتصال تهحساب ناموفق بود.',
|
||||
)
|
||||
: 'بارگذاری اتصال تهحساب ناموفق بود.';
|
||||
emit('linkChanged', null);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -195,8 +223,10 @@ async function refreshAssets() {
|
||||
|
||||
async function loadAsnad() {
|
||||
if (!connectionId.value || !currentLink.value) return;
|
||||
if (!fromDate.value || !toDate.value) {
|
||||
error.value = 'تاریخ از و تا را وارد کنید (شمسی YYYY-MM-DD).';
|
||||
const from = toShamsiYmd(fromDate.value);
|
||||
const to = toShamsiYmd(toDate.value);
|
||||
if (!from || !to) {
|
||||
error.value = 'تاریخ از و تا را از تقویم انتخاب کنید.';
|
||||
return;
|
||||
}
|
||||
asnadLoading.value = true;
|
||||
@@ -207,12 +237,16 @@ async function loadAsnad() {
|
||||
{
|
||||
params: {
|
||||
connectionId: connectionId.value,
|
||||
from: fromDate.value,
|
||||
to: toDate.value,
|
||||
from,
|
||||
to,
|
||||
},
|
||||
timeout: 60_000,
|
||||
},
|
||||
);
|
||||
asnadItems.value = data.items ?? [];
|
||||
ok.value = asnadItems.value.length
|
||||
? `${asnadItems.value.length} سند نمایش داده شد.`
|
||||
: 'در این بازه سندی یافت نشد.';
|
||||
} catch (e) {
|
||||
error.value = axios.isAxiosError(e)
|
||||
? String(
|
||||
@@ -315,6 +349,7 @@ async function unlink() {
|
||||
`/integrations/tahesab/people/${props.personId}/links/${connectionId.value}`,
|
||||
);
|
||||
assets.value = null;
|
||||
asnadItems.value = [];
|
||||
await loadConnectionsAndLinks();
|
||||
}
|
||||
|
||||
@@ -355,10 +390,17 @@ async function pushSanad() {
|
||||
watch(connectionId, async () => {
|
||||
matchCandidates.value = [];
|
||||
asnadItems.value = [];
|
||||
emitLinkCode();
|
||||
if (currentLink.value) await refreshAssets();
|
||||
else assets.value = null;
|
||||
});
|
||||
|
||||
watch(activeTab, (t) => {
|
||||
if (t === 'جزئیات حساب' && currentLink.value && !asnadItems.value.length) {
|
||||
void loadAsnad();
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
defaultJalaliRange();
|
||||
await loadConnectionsAndLinks();
|
||||
@@ -374,8 +416,8 @@ onMounted(async () => {
|
||||
</p>
|
||||
|
||||
<template v-else>
|
||||
<div class="toolbar">
|
||||
<label v-if="hasMultipleConnections" class="conn-pick">
|
||||
<div v-if="hasMultipleConnections" class="toolbar">
|
||||
<label class="conn-pick">
|
||||
<span>اتصال</span>
|
||||
<select v-model="connectionId">
|
||||
<option v-for="c in connections" :key="c.id" :value="c.id">
|
||||
@@ -383,19 +425,12 @@ onMounted(async () => {
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<div v-else-if="connections[0]" class="muted">
|
||||
اتصال: {{ connections[0].label }} · DB {{ connections[0].dbName }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="link-bar card">
|
||||
<template v-if="currentLink">
|
||||
<div>
|
||||
<strong>لینکشده</strong>
|
||||
<span class="muted">
|
||||
کد تهحساب: {{ currentLink.moshtariCode }} · روش:
|
||||
{{ currentLink.matchMethod }}
|
||||
</span>
|
||||
<strong>لینکشده به تهحساب</strong>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="button" class="btn ghost" @click="refreshAssets">بروزرسانی مانده</button>
|
||||
@@ -506,11 +541,11 @@ onMounted(async () => {
|
||||
<div class="date-row">
|
||||
<label>
|
||||
از
|
||||
<input v-model="fromDate" dir="ltr" placeholder="1405-01-01" />
|
||||
<JalaliDateInput v-model="fromDate" placeholder="از تاریخ" />
|
||||
</label>
|
||||
<label>
|
||||
تا
|
||||
<input v-model="toDate" dir="ltr" placeholder="1405-12-29" />
|
||||
<JalaliDateInput v-model="toDate" placeholder="تا تاریخ" />
|
||||
</label>
|
||||
<button type="button" class="btn" :disabled="asnadLoading" @click="loadAsnad">
|
||||
{{ asnadLoading ? '…' : 'نمایش اسناد' }}
|
||||
@@ -790,6 +825,10 @@ onMounted(async () => {
|
||||
align-items: end;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.date-row label {
|
||||
min-width: 160px;
|
||||
flex: 1;
|
||||
}
|
||||
.date-row label,
|
||||
.sanad-form label {
|
||||
display: grid;
|
||||
|
||||
Reference in New Issue
Block a user