Files
boursecu_admin/src/pages/menuPages/customers/base/components/WalletChargeForm.vue
T

220 lines
6.3 KiB
Vue
Raw Normal View History

2026-06-15 15:48:10 +03:30
<template>
<a-form
2026-06-15 22:39:22 +03:30
:model="modelValue"
2026-06-15 15:48:10 +03:30
ref="formRef"
autocomplete="off"
class="wallet-charge-form"
:class="formClass"
>
<a-form-item label="نوع عملیات" name="direction">
<a-radio-group
2026-06-15 22:39:22 +03:30
v-model:value="modelValue.direction"
2026-06-15 15:48:10 +03:30
button-style="solid"
class="wallet-charge-form__direction w-full"
>
<a-radio-button value="charge" class="wallet-charge-form__radio wallet-charge-form__radio--charge">
<span class="wallet-charge-form__radio-icon">+</span>
شارژ
</a-radio-button>
<a-radio-button value="discharge" class="wallet-charge-form__radio wallet-charge-form__radio--discharge">
<span class="wallet-charge-form__radio-icon">−</span>
دشارژ
</a-radio-button>
</a-radio-group>
</a-form-item>
<div class="wallet-charge-form__preview" :class="previewClass">
<span class="wallet-charge-form__preview-sign">{{ previewSign }}</span>
<span class="wallet-charge-form__preview-text">{{ previewText }}</span>
</div>
<a-form-item name="talabBedehi">
2026-06-15 22:39:22 +03:30
<a-checkbox v-model:checked="modelValue.talabBedehi">طلب/بدهی</a-checkbox>
2026-06-15 15:48:10 +03:30
</a-form-item>
<a-form-item :label="amountLabel" name="amountAbs" :rules="amountRules">
<BasicInput
2026-06-15 22:39:22 +03:30
v-model:value="modelValue.amountAbs"
2026-07-11 11:42:12 +03:30
:addon-before="resolvedUnit"
:type="resolvedInputType"
2026-06-15 15:48:10 +03:30
:place-holder="amountPlaceholder"
/>
2026-07-11 11:42:12 +03:30
<div v-if="isMoney && Number(modelValue.amountAbs) > 10" class="wallet-charge-form__hint">
2026-06-15 22:39:22 +03:30
معادل {{ usePrice(Number(modelValue.amountAbs) / 10, true, 'تومان') }}
2026-06-15 15:48:10 +03:30
</div>
</a-form-item>
<a-form-item :label="noteLabel" name="note" :rules="inputRules()">
2026-06-15 22:39:22 +03:30
<BasicInput v-model:value="modelValue.note" :place-holder="notePlaceholder" />
2026-06-15 15:48:10 +03:30
</a-form-item>
</a-form>
</template>
<script setup lang="ts">
2026-06-23 22:31:21 +03:30
import { computed, ref } from 'vue'
2026-06-15 15:48:10 +03:30
import type { FormInstance } from 'ant-design-vue'
2026-06-23 22:31:21 +03:30
import type { Charge } from '@/model/wallet'
2026-06-15 15:48:10 +03:30
import { inputRules } from '@/utils/inputRules'
import { usePrice } from '@core/utils/usePrice'
2026-07-11 11:42:12 +03:30
const props = withDefaults(
defineProps<{
/** @deprecated از unitLabel و isMoney استفاده کنید */
variant?: 'money' | 'gold'
modelValue: Charge
/** واحد نمایش: ریال، گرم، عدد، ... */
unitLabel?: string
/** true = ورودی قیمتی (ریال)، false = عددی */
isMoney?: boolean
/** نام کیف پول برای پیش‌نمایش */
walletLabel?: string
}>(),
{
variant: 'money',
},
)
2026-06-15 15:48:10 +03:30
const formRef = ref<FormInstance>()
2026-07-11 11:42:12 +03:30
const resolvedUnit = computed(
() => props.unitLabel ?? (props.variant === 'money' ? 'ریال' : 'گرم'),
)
const isMoney = computed(() => props.isMoney ?? props.variant === 'money')
const resolvedInputType = computed(() => (isMoney.value ? 'price' : 'number'))
2026-06-15 22:39:22 +03:30
const isDischarge = computed(() => props.modelValue.direction === 'discharge')
2026-06-15 15:48:10 +03:30
const formClass = computed(() =>
2026-07-11 11:42:12 +03:30
isDischarge.value ? 'wallet-charge-form--discharge' : 'wallet-charge-form--charge',
2026-06-15 15:48:10 +03:30
)
const previewClass = computed(() =>
isDischarge.value
? 'wallet-charge-form__preview--discharge'
2026-07-11 11:42:12 +03:30
: 'wallet-charge-form__preview--charge',
2026-06-15 15:48:10 +03:30
)
const previewSign = computed(() => (isDischarge.value ? '−' : '+'))
const previewText = computed(() => {
const action = isDischarge.value ? 'کسر از' : 'افزایش'
2026-07-11 11:42:12 +03:30
const wallet = props.walletLabel ?? (isMoney.value ? 'موجودی ریالی' : 'موجودی محصول')
2026-06-23 22:31:21 +03:30
return `${action} ${wallet} کاربر`
2026-06-15 15:48:10 +03:30
})
const amountLabel = computed(() =>
2026-07-11 11:42:12 +03:30
isDischarge.value ? `مقدار دشارژ (${resolvedUnit.value})` : `مقدار شارژ (${resolvedUnit.value})`,
2026-06-15 15:48:10 +03:30
)
const noteLabel = computed(() => (isDischarge.value ? 'علت دشارژ' : 'علت شارژ'))
const amountPlaceholder = computed(() =>
2026-07-11 11:42:12 +03:30
isMoney.value ? 'مثلاً ۱۰۰٬۰۰۰' : 'مثلاً ۰.۵',
2026-06-15 15:48:10 +03:30
)
const notePlaceholder = computed(() =>
2026-07-11 11:42:12 +03:30
isDischarge.value ? 'دلیل کسر موجودی' : 'دلیل افزایش موجودی',
2026-06-15 15:48:10 +03:30
)
const amountRules = [
...inputRules('مقدار'),
{
validator: (_rule: unknown, value: string | number | undefined) => {
const num = Math.abs(Number(value) || 0)
if (!num) {
return Promise.reject('مقدار باید بیشتر از صفر باشد')
}
return Promise.resolve()
2026-07-11 11:42:12 +03:30
},
},
2026-06-15 15:48:10 +03:30
]
defineExpose({
2026-07-11 11:42:12 +03:30
validateFields: () => formRef.value?.validateFields(),
2026-06-15 15:48:10 +03:30
})
</script>
<style scoped>
2026-07-11 17:59:30 +03:30
.wallet-charge-form :deep(.ant-form-item) {
margin-bottom: 0.65rem;
}
2026-06-15 15:48:10 +03:30
.wallet-charge-form__direction :deep(.ant-radio-button-wrapper) {
width: 50%;
text-align: center;
2026-07-11 17:59:30 +03:30
height: 2.35rem;
line-height: 2.25rem;
2026-06-15 15:48:10 +03:30
font-weight: 700;
}
.wallet-charge-form__radio-icon {
display: inline-block;
margin-left: 0.35rem;
font-size: 1.1rem;
font-weight: 800;
}
.wallet-charge-form__preview {
display: flex;
align-items: center;
2026-07-11 17:59:30 +03:30
gap: 0.5rem;
margin-bottom: 0.5rem;
padding: 0.55rem 0.75rem;
border-radius: 0.6rem;
2026-06-15 15:48:10 +03:30
border: 1px solid transparent;
2026-07-11 17:59:30 +03:30
font-size: 0.8125rem;
2026-06-15 15:48:10 +03:30
font-weight: 600;
}
.wallet-charge-form__preview-sign {
display: inline-flex;
align-items: center;
justify-content: center;
2026-07-11 17:59:30 +03:30
width: 1.45rem;
height: 1.45rem;
2026-06-15 15:48:10 +03:30
border-radius: 9999px;
2026-07-11 17:59:30 +03:30
font-size: 1rem;
2026-06-15 15:48:10 +03:30
font-weight: 800;
flex-shrink: 0;
}
.wallet-charge-form__preview--charge {
background: rgba(34, 197, 94, 0.12);
border-color: rgba(34, 197, 94, 0.35);
color: #86efac;
}
.wallet-charge-form__preview--charge .wallet-charge-form__preview-sign {
background: rgba(34, 197, 94, 0.2);
color: #4ade80;
}
.wallet-charge-form__preview--discharge {
background: rgba(239, 68, 68, 0.12);
border-color: rgba(239, 68, 68, 0.35);
color: #fca5a5;
}
.wallet-charge-form__preview--discharge .wallet-charge-form__preview-sign {
background: rgba(239, 68, 68, 0.2);
color: #f87171;
}
.wallet-charge-form__hint {
margin-top: 0.35rem;
font-size: 0.75rem;
opacity: 0.75;
}
.wallet-charge-form__direction :deep(.ant-radio-button-wrapper-checked.wallet-charge-form__radio--charge) {
background: #15803d !important;
border-color: #15803d !important;
color: #fff !important;
}
.wallet-charge-form__direction :deep(.ant-radio-button-wrapper-checked.wallet-charge-form__radio--discharge) {
background: #b91c1c !important;
border-color: #b91c1c !important;
color: #fff !important;
}
</style>