Files
nademitex_user/src/views/cart/components/DesktopCartPage.vue
T

659 lines
16 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { useRouter } from 'vue-router'
import CheckoutStepper from '@/components/layout/CheckoutStepper.vue'
import IconCart from '@/components/icons/IconCart.vue'
import IconTrash from '@/components/icons/IconTrash.vue'
import IconBuilding from '@/components/icons/IconBuilding.vue'
import IconChevronLeft from '@/components/icons/IconChevronLeft.vue'
import IconOrders from '@/components/icons/IconOrders.vue'
import IconClipboardEmpty from '@/components/icons/IconClipboardEmpty.vue'
import IconLightbulb from '@/components/icons/IconLightbulb.vue'
import IconLayoutGrid from '@/components/icons/IconLayoutGrid.vue'
import IconDiamond from '@/components/icons/IconDiamond.vue'
import { formatMeterage, formatNumber } from '@/utils/format'
import type { CartItem } from '@/types'
defineProps<{
items: CartItem[]
companyName: string
companySummaries?: {
companyId: string
companyName: string
meterage: number
maxMeterage: number
remaining: number
}[]
totalMeterage: number
maxMeterage: number
remainingCapacity: number
isEmpty: boolean
submitting?: boolean
}>()
const emit = defineEmits<{
remove: [id: string]
checkout: []
selectCompany: []
back: []
}>()
const router = useRouter()
const quickLinks = [
{
title: 'انتخاب شرکت',
desc: 'شروع سفارش از انتخاب شرکت',
icon: IconBuilding,
tone: 'blue',
action: () => emit('selectCompany'),
},
{
title: 'سفارش‌گذاری',
desc: 'مشاهده کاتالوگ و افزودن کالا',
icon: IconCart,
tone: 'green',
action: () => emit('back'),
},
{
title: 'سفارش‌های من',
desc: 'پیگیری وضعیت سفارش‌ها',
icon: IconOrders,
tone: 'blue',
action: () => router.push('/orders'),
},
]
</script>
<template>
<div class="desktop-page cart-desktop-page">
<CheckoutStepper :current-step="1" />
<header class="cart-desktop-page__head">
<h1 class="cart-desktop-page__title">سبد خرید</h1>
<p class="cart-desktop-page__subtitle">
{{ companyName ? `شرکت‌ها: ${companyName}` : 'سبد خرید مشترک' }}
</p>
</header>
<div class="cart-desktop-page__layout">
<section class="cart-desktop-page__main">
<div v-if="isEmpty" class="cart-empty-card">
<div class="cart-empty-card__visual" aria-hidden="true">
<span class="cart-empty-card__spark cart-empty-card__spark--1">+</span>
<span class="cart-empty-card__spark cart-empty-card__spark--2">·</span>
<span class="cart-empty-card__circle">
<IconCart :size="40" />
</span>
<span class="cart-empty-card__spark cart-empty-card__spark--3">·</span>
</div>
<h2 class="cart-empty-card__heading">سبد خرید شما خالی است</h2>
<p class="cart-empty-card__text">
برای ثبت سفارش جدید، ابتدا شرکت موردنظر را انتخاب کنید و سپس کالیته و محصولات
را به سبد اضافه کنید.
</p>
<div class="cart-empty-card__actions">
<button type="button" class="cart-btn cart-btn--primary" @click="emit('selectCompany')">
<IconBuilding :size="18" />
انتخاب شرکت
</button>
<button type="button" class="cart-btn cart-btn--outline" @click="emit('back')">
<IconChevronLeft :size="16" />
بازگشت به سفارش‌گذاری
</button>
</div>
</div>
<div v-else class="cart-items-card">
<div class="cart-items-card__scroll">
<table class="cart-items-table">
<thead>
<tr>
<th scope="col">محصول</th>
<th scope="col">شرکت</th>
<th scope="col">کد</th>
<th scope="col">متراژ (متر)</th>
<th scope="col">حذف</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>
<strong class="cart-items-table__name">{{ item.productName }}</strong>
</td>
<td>{{ item.companyName || '—' }}</td>
<td>{{ item.productCode }}</td>
<td>{{ formatNumber(item.meterage) }}</td>
<td>
<button
type="button"
class="cart-items-table__delete"
aria-label="حذف"
@click="emit('remove', item.id)"
>
<IconTrash :size="18" />
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<aside class="cart-desktop-page__sidebar">
<div class="cart-summary-card">
<h2 class="cart-summary-card__title">
<span class="cart-summary-card__title-icon" aria-hidden="true">
<IconClipboardEmpty :size="22" />
</span>
خلاصه سفارش
</h2>
<div class="cart-summary-card__rows">
<div class="cart-summary-card__row">
<span class="cart-summary-card__row-label">
<IconLayoutGrid :size="16" />
تعداد آیتم‌ها
</span>
<strong>{{ formatNumber(items.length) }}</strong>
</div>
<div class="cart-summary-card__row">
<span class="cart-summary-card__row-label">
<IconDiamond :size="16" />
متراژ کل
</span>
<strong>{{ formatMeterage(totalMeterage) }}</strong>
</div>
<div
v-for="row in companySummaries ?? []"
:key="row.companyId"
class="cart-summary-card__row cart-summary-card__row--sub"
>
<span class="cart-summary-card__row-label">{{ row.companyName }}</span>
<strong>
{{ formatMeterage(row.meterage) }}
<span class="cart-summary-card__cap">/ {{ formatMeterage(row.maxMeterage) }}</span>
</strong>
</div>
<div class="cart-summary-card__row cart-summary-card__row--hint">
<span class="cart-summary-card__row-label">
<IconOrders :size="16" />
مبلغ فاکتور
</span>
<span class="cart-summary-card__hint-value">
پس از قیمت‌گذاری مدیریت
</span>
</div>
</div>
<button
type="button"
class="cart-summary-card__cta"
:disabled="isEmpty || submitting"
@click="emit('checkout')"
>
<IconChevronLeft :size="16" />
{{ submitting ? 'در حال ثبت…' : 'ثبت پیش‌سفارش' }}
</button>
<p class="cart-summary-card__note">
اقلام همه شرکت‌ها در یک سبد و یک فاکتور ثبت می‌شوند؛ پس از قیمت‌گذاری، یک‌بار تسویه می‌کنید.
</p>
</div>
<div class="cart-guide-card">
<h3 class="cart-guide-card__title">
<span class="cart-guide-card__title-icon" aria-hidden="true">
<IconLightbulb :size="18" />
</span>
راهنمای گام بعدی
</h3>
<p class="cart-guide-card__text">
پس از انتخاب شرکت و افزودن محصولات، متراژ کل و سقف مجاز فاکتور را بررسی کنید.
<template v-if="!isEmpty">
سقف مجاز: {{ formatMeterage(maxMeterage) }} — باقی‌مانده:
{{ formatMeterage(remainingCapacity) }}.
</template>
سپس برای تکمیل سفارش، گزینه «ادامه و انتخاب تسویه» را بزنید.
</p>
</div>
</aside>
</div>
<nav class="cart-quick-nav" aria-label="دسترسی سریع">
<button
v-for="link in quickLinks"
:key="link.title"
type="button"
class="cart-quick-nav__item"
@click="link.action()"
>
<span class="cart-quick-nav__icon" :class="`cart-quick-nav__icon--${link.tone}`">
<component :is="link.icon" :size="20" />
</span>
<span class="cart-quick-nav__body">
<strong class="cart-quick-nav__title">{{ link.title }}</strong>
<span class="cart-quick-nav__desc">{{ link.desc }}</span>
</span>
<IconChevronLeft :size="16" class="cart-quick-nav__chevron" aria-hidden="true" />
</button>
</nav>
<p class="cart-desktop-page__footer">پارس بافت — سامانه سفارش‌گذاری پارچه</p>
</div>
</template>
<style scoped>
.cart-desktop-page {
width: 100%;
padding-bottom: 24px;
}
.cart-desktop-page__head {
margin-bottom: 20px;
}
.cart-desktop-page__title {
margin: 0 0 6px;
font-size: 1.375rem;
font-weight: 700;
color: var(--color-text);
}
.cart-desktop-page__subtitle {
margin: 0;
font-size: 0.875rem;
color: var(--color-text-muted);
}
.cart-desktop-page__layout {
direction: ltr;
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 20px;
align-items: start;
margin-bottom: 24px;
}
@media (min-width: 1100px) {
.cart-desktop-page__layout {
grid-template-columns: minmax(0, 1fr) 300px;
}
}
.cart-desktop-page__main,
.cart-desktop-page__sidebar {
direction: rtl;
}
.cart-desktop-page__sidebar {
display: flex;
flex-direction: column;
gap: 16px;
}
.cart-empty-card,
.cart-items-card {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
}
.cart-empty-card {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 48px 32px 40px;
min-height: 360px;
}
.cart-empty-card__visual {
position: relative;
width: 140px;
height: 100px;
margin-bottom: 24px;
}
.cart-empty-card__circle {
position: absolute;
inset: 12px 24px;
border-radius: 50%;
background: var(--color-primary-soft);
color: var(--color-primary);
display: flex;
align-items: center;
justify-content: center;
}
.cart-empty-card__spark {
position: absolute;
color: #93c5fd;
font-size: 1.125rem;
font-weight: 700;
line-height: 1;
}
.cart-empty-card__spark--1 {
top: 8px;
right: 18px;
}
.cart-empty-card__spark--2 {
top: 28px;
left: 8px;
font-size: 1.5rem;
}
.cart-empty-card__spark--3 {
bottom: 16px;
right: 10px;
font-size: 1.25rem;
}
.cart-empty-card__heading {
margin: 0 0 10px;
font-size: 1.0625rem;
font-weight: 700;
color: var(--color-text);
}
.cart-empty-card__text {
margin: 0 0 28px;
max-width: 380px;
font-size: 0.8125rem;
line-height: 1.7;
color: var(--color-text-muted);
}
.cart-empty-card__actions {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
.cart-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 44px;
padding: 0 22px;
border-radius: var(--radius-md);
font-family: inherit;
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
transition: opacity 0.15s, background 0.15s;
}
.cart-btn--primary {
border: none;
background: var(--color-primary);
color: var(--color-surface);
}
.cart-btn--primary:hover {
background: var(--color-primary-dark);
}
.cart-btn--outline {
border: 1px solid var(--color-border);
background: var(--color-surface);
color: var(--color-primary);
}
.cart-btn--outline:hover {
background: var(--color-primary-soft);
}
.cart-items-card__scroll {
overflow-x: auto;
}
.cart-items-table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
min-width: 520px;
}
.cart-items-table th {
padding: 14px 18px;
text-align: start;
font-size: 0.8125rem;
font-weight: 600;
color: var(--color-text-muted);
background: var(--color-bg);
border-bottom: 1px solid var(--color-border);
}
.cart-items-table td {
padding: 16px 18px;
border-bottom: 1px solid var(--color-border);
color: var(--color-text);
vertical-align: middle;
}
.cart-items-table tr:last-child td {
border-bottom: none;
}
.cart-items-table__name {
font-weight: 600;
}
.cart-items-table__delete {
border: none;
background: none;
cursor: pointer;
color: var(--color-text-muted);
padding: 4px;
display: inline-flex;
}
.cart-items-table__delete:hover {
color: var(--color-danger);
}
.cart-summary-card,
.cart-guide-card {
padding: 18px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
}
.cart-summary-card__title,
.cart-guide-card__title {
display: flex;
align-items: center;
gap: 8px;
margin: 0 0 14px;
font-size: 0.9375rem;
font-weight: 700;
color: var(--color-text);
}
.cart-summary-card__title-icon,
.cart-guide-card__title-icon {
display: flex;
align-items: center;
justify-content: center;
color: var(--color-primary);
}
.cart-summary-card__rows {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 16px;
}
.cart-summary-card__row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 0;
font-size: 0.8125rem;
border-bottom: 1px solid var(--color-border);
}
.cart-summary-card__row--sub {
padding-block: 6px;
font-size: 0.8125rem;
color: var(--color-text-muted);
}
.cart-summary-card__cap {
font-weight: 500;
color: var(--color-text-muted);
}
.cart-summary-card__row:last-child {
border-bottom: none;
}
.cart-summary-card__row-label {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--color-text-muted);
}
.cart-summary-card__row strong {
font-variant-numeric: tabular-nums;
color: var(--color-text);
}
.cart-summary-card__hint-value {
color: var(--color-text-muted);
font-size: 0.75rem;
}
.cart-summary-card__note {
margin: 10px 0 0;
font-size: 0.75rem;
line-height: 1.6;
color: var(--color-text-muted);
}
.cart-summary-card__cta {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
min-height: 44px;
border: 1px solid transparent;
border-radius: var(--radius-md);
background: var(--color-primary);
color: var(--color-surface);
font-family: inherit;
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.cart-summary-card__cta:hover:not(:disabled) {
background: var(--color-primary-dark);
}
.cart-summary-card__cta:disabled {
background: var(--color-elevated);
border-color: var(--color-border);
color: var(--color-text-muted);
cursor: not-allowed;
}
.cart-guide-card__text {
margin: 0;
font-size: 0.75rem;
line-height: 1.75;
color: var(--color-text-muted);
}
.cart-quick-nav {
direction: ltr;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-bottom: 20px;
}
.cart-quick-nav__item {
direction: rtl;
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 12px;
padding: 16px 18px;
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
background: var(--color-surface);
box-shadow: var(--shadow-card);
cursor: pointer;
text-align: right;
font-family: inherit;
transition: border-color 0.15s, box-shadow 0.15s;
}
.cart-quick-nav__item:hover {
border-color: var(--color-primary);
box-shadow: var(--shadow-md);
}
.cart-quick-nav__icon {
width: 42px;
height: 42px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.cart-quick-nav__icon--blue {
background: var(--color-primary-soft);
color: var(--color-primary);
}
.cart-quick-nav__icon--green {
background: var(--color-success-soft);
color: var(--color-success);
}
.cart-quick-nav__body {
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
.cart-quick-nav__title {
font-size: 0.875rem;
font-weight: 700;
color: var(--color-text);
}
.cart-quick-nav__desc {
font-size: 0.6875rem;
color: var(--color-text-muted);
line-height: 1.4;
}
.cart-quick-nav__chevron {
color: var(--color-text-muted);
flex-shrink: 0;
}
.cart-desktop-page__footer {
margin: 0;
text-align: center;
font-size: 0.75rem;
color: var(--color-text-muted);
}
</style>