282 lines
7.9 KiB
Vue
282 lines
7.9 KiB
Vue
<template>
|
|||
|
|
<BasicActionSheet
|
||
|
|
v-model:visible="visibleProxy"
|
||
|
|
:title="modalTitle"
|
||
|
|
modal-width="22rem"
|
||
|
|
drawer-height="auto"
|
||
|
|
compact
|
||
|
|
:loading="loading"
|
||
|
|
:show-button="false"
|
||
|
|
@close="handleClose"
|
||
|
|
>
|
||
|
|
<div class="dashboard-wallet-modal">
|
||
|
|
<div class="dashboard-wallet-modal__section">
|
||
|
|
<label class="dashboard-wallet-modal__label">مشتری</label>
|
||
|
|
<a-select
|
||
|
|
v-model:value="customerId"
|
||
|
|
show-search
|
||
|
|
allow-clear
|
||
|
|
placeholder="انتخاب کنید"
|
||
|
|
class="dashboard-wallet-modal__select w-full"
|
||
|
|
size="large"
|
||
|
|
:options="customerOptions"
|
||
|
|
:filter-option="filterCustomer"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div
|
||
|
|
v-if="selectedCustomer"
|
||
|
|
class="dashboard-wallet-modal__balances"
|
||
|
|
>
|
||
|
|
<div>
|
||
|
|
<span class="text-slate-500">طلایی</span>
|
||
|
|
<p class="font-semibold text-slate-800 dark:text-slate-100">{{ formatGold(selectedCustomer) }}</p>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<span class="text-slate-500">ریالی</span>
|
||
|
|
<p class="font-semibold text-slate-800 dark:text-slate-100">{{ formatCash(selectedCustomer) }}</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="dashboard-wallet-modal__section">
|
||
|
|
<label class="dashboard-wallet-modal__label">نوع کیف پول</label>
|
||
|
|
<a-radio-group v-model:value="walletVariant" button-style="solid" class="flex w-full">
|
||
|
|
<a-radio-button value="money" class="w-1/2 text-center">ریالی</a-radio-button>
|
||
|
|
<a-radio-button value="gold" class="w-1/2 text-center">طلایی</a-radio-button>
|
||
|
|
</a-radio-group>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<WalletChargeForm
|
||
|
|
ref="chargeFormRef"
|
||
|
|
class="dashboard-wallet-modal__form"
|
||
|
|
:model-value="formCharge"
|
||
|
|
:variant="walletVariant"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<div class="dashboard-wallet-modal__footer">
|
||
|
|
<a-button danger size="large" block @click="closeModal">
|
||
|
|
بستن
|
||
|
|
</a-button>
|
||
|
|
<a-button
|
||
|
|
type="primary"
|
||
|
|
:danger="formCharge.direction === 'discharge'"
|
||
|
|
size="large"
|
||
|
|
block
|
||
|
|
:loading="submitting"
|
||
|
|
@click="submit"
|
||
|
|
>
|
||
|
|
{{ okText }}
|
||
|
|
</a-button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</BasicActionSheet>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { computed, ref, watch } from 'vue'
|
||
|
|
import { message } from 'ant-design-vue'
|
||
|
|
import BasicActionSheet from '@/components/BasicActionSheet.vue'
|
||
|
|
import WalletChargeForm from '@/pages/menuPages/customers/base/components/WalletChargeForm.vue'
|
||
|
|
import {
|
||
|
|
buildChargePayload,
|
||
|
|
createEmptyChargeForm,
|
||
|
|
walletChargeOkText,
|
||
|
|
walletChargeSuccessMessage,
|
||
|
|
walletChargeTitle,
|
||
|
|
} from '@/pages/menuPages/customers/base/utils/walletChargeForm'
|
||
|
|
import { getCustomersList } from '@/api/customer'
|
||
|
|
import { chargeWallet } from '@/api/wallet'
|
||
|
|
import type { Customer } from '@/model/customer'
|
||
|
|
import type { Charge, Wallet } from '@/model/wallet'
|
||
|
|
import { usePrice } from '@core/utils/usePrice'
|
||
|
|
|
||
|
|
const props = defineProps<{ visible: boolean }>()
|
||
|
|
const emit = defineEmits<{ (e: 'update:visible', value: boolean): void }>()
|
||
|
|
|
||
|
|
const visibleProxy = computed({
|
||
|
|
get: () => props.visible,
|
||
|
|
set: (value: boolean) => emit('update:visible', value),
|
||
|
|
})
|
||
|
|
|
||
|
|
const loading = ref(false)
|
||
|
|
const submitting = ref(false)
|
||
|
|
const customers = ref<Customer[]>([])
|
||
|
|
const walletVariant = ref<'money' | 'gold'>('money')
|
||
|
|
const formCharge = ref<Charge>(createEmptyChargeForm())
|
||
|
|
const chargeFormRef = ref<InstanceType<typeof WalletChargeForm>>()
|
||
|
|
|
||
|
|
const customerId = computed({
|
||
|
|
get: () => formCharge.value.customer_id ?? undefined,
|
||
|
|
set: (value: number | undefined) => {
|
||
|
|
formCharge.value.customer_id = value
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
const customerOptions = computed(() =>
|
||
|
|
customers.value.map((customer) => ({
|
||
|
|
value: customer.id,
|
||
|
|
label: `${customer.name ?? ''} — ${customer.mobile ?? ''}`.trim(),
|
||
|
|
})),
|
||
|
|
)
|
||
|
|
|
||
|
|
const selectedCustomer = computed(() =>
|
||
|
|
customers.value.find((customer) => customer.id === formCharge.value.customer_id),
|
||
|
|
)
|
||
|
|
|
||
|
|
const modalTitle = computed(() =>
|
||
|
|
walletChargeTitle(walletVariant.value, formCharge.value.direction),
|
||
|
|
)
|
||
|
|
|
||
|
|
const okText = computed(() => walletChargeOkText(formCharge.value.direction))
|
||
|
|
|
||
|
|
function filterCustomer(input: string, option?: { label?: string }) {
|
||
|
|
return String(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
||
|
|
}
|
||
|
|
|
||
|
|
function customerWallet(customer: Customer): Wallet | undefined {
|
||
|
|
const wallet = customer.wallet as Wallet | Wallet[] | undefined
|
||
|
|
return Array.isArray(wallet) ? wallet[0] : wallet
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatGold(customer: Customer) {
|
||
|
|
const gold = customerWallet(customer)?.gold ?? customer.wallet_gold ?? customer.gold
|
||
|
|
return `${Number(gold ?? 0).toLocaleString('fa-IR', { maximumFractionDigits: 3 })} گرم`
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatCash(customer: Customer) {
|
||
|
|
const cash = customerWallet(customer)?.cash ?? customer.wallet_cash
|
||
|
|
return usePrice(Number(cash ?? 0), true, '')
|
||
|
|
}
|
||
|
|
|
||
|
|
async function loadCustomers() {
|
||
|
|
loading.value = true
|
||
|
|
try {
|
||
|
|
customers.value = (await getCustomersList()) ?? []
|
||
|
|
} catch (e) {
|
||
|
|
console.error(e)
|
||
|
|
message.error('خطا در بارگذاری لیست مشتریان')
|
||
|
|
} finally {
|
||
|
|
loading.value = false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function resetForm() {
|
||
|
|
walletVariant.value = 'money'
|
||
|
|
formCharge.value = createEmptyChargeForm()
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleClose() {
|
||
|
|
resetForm()
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeModal() {
|
||
|
|
visibleProxy.value = false
|
||
|
|
resetForm()
|
||
|
|
}
|
||
|
|
|
||
|
|
async function submit() {
|
||
|
|
if (!formCharge.value.customer_id) {
|
||
|
|
message.warning('مشتری را انتخاب کنید')
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
await chargeFormRef.value?.validateFields?.()
|
||
|
|
} catch {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
submitting.value = true
|
||
|
|
try {
|
||
|
|
await chargeWallet(buildChargePayload(formCharge.value), walletVariant.value)
|
||
|
|
message.success(walletChargeSuccessMessage(formCharge.value.direction))
|
||
|
|
closeModal()
|
||
|
|
} catch (e) {
|
||
|
|
console.error(e)
|
||
|
|
message.error('خطا در ثبت عملیات')
|
||
|
|
} finally {
|
||
|
|
submitting.value = false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
watch(
|
||
|
|
() => props.visible,
|
||
|
|
(open) => {
|
||
|
|
if (open) {
|
||
|
|
void loadCustomers()
|
||
|
|
}
|
||
|
|
},
|
||
|
|
)
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.dashboard-wallet-modal {
|
||
|
|
@apply flex flex-col gap-4 px-4 pb-2 pt-1;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__select :deep(.ant-select-selector) {
|
||
|
|
@apply !px-3;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__select :deep(.ant-select-selection-placeholder) {
|
||
|
|
@apply text-slate-400;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__section {
|
||
|
|
@apply flex flex-col gap-1.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__label {
|
||
|
|
@apply text-xs font-semibold text-slate-600 dark:text-slate-300;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__balances {
|
||
|
|
@apply grid grid-cols-2 gap-3 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2.5 text-xs dark:border-slate-600 dark:bg-slate-800/60;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__footer {
|
||
|
|
@apply sticky bottom-0 grid grid-cols-2 gap-2 border-t border-slate-200 bg-white pt-3 dark:border-slate-600 dark:bg-slate-900;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.ant-form-item) {
|
||
|
|
margin-bottom: 0.85rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.ant-form-item-label > label) {
|
||
|
|
@apply text-xs font-semibold text-slate-600 dark:text-slate-300;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.wallet-charge-form__direction .ant-radio-button-wrapper) {
|
||
|
|
height: 2.5rem;
|
||
|
|
line-height: 2.4rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.wallet-charge-form__preview) {
|
||
|
|
margin-bottom: 0.75rem;
|
||
|
|
padding: 0.65rem 0.85rem;
|
||
|
|
font-size: 0.8125rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.wallet-charge-form__preview--charge) {
|
||
|
|
color: #166534;
|
||
|
|
background: #f0fdf4;
|
||
|
|
border-color: #bbf7d0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.wallet-charge-form__preview--charge .wallet-charge-form__preview-sign) {
|
||
|
|
color: #15803d;
|
||
|
|
background: #dcfce7;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.wallet-charge-form__preview--discharge) {
|
||
|
|
color: #991b1b;
|
||
|
|
background: #fef2f2;
|
||
|
|
border-color: #fecaca;
|
||
|
|
}
|
||
|
|
|
||
|
|
.dashboard-wallet-modal__form :deep(.wallet-charge-form__preview--discharge .wallet-charge-form__preview-sign) {
|
||
|
|
color: #b91c1c;
|
||
|
|
background: #fee2e2;
|
||
|
|
}
|
||
|
|
</style>
|