feat: add withdraw request functionality and UI components
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useForm } from '@inertiajs/inertia-vue3';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import { toast } from 'vue3-toastify';
|
||||
import ClientLayout from '../../../layouts/ClientLayout.vue';
|
||||
import UiButton from '../../../components/ui/UiButton.vue';
|
||||
import CaseSpecsCard from '../../../components/dashboard/cases/CaseSpecsCard.vue';
|
||||
import ReportSectionCard from '../../../components/dashboard/cases/ReportSectionCard.vue';
|
||||
import FileUploadBox from '../../../components/dashboard/fastRequest/FileUploadBox.vue';
|
||||
import { modalityTitle } from '../../../data/fastRequestOptions';
|
||||
import { convertEnglishToPersian } from '../../../utils/numberUtils';
|
||||
|
||||
const props = defineProps({
|
||||
case: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
canReport: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const petRows = computed(() => [
|
||||
{ label: 'نام', value: props.case.pet?.name },
|
||||
{ label: 'نوع', value: props.case.pet?.type },
|
||||
{ label: 'جنسیت', value: props.case.pet?.gender },
|
||||
{ label: 'نژاد', value: props.case.pet?.breed },
|
||||
{ label: 'سن', value: props.case.pet?.age !== null && props.case.pet?.age !== undefined ? `${convertEnglishToPersian(props.case.pet.age)} سال` : null },
|
||||
{ label: 'وزن', value: props.case.pet?.weight ? `${convertEnglishToPersian(props.case.pet.weight)} کیلو گرم` : null },
|
||||
{ label: 'وضعیت عقیمسازی', value: props.case.pet?.sterilized === null ? null : (props.case.pet?.sterilized ? 'عقیم شده' : 'عقیم نشده') },
|
||||
]);
|
||||
|
||||
const requesterRows = computed(() => {
|
||||
const requester = props.case.requester || {};
|
||||
return [
|
||||
{ label: 'نوع', value: requester.level },
|
||||
{ label: 'نام و نام خانوادگی', value: requester.fullname },
|
||||
{ label: 'شماره موبایل', value: requester.phone ? convertEnglishToPersian(requester.phone) : null },
|
||||
{ label: 'تخصص', value: requester.specialty },
|
||||
{ label: 'کلینیک', value: requester.clinic_name },
|
||||
{ label: 'تلفن کلینیک', value: requester.clinic_phone ? convertEnglishToPersian(requester.clinic_phone) : null },
|
||||
{ label: 'محل اقامت', value: [requester.province, requester.city].filter(Boolean).join('، ') || null },
|
||||
].filter((row) => row.value);
|
||||
});
|
||||
|
||||
const remainingLabel = ref(null);
|
||||
let timerId = null;
|
||||
|
||||
const updateRemaining = () => {
|
||||
if (!props.case.processing_deadline) {
|
||||
remainingLabel.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const diff = Math.floor((new Date(props.case.processing_deadline).getTime() - Date.now()) / 1000);
|
||||
|
||||
if (diff <= 0) {
|
||||
remainingLabel.value = 'اتمام فرصت رسیدگی';
|
||||
return;
|
||||
}
|
||||
|
||||
const pad = (value) => String(value).padStart(2, '0');
|
||||
remainingLabel.value = convertEnglishToPersian(`${pad(Math.floor(diff / 3600))}:${pad(Math.floor((diff % 3600) / 60))}:${pad(diff % 60)}`) + ' تا پایان زمان ثبت گزارش';
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
updateRemaining();
|
||||
timerId = setInterval(updateRemaining, 1000);
|
||||
});
|
||||
|
||||
onUnmounted(() => clearInterval(timerId));
|
||||
|
||||
const openFiles = (files) => {
|
||||
files.forEach((file) => window.open(file.url, '_blank'));
|
||||
};
|
||||
|
||||
const reportForm = useForm({
|
||||
document_id: props.case.id,
|
||||
technique: props.case.report?.technique || '',
|
||||
finding: props.case.report?.finding || '',
|
||||
diagnose: props.case.report?.diagnose || '',
|
||||
recommendation: props.case.report?.recommendation || '',
|
||||
files: [],
|
||||
});
|
||||
|
||||
const submitReport = () => {
|
||||
reportForm.post('/dashboard/reports', {
|
||||
forceFormData: true,
|
||||
onError: () => toast.error('لطفا موارد مشخصشده را بررسی و اصلاح کنید.'),
|
||||
});
|
||||
};
|
||||
|
||||
const rejectModalVisible = ref(false);
|
||||
const rejectReason = ref('');
|
||||
const rejecting = ref(false);
|
||||
|
||||
const submitReject = () => {
|
||||
if (!rejectReason.value.trim()) {
|
||||
toast.error('لطفا دلیل رد درخواست را وارد کنید.');
|
||||
return;
|
||||
}
|
||||
|
||||
rejecting.value = true;
|
||||
Inertia.post(`/dashboard/cases/${props.case.id}/reject`, { reason: rejectReason.value }, {
|
||||
onFinish: () => {
|
||||
rejecting.value = false;
|
||||
rejectModalVisible.value = false;
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientLayout>
|
||||
<div class="flex flex-col gap-4">
|
||||
<header class="bg-white border border-complement-50 rounded-2xl px-4 py-3 flex items-center justify-between flex-wrap gap-2">
|
||||
<h1 class="text-[13px] font-bold text-[#3E4C63]">پرونده شماره {{ convertEnglishToPersian(props.case.code) }}</h1>
|
||||
<div class="flex items-center gap-3 text-[11px]">
|
||||
<span v-if="canReport && remainingLabel" class="font-semibold text-[#7A1419]">{{ remainingLabel }}</span>
|
||||
<span v-else class="font-normal text-[#576989]">وضعیت فعلی</span>
|
||||
<span class="font-semibold text-[#3E4C63] border-r border-[#DEE3EB] pr-3">{{ props.case.status }}</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="grid grid-cols-[16rem_1fr] max-lg:grid-cols-1 gap-4 items-start">
|
||||
<aside class="flex flex-col gap-4">
|
||||
<CaseSpecsCard title="مشخصات کیس" :rows="petRows" />
|
||||
<CaseSpecsCard v-if="canReport && requesterRows.length" title="مشخصات درخواستدهنده" :rows="requesterRows" />
|
||||
</aside>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<section class="bg-white border border-complement-50 rounded-2xl p-4 flex flex-col gap-3">
|
||||
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
|
||||
جزئیات درخواست
|
||||
</h2>
|
||||
<div class="flex items-center gap-3 flex-wrap text-[11px]">
|
||||
<p><span class="font-normal text-[#576989]">گزارش درخواستشده:</span> <span class="font-semibold text-[#7A1419]">{{ modalityTitle(props.case.modality) }}</span></p>
|
||||
<span class="text-[#DEE3EB]">|</span>
|
||||
<p><span class="font-normal text-[#576989]">نوع درخواست:</span> <span class="font-semibold text-[#7A1419]">{{ props.case.priority }}</span></p>
|
||||
<span class="text-[#DEE3EB]">|</span>
|
||||
<p><span class="font-normal text-[#576989]">زمان درخواست:</span> <span class="font-semibold text-[#3E4C63]">{{ props.case.submitted_at ? convertEnglishToPersian(props.case.submitted_at) : '-' }}</span></p>
|
||||
</div>
|
||||
<div class="text-[12px] leading-6">
|
||||
<p class="font-normal text-[#576989]">تاریخچه بیماری:</p>
|
||||
<p class="font-normal text-[#3E4C63] whitespace-pre-line">{{ props.case.note || 'توضیحی ثبت نشده است.' }}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 flex-wrap pt-2 border-t border-[#EBEBEB]">
|
||||
<UiButton label="دانلود فایل درخواست" severity="secondary" size="small" :disabled="!props.case.primary_files.length" @click="openFiles(props.case.primary_files)" />
|
||||
<UiButton label="دانلود سوابق پزشکی قبلی" severity="secondary" size="small" :disabled="!props.case.history_files.length" @click="openFiles(props.case.history_files)" />
|
||||
<UiButton v-if="!canReport && props.case.report" label="دانلود فایل گزارش" severity="secondary" size="small" :disabled="!props.case.report.attachments.length" @click="openFiles(props.case.report.attachments)" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<p v-if="props.case.rejection_reason" class="bg-[#F8E9EA] border border-[#E7C3C5] rounded-2xl p-4 text-[12px] font-normal text-[#7A1419] leading-6">
|
||||
دلیل رد درخواست: {{ props.case.rejection_reason }}
|
||||
</p>
|
||||
|
||||
<template v-if="canReport">
|
||||
<ReportSectionCard v-model="reportForm.technique" title="تکنیک (Technique)" editable placeholder="شرح تکنیک را وارد کنید" :error="reportForm.errors.technique" />
|
||||
<ReportSectionCard v-model="reportForm.finding" title="یافتهها (Finding)" editable placeholder="یافتهها را وارد کنید" :error="reportForm.errors.finding" />
|
||||
<ReportSectionCard v-model="reportForm.diagnose" title="تشخیص (Diagnose)" editable placeholder="تشخیص را وارد کنید" :error="reportForm.errors.diagnose" />
|
||||
<ReportSectionCard v-model="reportForm.recommendation" title="پیشنهادات (Recommendation)" editable placeholder="پیشنهادات را وارد کنید" :error="reportForm.errors.recommendation" />
|
||||
|
||||
<section class="bg-white border border-complement-50 rounded-2xl p-4 flex flex-col gap-3">
|
||||
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
|
||||
آپلود فایل و مستندات
|
||||
</h2>
|
||||
<FileUploadBox v-model="reportForm.files" title="آپلود فایل و مستندات گزارش" />
|
||||
</section>
|
||||
|
||||
<footer class="bg-white border border-complement-50 rounded-2xl p-4 flex items-center justify-between flex-wrap gap-3">
|
||||
<p class="text-[11px] font-normal text-[#576989]">با تایید گزارش و یا رد درخواست دیگر امکان ویرایش آن را نخواهید داشت.</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<button type="button" class="text-[11px] font-semibold text-[#7A1419]" @click="rejectModalVisible = true">رد درخواست</button>
|
||||
<UiButton label="تایید و ثبت گزارش" severity="success" size="small" :loading="reportForm.processing" :disabled="reportForm.processing" @click="submitReport" />
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<ReportSectionCard :model-value="props.case.report?.technique || ''" title="تکنیک (Technique)" />
|
||||
<ReportSectionCard :model-value="props.case.report?.finding || ''" title="یافتهها (Finding)" />
|
||||
<ReportSectionCard :model-value="props.case.report?.diagnose || ''" title="تشخیص (Diagnose)" />
|
||||
<ReportSectionCard :model-value="props.case.report?.recommendation || ''" title="پیشنهادات (Recommendation)" />
|
||||
|
||||
<section class="bg-white border border-complement-50 rounded-2xl p-4 flex flex-col gap-3">
|
||||
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
|
||||
آپلود فایل و مستندات
|
||||
</h2>
|
||||
<div v-if="props.case.report?.attachments?.length" class="flex flex-wrap gap-4">
|
||||
<a v-for="file in props.case.report.attachments" :key="file.id" :href="file.url" target="_blank" class="relative w-[5rem] h-[5rem] rounded-lg border border-gray-200 overflow-hidden">
|
||||
<img :alt="file.filename" :src="file.url" class="absolute top-0 left-0 w-full h-full object-cover" />
|
||||
</a>
|
||||
</div>
|
||||
<p v-else class="w-full min-h-[5rem] bg-[#F8FAFC] border border-[#DEE3EB] rounded-xl p-4 text-[12px] font-normal text-[#576989] leading-6 flex items-center justify-center text-center">
|
||||
عکسی برای این پرونده آپلود نشده است.
|
||||
</p>
|
||||
</section>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog v-model:visible="rejectModalVisible" :modal="true" :closable="true" :dismissableMask="false" :style="{ width: '480px' }" class="fast-request-dialog" :pt="{ header: '!bg-client-primaryBlue' }">
|
||||
<template #header>
|
||||
<div class="w-full flex items-center justify-start">
|
||||
<h2 class="text-[14px] font-[700] text-[#576989]">رد درخواست</h2>
|
||||
</div>
|
||||
</template>
|
||||
<div class="w-full flex flex-col gap-3 border-t border-[#EBEBEB] pt-4">
|
||||
<p class="text-[12px] font-normal text-[#3E4C63] leading-6">پس از رد درخواست، مبلغ فاکتور به کیف پول درخواستکننده بازگردانده میشود.</p>
|
||||
<textarea
|
||||
v-model="rejectReason"
|
||||
rows="4"
|
||||
placeholder="دلیل رد درخواست را وارد کنید"
|
||||
class="w-full bg-[#F8FAFC] border border-[#DEE3EB] rounded-xl p-4 text-[12px] font-normal text-[#3E4C63] leading-6 outline-none focus:border-[#C1D0E8] resize-y"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="w-full pt-3 flex items-center justify-start gap-2 border-t border-[#EBEBEB]">
|
||||
<UiButton label="رد درخواست" severity="danger" size="small" :loading="rejecting" :disabled="rejecting" @click="submitReject" />
|
||||
<UiButton label="انصراف" severity="secondary" size="small" :disabled="rejecting" @click="rejectModalVisible = false" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</ClientLayout>
|
||||
</template>
|
||||
@@ -7,9 +7,10 @@ import UiButton from '../../components/ui/UiButton.vue';
|
||||
import EyeSvg from '../../components/svg/eye.svg';
|
||||
import UiCard from '../../components/ui/UiCard.vue';
|
||||
import RequestCard from '../../components/dashboard/RequestCard.vue';
|
||||
import { ref } from 'vue';
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { Link, usePage } from '@inertiajs/inertia-vue3';
|
||||
import FastRequestModal from '../../components/dashboard/FastRequestModal.vue';
|
||||
import PaymentResultModal from '../../components/dashboard/PaymentResultModal.vue';
|
||||
import { useFastRequestStore } from '../../store/FastRequest';
|
||||
import { modalities } from '../../data/fastRequestOptions';
|
||||
import { caseColumns } from '../../data/casesTableColumns';
|
||||
@@ -22,6 +23,17 @@ const openFastRequestModal = (type) => {
|
||||
fastRequestStore.requestType = type;
|
||||
}
|
||||
|
||||
const paymentResultVisible = ref(false);
|
||||
const paymentResult = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
const result = usePage().props.value.flash?.payment_result;
|
||||
if (result) {
|
||||
paymentResult.value = result;
|
||||
paymentResultVisible.value = true;
|
||||
}
|
||||
})
|
||||
|
||||
defineProps({
|
||||
user: {
|
||||
type: Object,
|
||||
@@ -30,13 +42,17 @@ defineProps({
|
||||
cases: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
stats: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientLayout>
|
||||
<ActivitiesWidget />
|
||||
<ActivitiesWidget :stats="stats" />
|
||||
<UiCard title="ثبت آنی درخواست جدید" variant="default" class="mt-4">
|
||||
<p class="w-full flex items-center justify-start font-[400] text-[11px]">فقط چند قدم ساده برای ثبت درخواست کافیه.</p>
|
||||
<div class="w-full h-[179px] grid grid-cols-5 gap-3 justify-start pt-[10px]">
|
||||
@@ -77,5 +93,6 @@ defineProps({
|
||||
<ActivitiesChart />
|
||||
</UiCard>
|
||||
<fast-request-modal v-model:visible="fastRequestModalVisible"></fast-request-modal>
|
||||
<payment-result-modal v-model:visible="paymentResultVisible" :result="paymentResult"></payment-result-modal>
|
||||
</ClientLayout>
|
||||
</template>
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<script setup>
|
||||
import ClientLayout from '../../../layouts/ClientLayout.vue';
|
||||
|
||||
const props = defineProps({
|
||||
document: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<ClientLayout>
|
||||
<h1>{{ document.title }}</h1>
|
||||
<p>{{ document.description }}</p>
|
||||
<p>{{ document.created_at }}</p>
|
||||
<p>{{ document.updated_at }}</p>
|
||||
<p>{{ document.status }}</p>
|
||||
<p>{{ document.priority }}</p>
|
||||
<p>{{ document.note }}</p>
|
||||
<p>{{ document.modality }}</p>
|
||||
<p>{{ document.pet_id }}</p>
|
||||
<p>{{ document.requester_id }}</p>
|
||||
</ClientLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,55 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import ClientLayout from '../../../layouts/ClientLayout.vue';
|
||||
import TableGeneric from '../../../components/ui/TableGeneric.vue';
|
||||
import UiCard from '../../../components/ui/UiCard.vue';
|
||||
import UiButton from '../../../components/ui/UiButton.vue';
|
||||
import InvoiceModal from '../../../components/dashboard/fastRequest/InvoiceModal.vue';
|
||||
import { invoiceColumns } from '../../../data/invoicesTableColumns';
|
||||
|
||||
defineProps({
|
||||
invoices: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const selectedInvoice = ref(null);
|
||||
const invoiceModalVisible = ref(false);
|
||||
|
||||
const openInvoice = (invoice) => {
|
||||
selectedInvoice.value = invoice;
|
||||
invoiceModalVisible.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientLayout>
|
||||
<UiCard title="لیست فاکتورها" variant="default">
|
||||
<TableGeneric
|
||||
class="bg-white !rounded-2xl"
|
||||
:data="invoices.data"
|
||||
customStyle="!text-[11px] !font-normal"
|
||||
:searchable="false"
|
||||
:columns="invoiceColumns"
|
||||
:selectable="false"
|
||||
:pagination="invoices.meta"
|
||||
:model-value="[]"
|
||||
>
|
||||
<template #column-actions="{ data }">
|
||||
<div class="flex items-center justify-end">
|
||||
<UiButton
|
||||
v-if="data.status === 'در انتظار پرداخت'"
|
||||
label="پرداخت"
|
||||
severity="success"
|
||||
size="small"
|
||||
@click="openInvoice(data)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</TableGeneric>
|
||||
</UiCard>
|
||||
|
||||
<InvoiceModal v-model:visible="invoiceModalVisible" :invoice="selectedInvoice" />
|
||||
</ClientLayout>
|
||||
</template>
|
||||
@@ -1,11 +1,42 @@
|
||||
<script setup>
|
||||
import ClientLayout from '../../../layouts/ClientLayout.vue'
|
||||
import ClientLayout from '../../../layouts/ClientLayout.vue';
|
||||
import TableGeneric from '../../../components/ui/TableGeneric.vue';
|
||||
import UiCard from '../../../components/ui/UiCard.vue';
|
||||
import EyeSvg from '../../../components/svg/eye.svg';
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import { reportColumns } from '../../../data/reportsTableColumns';
|
||||
|
||||
defineProps({
|
||||
reports: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientLayout>
|
||||
<h1 class="text-2xl font-bold">
|
||||
Reports
|
||||
</h1>
|
||||
<UiCard title="گزارشات" variant="default">
|
||||
<TableGeneric
|
||||
class="bg-white !rounded-2xl"
|
||||
:data="reports.data"
|
||||
customStyle="!text-[11px] !font-normal"
|
||||
:searchable="false"
|
||||
:columns="reportColumns"
|
||||
:selectable="false"
|
||||
:pagination="reports.meta"
|
||||
:model-value="[]"
|
||||
>
|
||||
<template #column-actions="{ data }">
|
||||
<div class="flex items-center justify-end">
|
||||
<Link :href="`/dashboard/cases/${data.document?.id}`"
|
||||
class="text-primary-500 bg-complement-100 flex items-center justify-end p-1.5 rounded-md"
|
||||
>
|
||||
<EyeSvg class="w-4 h-4 text-primary-500" />
|
||||
</Link>
|
||||
</div>
|
||||
</template>
|
||||
</TableGeneric>
|
||||
</UiCard>
|
||||
</ClientLayout>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { usePage } from '@inertiajs/inertia-vue3';
|
||||
import { toast } from 'vue3-toastify';
|
||||
import ClientLayout from '../../../layouts/ClientLayout.vue';
|
||||
import TableGeneric from '../../../components/ui/TableGeneric.vue';
|
||||
import UiCard from '../../../components/ui/UiCard.vue';
|
||||
import UiInput from '../../../components/ui/UiInput.vue';
|
||||
import UiButton from '../../../components/ui/UiButton.vue';
|
||||
import WalletSvg from '../../../components/svg/wallet.svg';
|
||||
import WithdrawRequestCard from '../../../components/dashboard/wallet/WithdrawRequestCard.vue';
|
||||
import { walletTransactionColumns } from '../../../data/walletTransactionsTableColumns';
|
||||
import { withdrawRequestColumns } from '../../../data/withdrawRequestsTableColumns';
|
||||
import { convertEnglishToPersian, convertPersianToEnglish, formatPrice } from '../../../utils/numberUtils';
|
||||
|
||||
const props = defineProps({
|
||||
transactions: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
withdrawRequests: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
bankCards: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const { props: pageProps } = usePage();
|
||||
|
||||
const quickAmounts = [100000, 200000, 500000];
|
||||
|
||||
const amount = ref('');
|
||||
const depositing = ref(false);
|
||||
|
||||
const numericAmount = computed(() => Number(convertPersianToEnglish(amount.value).replace(/\D/g, '')) || 0);
|
||||
|
||||
const formattedBalance = computed(() => formatPrice(pageProps.value.auth?.wallet_balance || 0));
|
||||
|
||||
const pendingWithdrawAmount = computed(() => props.withdrawRequests
|
||||
.filter((request) => request.status === 'در انتظار بررسی')
|
||||
.reduce((sum, request) => sum + request.amount, 0));
|
||||
|
||||
const withdrawStatusClasses = (status) => {
|
||||
if (status === 'تایید شده') {
|
||||
return 'text-[#1F7A4D] bg-[#E6F4EC]';
|
||||
}
|
||||
|
||||
if (status === 'رد شده') {
|
||||
return 'text-[#7A1419] bg-[#F8E9EA]';
|
||||
}
|
||||
|
||||
return 'text-[#576989] bg-[#EEF2F8]';
|
||||
};
|
||||
|
||||
const formatCardNumber = (cardNumber) => convertEnglishToPersian(cardNumber.replace(/(\d{4})(?=\d)/g, '$1 - '));
|
||||
|
||||
const selectQuickAmount = (value) => {
|
||||
amount.value = String(value);
|
||||
};
|
||||
|
||||
const handleDeposit = async () => {
|
||||
if (numericAmount.value < 10000) {
|
||||
toast.error('حداقل مبلغ شارژ ۱۰٬۰۰۰ تومان است.');
|
||||
return;
|
||||
}
|
||||
|
||||
depositing.value = true;
|
||||
try {
|
||||
const { data } = await window.axios.post('/dashboard/wallet/deposit', { amount: numericAmount.value });
|
||||
window.location.href = data.url;
|
||||
} catch (error) {
|
||||
depositing.value = false;
|
||||
toast.error(error.response?.data?.message || 'خطا در اتصال به درگاه پرداخت. لطفا دوباره تلاش کنید.');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientLayout>
|
||||
<div class="flex flex-col gap-4">
|
||||
<UiCard title="کیف پول" variant="default">
|
||||
<div class="grid grid-cols-2 max-sm:grid-cols-1 gap-4">
|
||||
<div class="flex items-center gap-3 bg-[#EEF2F8] border border-[#DEE3EB] rounded-[12px] px-5 py-4">
|
||||
<WalletSvg class="w-6 h-6" />
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-[11px] font-normal text-[#576989]">موجودی کیف پول</span>
|
||||
<strong class="text-[16px] font-bold text-[#3E4C63]">{{ formattedBalance }} تومان</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 bg-[#F8FAFC] border border-[#DEE3EB] rounded-[12px] px-5 py-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-[11px] font-normal text-[#576989]">مبلغ در انتظار برداشت</span>
|
||||
<strong class="text-[16px] font-bold text-[#3E4C63]">{{ formatPrice(pendingWithdrawAmount) }} تومان</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UiCard>
|
||||
|
||||
<UiCard title="شارژ کیف پول" variant="default">
|
||||
<form class="flex flex-col gap-4" @submit.prevent="handleDeposit">
|
||||
<p class="text-[11px] font-normal text-[#576989] leading-6">
|
||||
مبلغ مورد نظر را وارد کنید؛ پس از پرداخت از طریق درگاه بانکی، موجودی کیف پول شما بلافاصله افزایش مییابد.
|
||||
</p>
|
||||
<div class="flex items-end gap-3 max-sm:flex-col max-sm:items-stretch">
|
||||
<UiInput
|
||||
v-model="amount"
|
||||
label="مبلغ شارژ"
|
||||
placeholder="مبلغ مورد نظر را به تومان وارد کنید"
|
||||
prefixEnd="تومان"
|
||||
prefixClasses="!border-dominant-50"
|
||||
class="!w-[22rem] max-sm:!w-full"
|
||||
customClass="!border-dominant-50 !font-normal !text-[12px]"
|
||||
/>
|
||||
<UiButton
|
||||
label="افزایش موجودی"
|
||||
severity="success"
|
||||
size="small"
|
||||
:loading="depositing"
|
||||
:disabled="depositing"
|
||||
@click="handleDeposit"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<button
|
||||
v-for="value in quickAmounts"
|
||||
:key="value"
|
||||
type="button"
|
||||
class="text-[11px] font-normal text-[#576989] bg-[#F5F7FA] border border-[#DEE3EB] rounded-lg px-3 py-1.5 hover:bg-[#EEF2F8]"
|
||||
@click="selectQuickAmount(value)"
|
||||
>
|
||||
{{ formatPrice(value) }} تومان
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</UiCard>
|
||||
|
||||
<WithdrawRequestCard :bank-cards="bankCards" />
|
||||
|
||||
<UiCard title="درخواستهای برداشت" variant="default">
|
||||
<TableGeneric
|
||||
class="bg-white !rounded-2xl"
|
||||
:data="withdrawRequests"
|
||||
customStyle="!text-[11px] !font-normal"
|
||||
:searchable="false"
|
||||
:columns="withdrawRequestColumns"
|
||||
:selectable="false"
|
||||
:pagination="null"
|
||||
:model-value="[]"
|
||||
>
|
||||
<template #column-bank_card="{ data }">
|
||||
<span v-if="data.bank_card" dir="ltr">{{ formatCardNumber(data.bank_card.card_number) }}</span>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
<template #column-status="{ data }">
|
||||
<span class="text-[11px] font-normal rounded-md px-2 py-1" :class="withdrawStatusClasses(data.status)">
|
||||
{{ data.status }}
|
||||
</span>
|
||||
</template>
|
||||
</TableGeneric>
|
||||
</UiCard>
|
||||
|
||||
<UiCard title="تراکنشها" variant="default">
|
||||
<TableGeneric
|
||||
class="bg-white !rounded-2xl"
|
||||
:data="transactions.data"
|
||||
customStyle="!text-[11px] !font-normal"
|
||||
:searchable="false"
|
||||
:columns="walletTransactionColumns"
|
||||
:selectable="false"
|
||||
:pagination="transactions.meta"
|
||||
:model-value="[]"
|
||||
>
|
||||
<template #column-type="{ data }">
|
||||
<span
|
||||
class="text-[11px] font-normal rounded-md px-2 py-1"
|
||||
:class="data.type === 'واریز' ? 'text-[#1F7A4D] bg-[#E6F4EC]' : 'text-[#7A1419] bg-[#F8E9EA]'"
|
||||
>
|
||||
{{ data.type }}
|
||||
</span>
|
||||
</template>
|
||||
</TableGeneric>
|
||||
</UiCard>
|
||||
</div>
|
||||
</ClientLayout>
|
||||
</template>
|
||||
Reference in New Issue
Block a user