7/7/1405
This commit is contained in:
@@ -3,9 +3,10 @@ import { computed, ref, watch } from 'vue'
|
||||
import AdminIcon from '@/components/icons/AdminIcon.vue'
|
||||
import AdminSelect from '@/components/ui/AdminSelect.vue'
|
||||
import StatusBadge from '@/components/ui/StatusBadge.vue'
|
||||
import { formatCurrency, formatMeterage, formatNumber } from '@/utils/format'
|
||||
import { CUSTOMER_TYPE_LABELS } from '@/utils/adminLabels'
|
||||
import { ORDER_STATUS_META, RAW_ORDER_STATUS_LABELS, canFinalApproveOrder, canPriceOrder, rawStatusLabel } from '@/utils/orderStatus'
|
||||
import { formatCurrency, formatDateTime, formatMeterage, formatNumber } from '@/utils/format'
|
||||
import { CASH_PAYMENT_STATUS_LABELS, CUSTOMER_TYPE_LABELS } from '@/utils/adminLabels'
|
||||
import AdminImageLightbox from '@/components/ui/AdminImageLightbox.vue'
|
||||
import { ORDER_STATUS_META, canFinalApproveOrder, canPriceOrder, rawStatusLabel } from '@/utils/orderStatus'
|
||||
import type { CustomerType, Order, RawOrderStatus } from '@/types'
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -28,25 +29,19 @@ const emit = defineEmits<{
|
||||
orderId: string
|
||||
status: RawOrderStatus
|
||||
note?: string
|
||||
reason?: string
|
||||
force?: boolean
|
||||
},
|
||||
]
|
||||
}>()
|
||||
|
||||
const manualMode = ref(false)
|
||||
const nextStatus = ref<RawOrderStatus | ''>('')
|
||||
const statusNote = ref('')
|
||||
const receiptPreviewOpen = ref(false)
|
||||
|
||||
const allStatuses = Object.keys(RAW_ORDER_STATUS_LABELS) as RawOrderStatus[]
|
||||
const cashReceipt = computed(() => props.order.cashReceipt ?? null)
|
||||
|
||||
const transitions = computed(() => props.order.allowedTransitions ?? [])
|
||||
|
||||
const statusOptions = computed<RawOrderStatus[]>(() =>
|
||||
manualMode.value
|
||||
? allStatuses.filter((s) => s !== props.order.rawStatus)
|
||||
: [...transitions.value],
|
||||
)
|
||||
const statusOptions = computed<RawOrderStatus[]>(() => [...transitions.value])
|
||||
|
||||
const statusSelectOptions = computed(() => [
|
||||
{ value: '', label: 'انتخاب کنید…' },
|
||||
@@ -56,10 +51,7 @@ const statusSelectOptions = computed(() => [
|
||||
})),
|
||||
])
|
||||
|
||||
const noteRequired = computed(() => manualMode.value)
|
||||
const canSubmitStatus = computed(
|
||||
() => !!nextStatus.value && (!noteRequired.value || statusNote.value.trim().length > 0),
|
||||
)
|
||||
const canSubmitStatus = computed(() => !!nextStatus.value)
|
||||
|
||||
const useTable = computed(() => props.layout === 'desktop')
|
||||
|
||||
@@ -100,10 +92,13 @@ const primaryAction = computed<'pricing' | 'final' | 'checks' | 'cash' | null>((
|
||||
return null
|
||||
})
|
||||
|
||||
watch([() => props.order.id, manualMode], () => {
|
||||
nextStatus.value = ''
|
||||
statusNote.value = ''
|
||||
})
|
||||
watch(
|
||||
() => props.order.id,
|
||||
() => {
|
||||
nextStatus.value = ''
|
||||
statusNote.value = ''
|
||||
},
|
||||
)
|
||||
|
||||
function submitStatus() {
|
||||
if (!nextStatus.value || !canSubmitStatus.value) return
|
||||
@@ -112,12 +107,18 @@ function submitStatus() {
|
||||
orderId: props.order.id,
|
||||
status: nextStatus.value,
|
||||
note,
|
||||
reason: manualMode.value ? note : undefined,
|
||||
force: manualMode.value || undefined,
|
||||
})
|
||||
nextStatus.value = ''
|
||||
statusNote.value = ''
|
||||
}
|
||||
|
||||
function onCashReceiptAction() {
|
||||
if (cashReceipt.value?.receiptImage) {
|
||||
receiptPreviewOpen.value = true
|
||||
return
|
||||
}
|
||||
emit('cashReceipt')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -157,9 +158,9 @@ function submitStatus() {
|
||||
type="button"
|
||||
class="admin-btn admin-btn--sm"
|
||||
:class="primaryAction === 'cash' ? 'admin-btn--primary' : 'admin-btn--outline'"
|
||||
@click="emit('cashReceipt')"
|
||||
@click="onCashReceiptAction"
|
||||
>
|
||||
رسید پرداخت
|
||||
{{ cashReceipt?.receiptImage ? 'مشاهده رسید' : 'رسید پرداخت' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="showFinalApprove"
|
||||
@@ -275,20 +276,75 @@ function submitStatus() {
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="order-detail__section order-detail__status no-print">
|
||||
<div class="order-detail__status-head">
|
||||
<h3 class="order-detail__section-title">تغییر وضعیت</h3>
|
||||
<label class="order-detail__manual">
|
||||
<input v-model="manualMode" type="checkbox" />
|
||||
<span>تغییر دستی</span>
|
||||
</label>
|
||||
<section v-if="cashReceipt" class="order-detail__section">
|
||||
<h3 class="order-detail__section-title">رسید پرداخت نقدی</h3>
|
||||
<div class="order-detail__info">
|
||||
<div class="order-detail__info-row">
|
||||
<span class="order-detail__info-label">وضعیت</span>
|
||||
<span class="order-detail__info-value">
|
||||
{{ CASH_PAYMENT_STATUS_LABELS[cashReceipt.status] }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="order-detail__info-row">
|
||||
<span class="order-detail__info-label">مبلغ واریزی</span>
|
||||
<span class="order-detail__info-value">
|
||||
{{
|
||||
cashReceipt.paidAmount != null
|
||||
? formatCurrency(cashReceipt.paidAmount)
|
||||
: formatCurrency(cashReceipt.amount)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="cashReceipt.transferDate" class="order-detail__info-row">
|
||||
<span class="order-detail__info-label">تاریخ واریز</span>
|
||||
<span class="order-detail__info-value">
|
||||
{{ formatDateTime(cashReceipt.transferDate) }}
|
||||
<template v-if="cashReceipt.transferTime"> · {{ cashReceipt.transferTime }}</template>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="cashReceipt.trackingNumber || cashReceipt.trackingCode" class="order-detail__info-row">
|
||||
<span class="order-detail__info-label">پیگیری</span>
|
||||
<span class="order-detail__info-value" dir="ltr">
|
||||
{{ cashReceipt.trackingNumber || cashReceipt.trackingCode }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="cashReceipt.notes" class="order-detail__info-row">
|
||||
<span class="order-detail__info-label">یادداشت</span>
|
||||
<span class="order-detail__info-value">{{ cashReceipt.notes }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="manualMode" class="order-detail__status-hint">
|
||||
این گذر خارج از روال استاندارد است؛ ثبت یادداشت اجباری است.
|
||||
</p>
|
||||
<p v-else-if="!statusOptions.length" class="order-detail__status-hint">
|
||||
در این وضعیت گذر خودکاری وجود ندارد. برای تغییر، حالت دستی را فعال کنید.
|
||||
<div v-if="cashReceipt.receiptImage" class="order-detail__receipt">
|
||||
<button
|
||||
type="button"
|
||||
class="order-detail__receipt-thumb"
|
||||
@click="receiptPreviewOpen = true"
|
||||
>
|
||||
<img :src="cashReceipt.receiptImage" alt="تصویر رسید پرداخت" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="admin-btn admin-btn--outline admin-btn--sm"
|
||||
@click="receiptPreviewOpen = true"
|
||||
>
|
||||
مشاهده تصویر رسید
|
||||
</button>
|
||||
</div>
|
||||
<p v-else class="order-detail__status-hint">تصویر رسید هنوز آپلود نشده است.</p>
|
||||
</section>
|
||||
|
||||
<AdminImageLightbox
|
||||
v-if="cashReceipt?.receiptImage"
|
||||
v-model="receiptPreviewOpen"
|
||||
:src="cashReceipt.receiptImage"
|
||||
alt="تصویر رسید پرداخت"
|
||||
/>
|
||||
|
||||
<section class="order-detail__section order-detail__status no-print">
|
||||
<h3 class="order-detail__section-title">تغییر وضعیت</h3>
|
||||
|
||||
<p v-if="!statusOptions.length" class="order-detail__status-hint">
|
||||
در این مرحله گذر مجازی از این بخش نیست؛ از اقدامهای مرحلهای بالا (قیمتگذاری، چک، رسید نقدی و …) استفاده کنید.
|
||||
</p>
|
||||
|
||||
<div v-if="statusOptions.length" class="order-detail__status-form">
|
||||
@@ -304,9 +360,7 @@ function submitStatus() {
|
||||
</div>
|
||||
|
||||
<div class="admin-form__field">
|
||||
<label for="status-note">
|
||||
یادداشت{{ noteRequired ? ' (اجباری)' : ' (اختیاری)' }}
|
||||
</label>
|
||||
<label for="status-note">یادداشت (اختیاری)</label>
|
||||
<input
|
||||
id="status-note"
|
||||
v-model="statusNote"
|
||||
@@ -477,31 +531,33 @@ function submitStatus() {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.order-detail__status-head {
|
||||
.order-detail__receipt {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.order-detail__status-head .order-detail__section-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.order-detail__manual {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text-muted);
|
||||
.order-detail__receipt-thumb {
|
||||
padding: 0;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-bg);
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.order-detail__manual input {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
accent-color: var(--color-primary);
|
||||
.order-detail__receipt-thumb img {
|
||||
display: block;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.order-detail__status .order-detail__section-title {
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
.order-detail__status-hint {
|
||||
|
||||
Reference in New Issue
Block a user