added some text handling 3
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<BasicModal
|
||||
v-model:visible="visibleProxy"
|
||||
title="ویرایش مقدار برداشت"
|
||||
width="28rem"
|
||||
wrap-class-name="physical-withdraw-adjust-modal"
|
||||
:loading="loading"
|
||||
:confirm-loading="saving"
|
||||
@ok="submit"
|
||||
@close="close"
|
||||
>
|
||||
<div v-if="loading" class="py-10 text-center text-sm text-gray-500">در حال بارگذاری...</div>
|
||||
|
||||
<div v-else-if="info && formLines.length" class="space-y-4">
|
||||
<div class="rounded-lg bg-gray-50 p-3 text-sm leading-6">
|
||||
<div>سند: <span class="font-semibold">#{{ info.withdraw_id }}</span></div>
|
||||
<div>مشتری: <span class="font-semibold">{{ info.customer_name || '-' }}</span></div>
|
||||
<div v-if="info.customer_mobile">موبایل: {{ info.customer_mobile }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="line in formLines"
|
||||
:key="line.transaction_id"
|
||||
class="rounded-lg border border-gray-200 p-3"
|
||||
>
|
||||
<div class="mb-2 text-sm font-semibold">{{ line.title }}</div>
|
||||
<div class="mb-3 grid grid-cols-2 gap-2 text-xs text-gray-600">
|
||||
<div>مقدار فعلی: <span class="font-medium text-gray-900">{{ formatQty(line.current_value, line) }}</span></div>
|
||||
<div>قابل افزودن: <span class="font-medium text-gray-900">{{ formatQty(line.available_add, line) }}</span></div>
|
||||
<div>حداکثر مجاز: <span class="font-medium text-gray-900">{{ formatQty(line.max_value, line) }}</span></div>
|
||||
<div>حداقل مجاز: <span class="font-medium text-gray-900">{{ formatQty(line.min_value, line) }}</span></div>
|
||||
</div>
|
||||
|
||||
<a-form-item
|
||||
class="!mb-0"
|
||||
:validate-status="lineError(line.transaction_id) ? 'error' : ''"
|
||||
:help="lineError(line.transaction_id)"
|
||||
>
|
||||
<template #label>
|
||||
<AdminLabelWithHelp label="مقدار جدید" :help="physicalWithdrawAdjustValueHelp" />
|
||||
</template>
|
||||
<BasicInput
|
||||
v-model:value="line.valueInput"
|
||||
type="number"
|
||||
:step="line.allows_decimal ? '0.001' : '1'"
|
||||
:place-holder="line.allows_decimal ? 'مثلاً 1.250' : 'مثلاً 2'"
|
||||
@change="() => clearLineError(line.transaction_id)"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="info && !formLines.length" class="py-8 text-center text-sm text-gray-500">
|
||||
خطی برای ویرایش یافت نشد.
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { message } from 'ant-design-vue'
|
||||
import AdminLabelWithHelp from '@/components/AdminLabelWithHelp.vue'
|
||||
import {
|
||||
adjustPhysicalWithdraw,
|
||||
getPhysicalWithdrawAdjustInfo,
|
||||
type PhysicalWithdrawAdjustInfo,
|
||||
type PhysicalWithdrawAdjustLine
|
||||
} from '@/api/physicalWithdraw'
|
||||
import { physicalWithdrawAdjustValueHelp } from '@/utils/adminHelpCopy'
|
||||
|
||||
type FormLine = PhysicalWithdrawAdjustLine & { valueInput: string }
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
withdrawId?: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:visible': [value: boolean]
|
||||
success: []
|
||||
}>()
|
||||
|
||||
const visibleProxy = computed({
|
||||
get: () => props.visible,
|
||||
set: (value: boolean) => emit('update:visible', value),
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const info = ref<PhysicalWithdrawAdjustInfo | null>(null)
|
||||
const formLines = ref<FormLine[]>([])
|
||||
const lineErrors = ref<Record<number, string>>({})
|
||||
|
||||
watch(
|
||||
() => [props.visible, props.withdrawId] as const,
|
||||
([open, withdrawId]) => {
|
||||
if (open && withdrawId) {
|
||||
void loadInfo(withdrawId)
|
||||
}
|
||||
if (!open) {
|
||||
resetState()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
function resetState() {
|
||||
info.value = null
|
||||
formLines.value = []
|
||||
lineErrors.value = {}
|
||||
}
|
||||
|
||||
function formatQty(value: number, line: Pick<PhysicalWithdrawAdjustLine, 'unit' | 'allows_decimal'>) {
|
||||
const decimals = line.allows_decimal ? 3 : 0
|
||||
const formatted = Number(value).toLocaleString('fa-IR', {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: decimals
|
||||
})
|
||||
return `${formatted} ${line.unit}`
|
||||
}
|
||||
|
||||
function lineError(transactionId: number) {
|
||||
return lineErrors.value[transactionId] ?? ''
|
||||
}
|
||||
|
||||
function clearLineError(transactionId: number) {
|
||||
if (lineErrors.value[transactionId]) {
|
||||
const next = { ...lineErrors.value }
|
||||
delete next[transactionId]
|
||||
lineErrors.value = next
|
||||
}
|
||||
}
|
||||
|
||||
function parseValue(raw: string, line: PhysicalWithdrawAdjustLine): number | null {
|
||||
const normalized = String(raw ?? '').trim().replace(',', '.')
|
||||
if (!normalized) return null
|
||||
const value = Number(normalized)
|
||||
if (!Number.isFinite(value)) return null
|
||||
if (!line.allows_decimal && Math.abs(value - Math.round(value)) > 0.000001) {
|
||||
return null
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
function validateLine(line: FormLine): string | null {
|
||||
const value = parseValue(line.valueInput, line)
|
||||
if (value == null) {
|
||||
return line.allows_decimal ? 'مقدار معتبر وارد کنید' : 'مقدار باید عدد صحیح باشد'
|
||||
}
|
||||
if (value < line.min_value - 0.000001) {
|
||||
return `حداقل مقدار ${formatQty(line.min_value, line)} است`
|
||||
}
|
||||
if (value > line.max_value + 0.000001) {
|
||||
return `حداکثر مقدار ${formatQty(line.max_value, line)} است`
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async function loadInfo(withdrawId: number) {
|
||||
loading.value = true
|
||||
lineErrors.value = {}
|
||||
try {
|
||||
const data = await getPhysicalWithdrawAdjustInfo(withdrawId)
|
||||
info.value = data
|
||||
formLines.value = (data.lines ?? []).map((line) => ({
|
||||
...line,
|
||||
valueInput: String(line.current_value ?? '')
|
||||
}))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
visibleProxy.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
visibleProxy.value = false
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (!props.withdrawId || !formLines.value.length) return
|
||||
|
||||
const errors: Record<number, string> = {}
|
||||
const items: Array<{ transaction_id: number; value: number }> = []
|
||||
|
||||
for (const line of formLines.value) {
|
||||
const error = validateLine(line)
|
||||
if (error) {
|
||||
errors[line.transaction_id] = error
|
||||
continue
|
||||
}
|
||||
const value = parseValue(line.valueInput, line)
|
||||
if (value == null) {
|
||||
errors[line.transaction_id] = 'مقدار معتبر وارد کنید'
|
||||
continue
|
||||
}
|
||||
if (Math.abs(value - line.current_value) < 0.000001) {
|
||||
continue
|
||||
}
|
||||
items.push({
|
||||
transaction_id: line.transaction_id,
|
||||
value
|
||||
})
|
||||
}
|
||||
|
||||
lineErrors.value = errors
|
||||
if (Object.keys(errors).length) {
|
||||
message.error('لطفاً مقادیر را اصلاح کنید')
|
||||
return
|
||||
}
|
||||
if (!items.length) {
|
||||
message.info('تغییری اعمال نشده است')
|
||||
return
|
||||
}
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
await adjustPhysicalWithdraw(props.withdrawId, { items })
|
||||
message.success('مقادیر با موفقیت بهروزرسانی شد')
|
||||
visibleProxy.value = false
|
||||
emit('success')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.physical-withdraw-adjust-modal {
|
||||
z-index: 1100 !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user