fix(dashboard): fix date conversion offset, calendar arrow directions, payment duplicate warning, attendance class filter, and session auto-generation

This commit is contained in:
2026-08-23 14:15:26 +03:30
parent 497b065b5c
commit de87412bb1
11 changed files with 279 additions and 73 deletions
+8 -2
View File
@@ -152,7 +152,10 @@
<div class="flex flex-column gap-3 py-2">
<div class="flex flex-column gap-2">
<label class="font-semibold text-sm">مبلغ واریزی (تومان) *</label>
<InputNumber v-model="trxForm.amount" class="w-full text-sm" suffix=" تومان" :min="1" />
<InputGroup>
<InputNumber v-model="trxForm.amount" class="w-full text-sm" :min="1" />
<InputGroupAddon>تومان</InputGroupAddon>
</InputGroup>
</div>
<div class="flex flex-column gap-2">
<label class="font-semibold text-sm">وضعیت تراکنش *</label>
@@ -198,7 +201,10 @@
<div class="flex flex-column gap-3 py-2">
<div class="flex flex-column gap-2">
<label class="font-semibold text-sm">مبلغ (تومان) *</label>
<InputNumber v-model="editForm.amount" class="w-full text-sm" suffix=" تومان" :min="0" />
<InputGroup>
<InputNumber v-model="editForm.amount" class="w-full text-sm" :min="0" />
<InputGroupAddon>تومان</InputGroupAddon>
</InputGroup>
</div>
<div class="flex flex-column gap-2">
<label class="font-semibold text-sm">وضعیت تراکنش *</label>
+51 -24
View File
@@ -109,7 +109,7 @@
:placeholder="createForm.classes?.length ? 'دانشجوی ثبت‌نام‌شده را انتخاب کنید' : 'ابتدا کلاس را انتخاب کنید'"
class="w-full text-sm"
:disabled="!createForm.classes?.length"
@change="checkDuplicateInvoice"
@change="() => checkDuplicateInvoice()"
/>
<small v-if="createForm.classes?.length && !eligibleUsers.length" class="text-orange-500">
هیچ دانشجوی ثبت‌نام‌شده‌ای در کلاس‌های انتخاب‌شده یافت نشد
@@ -132,7 +132,10 @@
<div class="flex flex-column gap-2">
<label class="font-semibold text-sm" for="invoice-amount">مبلغ کل صورتحساب (تومان) *</label>
<InputNumber inputId="invoice-amount" v-model="createForm.amount" class="w-full text-sm" suffix=" تومان" :min="0" />
<InputGroup>
<InputNumber inputId="invoice-amount" v-model="createForm.amount" class="w-full text-sm" :min="0" />
<InputGroupAddon>تومان</InputGroupAddon>
</InputGroup>
</div>
<div class="flex align-items-center gap-2">
@@ -142,14 +145,16 @@
<div v-if="hasDiscount" class="flex flex-column gap-2">
<label class="font-semibold text-sm" for="invoice-discount-amount">مبلغ تخفیف (تومان)</label>
<InputNumber
inputId="invoice-discount-amount"
v-model="createForm.discount"
class="w-full text-sm"
suffix=" تومان"
:min="0"
:max="createForm.amount || 0"
/>
<InputGroup>
<InputNumber
inputId="invoice-discount-amount"
v-model="createForm.discount"
class="w-full text-sm"
:min="0"
:max="createForm.amount || 0"
/>
<InputGroupAddon>تومان</InputGroupAddon>
</InputGroup>
<small class="font-semibold text-color">
مبلغ نهایی: {{ toPersianDigits(createPayableAmount.toLocaleString()) }} تومان
</small>
@@ -204,7 +209,10 @@
<div class="flex flex-column gap-2">
<label class="font-semibold text-sm" for="bulk-invoice-amount">مبلغ شهریه هر دانشجو (تومان) *</label>
<InputNumber inputId="bulk-invoice-amount" v-model="bulkForm.amount" class="w-full text-sm" suffix=" تومان" :min="0" />
<InputGroup>
<InputNumber inputId="bulk-invoice-amount" v-model="bulkForm.amount" class="w-full text-sm" :min="0" />
<InputGroupAddon>تومان</InputGroupAddon>
</InputGroup>
</div>
<div class="flex align-items-center gap-2">
@@ -214,14 +222,16 @@
<div v-if="hasBulkDiscount" class="flex flex-column gap-2">
<label class="font-semibold text-sm" for="bulk-invoice-discount-amount">مبلغ تخفیف (تومان)</label>
<InputNumber
inputId="bulk-invoice-discount-amount"
v-model="bulkForm.discount"
class="w-full text-sm"
suffix=" تومان"
:min="0"
:max="bulkForm.amount || 0"
/>
<InputGroup>
<InputNumber
inputId="bulk-invoice-discount-amount"
v-model="bulkForm.discount"
class="w-full text-sm"
:min="0"
:max="bulkForm.amount || 0"
/>
<InputGroupAddon>تومان</InputGroupAddon>
</InputGroup>
<small class="font-semibold text-color">
مبلغ نهایی هر صورتحساب: {{ toPersianDigits(bulkPayableAmount.toLocaleString()) }} تومان
</small>
@@ -298,6 +308,8 @@ import Dialog from 'primevue/dialog';
import Dropdown from 'primevue/select';
import MultiSelect from 'primevue/multiselect';
import InputNumber from 'primevue/inputnumber';
import InputGroup from 'primevue/inputgroup';
import InputGroupAddon from 'primevue/inputgroupaddon';
import Checkbox from 'primevue/checkbox';
import Textarea from 'primevue/textarea';
import DatePicker from 'vue3-persian-datetime-picker';
@@ -391,18 +403,33 @@ const eligibleUsers = computed(() => {
return usersList.value.filter((u) => eligibleIds?.has(String(u._id || u.id)));
});
const extractId = (val) => {
if (!val) return null;
if (typeof val === 'object') {
if (val.value !== undefined && (typeof val.value === 'string' || typeof val.value === 'number')) {
return String(val.value);
}
return val._id ? String(val._id) : (val.id ? String(val.id) : null);
}
return String(val);
};
const checkDuplicateInvoice = async (userIdVal = null) => {
const targetUser = userIdVal || createForm.user;
if (!targetUser || !createForm.classes || !createForm.classes.length) {
const targetUserId = extractId(userIdVal) || extractId(createForm.user);
if (!targetUserId || !createForm.classes || !createForm.classes.length) {
duplicateWarning.value = null;
return;
}
try {
const classIds = Array.isArray(createForm.classes)
? createForm.classes.map((c) => c?._id || c?.id || c).join(',')
: String(createForm.classes);
? createForm.classes.map(extractId).filter(Boolean).join(',')
: (extractId(createForm.classes) || '');
if (!classIds) {
duplicateWarning.value = null;
return;
}
const res = await paymentApi.checkDuplicate({
userId: String(targetUser?._id || targetUser?.id || targetUser),
userId: targetUserId,
classes: classIds
});
duplicateWarning.value = res.data?.data || res.data || res;