چک {{ check.row }} — {{ formatNumber(check.amount) }} تومان
+چک {{ check.row }} — {{ formatCurrency(check.amount) }}
diff --git a/src/assets/styles/responsive.css b/src/assets/styles/responsive.css index 4162232..e444aaa 100644 --- a/src/assets/styles/responsive.css +++ b/src/assets/styles/responsive.css @@ -122,12 +122,19 @@ .admin-card-item__header { display: flex; - align-items: flex-start; + align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; } +.admin-card-item__header-actions { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} + .admin-card-item__title { margin: 0; font-size: 0.875rem; diff --git a/src/components/ui/ActiveSwitchCell.vue b/src/components/ui/ActiveSwitchCell.vue index ed9152c..171cf5e 100644 --- a/src/components/ui/ActiveSwitchCell.vue +++ b/src/components/ui/ActiveSwitchCell.vue @@ -26,18 +26,21 @@ const { toggle, isLoading, hasError } = useAsyncToggle({ ? `${props.entityType ?? 'مورد'} «${props.entityName}» فعال شد.` : `${props.entityType ?? 'مورد'} «${props.entityName}» غیرفعال شد.`, }) + async function onChange(next: boolean) { if (next === props.modelValue) return - if (!next) { - const ok = await confirm({ - title: `غیرفعالسازی ${props.entityType ?? 'مورد'}`, - message: `آیا از غیرفعال کردن «${props.entityName}» مطمئن هستید؟`, - tone: 'danger', - confirmLabel: 'غیرفعال کردن', - }) - if (!ok) return - } + const entity = props.entityType ?? 'مورد' + const ok = await confirm({ + title: next ? `فعالسازی ${entity}` : `غیرفعالسازی ${entity}`, + message: next + ? `آیا از فعال کردن «${props.entityName}» مطمئن هستید؟` + : `آیا از غیرفعال کردن «${props.entityName}» مطمئن هستید؟`, + tone: next ? 'primary' : 'danger', + confirmLabel: next ? 'فعال کردن' : 'غیرفعال کردن', + cancelLabel: 'انصراف', + }) + if (!ok) return const result = await toggle(props.id, props.modelValue) emit('update:modelValue', result) diff --git a/src/components/ui/AdminCurrencyInput.vue b/src/components/ui/AdminCurrencyInput.vue new file mode 100644 index 0000000..940c27f --- /dev/null +++ b/src/components/ui/AdminCurrencyInput.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/components/ui/BaseSwitch.vue b/src/components/ui/BaseSwitch.vue index e35dbf1..a665aef 100644 --- a/src/components/ui/BaseSwitch.vue +++ b/src/components/ui/BaseSwitch.vue @@ -26,13 +26,22 @@ const inputId = computed(() => props.id ?? `switch-${crypto.randomUUID().slice(0 const stateText = computed(() => (props.modelValue ? props.activeText : props.inactiveText)) function onChange(event: Event) { + const input = event.target as HTMLInputElement + const next = input.checked + // Keep the visual state locked to modelValue until the parent accepts the change. + // Native click flips the DOM checkbox even when the parent cancels. + input.checked = props.modelValue if (props.disabled || props.loading) return - emit('update:modelValue', (event.target as HTMLInputElement).checked) + emit('update:modelValue', next) } - @@ -82,7 +90,6 @@ function onChange(event: Event) { .base-switch__control { display: inline-flex; align-items: center; - gap: 10px; } .base-switch__input { @@ -131,12 +138,6 @@ function onChange(event: Event) { transform: translateX(-20px); } -.base-switch__state { - font-size: 0.8125rem; - color: var(--color-text-muted); - min-width: 3.5rem; -} - .base-switch__spinner { width: 12px; height: 12px; diff --git a/src/data/mockData.ts b/src/data/mockData.ts index a86516f..2f7d3ec 100644 --- a/src/data/mockData.ts +++ b/src/data/mockData.ts @@ -82,7 +82,6 @@ export const orders: Order[] = [ requestedMeterage: 2000, confirmedMeterage: 2000, supplyPrice: null, - unitDiscount: 0, totalAmount: null, }, { @@ -93,7 +92,6 @@ export const orders: Order[] = [ requestedMeterage: 1500, confirmedMeterage: 1000, supplyPrice: null, - unitDiscount: 0, totalAmount: null, }, { @@ -104,7 +102,6 @@ export const orders: Order[] = [ requestedMeterage: 750, confirmedMeterage: 750, supplyPrice: null, - unitDiscount: 0, totalAmount: null, }, ], @@ -250,7 +247,7 @@ export const internalMessages: InternalMessage[] = [ id: 'msg-2', senderName: 'رضا کریمی', subject: 'درخواست اصلاح قیمت', - preview: 'مشتری درخواست تخفیف ۵٪ روی متراژ بالای ۳۰۰۰ متر داده است.', + preview: 'مشتری درخواست اصلاح متراژ سفارش را داده است.', sentAt: '2024-10-25T08:40:00', isRead: false, }, diff --git a/src/services/api.ts b/src/services/api.ts index 8d5ae52..30ee5cd 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -203,13 +203,11 @@ export type OrderItemPricingPayload = { confirmedMeterage?: number unitPrice?: number supplyPrice?: number - unitDiscount?: number } export type UpdateOrderPricingPayload = { items: OrderItemPricingPayload[] shippingCost?: number - totalDiscount?: number note?: string } @@ -218,7 +216,6 @@ export type ApiOrder = Order & { settlementType?: SettlementMethod totalMeterage?: number shippingCost?: number | null - totalDiscount?: number | null finalAmount?: number | null checkRassDays?: number | null checkRassDate?: string diff --git a/src/types/index.ts b/src/types/index.ts index 0a1a49f..c8fe3d0 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -40,7 +40,6 @@ export interface OrderItem { requestedMeterage: number confirmedMeterage: number | null supplyPrice: number | null - unitDiscount: number totalAmount: number | null } diff --git a/src/utils/format.ts b/src/utils/format.ts index 0670afc..6f6ab07 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -1,6 +1,19 @@ const persianDigits = '۰۱۲۳۴۵۶۷۸۹' const numberFormatter = new Intl.NumberFormat('fa-IR', { useGrouping: true }) +export function normalizeDigits(input: string): string { + return input.replace(/[۰-۹]/g, (digit) => String(persianDigits.indexOf(digit))) +} + +export function extractNumericString(input: string): string { + return normalizeDigits(input).replace(/[^\d]/g, '') +} + +export function parseFormattedNumber(value: string): number { + const numeric = extractNumericString(value) + return numeric ? Number(numeric) : 0 +} + export function formatNumber(value: number): string { if (!Number.isFinite(value)) return '—' return numberFormatter.format(value) diff --git a/src/views/cash-payments/CashPaymentsView.vue b/src/views/cash-payments/CashPaymentsView.vue index cd1cb68..dda9a34 100644 --- a/src/views/cash-payments/CashPaymentsView.vue +++ b/src/views/cash-payments/CashPaymentsView.vue @@ -168,6 +168,7 @@ async function rejectPayment(payment: CashPayment) {
چک {{ check.row }} — {{ formatNumber(check.amount) }} تومان
+چک {{ check.row }} — {{ formatCurrency(check.amount) }}
تخفیف کل
-- {{ formatCurrency(order?.totalDiscount ?? 0) }} -
-هزینه حمل
@@ -216,7 +227,6 @@ async function savePricing() {
+ مبلغ کل: {{ formatCurrency(item.totalAmount) }} +