From d33d88e76dbb5e912eb45f84a67697df17e2cfd8 Mon Sep 17 00:00:00 2001 From: Mahdi Date: Sun, 8 Nov 2026 17:34:12 +0330 Subject: [PATCH] feat(finance): show payroll details and search payment periods Keep long reasons out of the report table, open them with payments in a details view, and let a payment period be found by name or month. Co-authored-by: Cursor --- .../views/treasury/TreasuryPayrollView.vue | 162 +++++++++++++----- 1 file changed, 123 insertions(+), 39 deletions(-) diff --git a/apps/web/src/views/treasury/TreasuryPayrollView.vue b/apps/web/src/views/treasury/TreasuryPayrollView.vue index f1caaf8..a29faf4 100644 --- a/apps/web/src/views/treasury/TreasuryPayrollView.vue +++ b/apps/web/src/views/treasury/TreasuryPayrollView.vue @@ -6,21 +6,24 @@ import { Button as AButton, Card as ACard, Col as ACol, + Descriptions as ADescriptions, + DescriptionsItem as ADescriptionsItem, Empty as AEmpty, Flex as AFlex, Form as AForm, FormItem as AFormItem, - Input as AInput, + Modal as AModal, Row as ARow, Select as ASelect, Space as ASpace, Table as ATable, + Textarea as ATextarea, Tooltip as ATooltip, Typography, message, theme, } from 'ant-design-vue'; -import { EditOutlined, WalletOutlined } from '@ant-design/icons-vue'; +import { EditOutlined, EyeOutlined, WalletOutlined } from '@ant-design/icons-vue'; import type { TableColumnsType } from 'ant-design-vue'; import { api } from '@/lib/api'; import type { FinancialAccountDto, OrgUserDto } from '@mento/shared'; @@ -99,6 +102,7 @@ const form = ref({ const pay = ref({ id: '', amount: '', accountId: undefined as string | undefined }); const editingId = ref(''); const editingPaymentId = ref(''); +const detail = ref(null); const filterUserId = ref(undefined); const filterYear = ref(undefined); const filterMonth = ref(undefined); @@ -203,33 +207,36 @@ const paymentColumns: TableColumnsType = [ { title: 'عملیات', key: 'action' }, ]; +const detailPaymentColumns: TableColumnsType = [ + { title: 'تاریخ', key: 'occurredAt' }, + { title: 'حساب', dataIndex: 'accountName', key: 'accountName' }, + { title: 'مبلغ', key: 'amount' }, +]; + function moneyFilled(value: string) { return (parseMoneyNumber(String(value ?? ''), 0) ?? 0) > 0; } +function normalizeSearch(value: string) { + return value + .trim() + .replace(/[يى]/g, 'ی') + .replace(/ك/g, 'ک') + .replace(/[۰-۹]/g, (digit) => String(digit.charCodeAt(0) - 0x06f0)) + .replace(/[٠-٩]/g, (digit) => String(digit.charCodeAt(0) - 0x0660)) + .toLowerCase(); +} + +function filterPayOption(input: string, option?: { label?: string }) { + return normalizeSearch(String(option?.label ?? '')).includes(normalizeSearch(input)); +} + function reasonFor(amount: string, reason: string) { if (!moneyFilled(amount)) return null; const text = reason.trim(); return text || null; } -function amountReason( - row: { - benefits?: string; - benefitsReason?: string | null; - bonus?: string; - bonusReason?: string | null; - deductions?: string; - deductionsReason?: string | null; - }, - key: 'benefits' | 'bonus' | 'deductions', -) { - if (!Number(row[key])) return ''; - if (key === 'benefits') return row.benefitsReason?.trim() || ''; - if (key === 'bonus') return row.bonusReason?.trim() || ''; - return row.deductionsReason?.trim() || ''; -} - function buildPeriod(year: number, month: number, day: number | null) { const startDay = Math.min(Math.max(1, Math.trunc(Number(day)) || 1), jalaliMonthLength(year, month)); const next = addJalaliMonths(year, month, 1); @@ -512,24 +519,48 @@ onMounted(() => { - - - - - - - - + + + + + + + + + + + + + + @@ -575,8 +606,9 @@ onMounted(() => { allow-clear show-search option-filter-prop="label" + :filter-option="filterPayOption" style="width: 100%" - placeholder="انتخاب دوره" + placeholder="جستجوی نام یا دوره" :options="payOptions" @change="onPayPick" /> @@ -729,6 +761,16 @@ onMounted(() => { - @@ -771,5 +802,58 @@ onMounted(() => { + + + + + {{ detail.fullName }} + {{ formatPeriod(detail.period) }} + {{ statusLabel[detail.status] ?? detail.status }} + {{ toman(detail.baseAmount) }} + {{ toman(detail.benefits) }} + + {{ detail.benefitsReason }} + + {{ toman(detail.bonus) }} + + {{ detail.bonusReason }} + + {{ toman(detail.deductions) }} + + {{ detail.deductionsReason }} + + {{ toman(detail.payable) }} + {{ toman(detail.paidAmount) }} + {{ toman(detail.remaining) }} + + پرداخت‌ها + + + + + +