Gate order actions by status, add final-approve after checks, and select customers in new orders.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-11 18:11:43 +02:00
co-authored by Cursor
parent 3848617108
commit 5d70002345
20 changed files with 305 additions and 53 deletions
@@ -4,8 +4,9 @@ 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 { RAW_ORDER_STATUS_LABELS, rawStatusLabel } from '@/utils/orderStatus'
import type { Order, RawOrderStatus } from '@/types'
import { CUSTOMER_TYPE_LABELS } from '@/utils/adminLabels'
import { ORDER_STATUS_META, RAW_ORDER_STATUS_LABELS, canPriceOrder, rawStatusLabel } from '@/utils/orderStatus'
import type { CustomerType, Order, RawOrderStatus } from '@/types'
const props = withDefaults(
defineProps<{
@@ -61,6 +62,34 @@ const canSubmitStatus = computed(
const useTable = computed(() => props.layout === 'desktop')
const badgeStatusLabel = computed(
() => ORDER_STATUS_META[props.order.status]?.label ?? props.order.status,
)
/** Avoid duplicating the same Persian label under the badge. */
const distinctRawStatusLabel = computed(() => {
const raw = rawStatusLabel(props.order.rawStatus)
if (!raw || raw === badgeStatusLabel.value) return ''
return raw
})
const customerTypeLabel = computed(() => {
const type = props.order.customerType as CustomerType | undefined
if (!type) return '—'
return CUSTOMER_TYPE_LABELS[type] ?? props.order.customerType ?? '—'
})
const showPricingAction = computed(() => canPriceOrder(props.order))
const showChecksAction = computed(() => props.order.settlementMethod === 'check')
const showCashAction = computed(() => props.order.settlementMethod === 'cash')
/** Primary CTA follows the current workflow stage. */
const primaryAction = computed<'pricing' | 'checks' | 'cash' | null>(() => {
if (showPricingAction.value) return 'pricing'
if (showChecksAction.value) return 'checks'
if (showCashAction.value) return 'cash'
return null
})
watch([() => props.order.id, manualMode], () => {
nextStatus.value = ''
statusNote.value = ''
@@ -89,25 +118,35 @@ function submitStatus() {
<strong>{{ order.orderNumber }}</strong>
<StatusBadge :status="order.status" />
</div>
<p class="order-detail__raw-status">{{ rawStatusLabel(order.rawStatus) }}</p>
<p v-if="distinctRawStatusLabel" class="order-detail__raw-status">
{{ distinctRawStatusLabel }}
</p>
</div>
<div class="order-detail__actions no-print">
<button type="button" class="admin-btn admin-btn--primary admin-btn--sm" @click="emit('pricing')">
<button
v-if="showPricingAction"
type="button"
class="admin-btn admin-btn--sm"
:class="primaryAction === 'pricing' ? 'admin-btn--primary' : 'admin-btn--outline'"
@click="emit('pricing')"
>
قیمت‌گذاری سفارش
</button>
<button
v-if="order.settlementMethod === 'check'"
v-if="showChecksAction"
type="button"
class="admin-btn admin-btn--outline admin-btn--sm"
class="admin-btn admin-btn--sm"
:class="primaryAction === 'checks' ? 'admin-btn--primary' : 'admin-btn--outline'"
@click="emit('checks')"
>
مدیریت چک‌ها
</button>
<button
v-if="order.settlementMethod === 'cash'"
v-if="showCashAction"
type="button"
class="admin-btn admin-btn--outline admin-btn--sm"
class="admin-btn admin-btn--sm"
:class="primaryAction === 'cash' ? 'admin-btn--primary' : 'admin-btn--outline'"
@click="emit('cashReceipt')"
>
رسید پرداخت
@@ -127,7 +166,7 @@ function submitStatus() {
<div class="order-detail__info-row">
<AdminIcon name="phone" :size="16" />
<span class="order-detail__info-label">تلفن</span>
<span class="order-detail__info-value" dir="ltr">{{ order.customerPhone ?? '—' }}</span>
<span class="order-detail__info-value order-detail__info-value--phone" dir="ltr">{{ order.customerPhone ?? '—' }}</span>
</div>
<div class="order-detail__info-row">
<AdminIcon name="id-card" :size="16" />
@@ -137,7 +176,7 @@ function submitStatus() {
<div class="order-detail__info-row">
<AdminIcon name="user" :size="16" />
<span class="order-detail__info-label">نوع مشتری</span>
<span class="order-detail__info-value">{{ order.customerType ?? '—' }}</span>
<span class="order-detail__info-value">{{ customerTypeLabel }}</span>
</div>
</div>
</section>
@@ -288,13 +327,17 @@ function submitStatus() {
.order-detail__id {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-direction: column;
align-items: flex-start;
gap: 8px;
margin-bottom: 4px;
margin-bottom: 0;
font-size: 1rem;
}
.order-detail__id strong {
line-height: 1.3;
}
.order-detail__raw-status {
margin: 0;
font-size: 0.75rem;
@@ -359,6 +402,11 @@ function submitStatus() {
word-break: break-word;
}
.order-detail__info-value--phone {
text-align: right;
justify-self: stretch;
}
.order-detail__table {
overflow-x: auto;
}