changes of UI
This commit is contained in:
@@ -78,7 +78,7 @@ function openSeason(id: string) {
|
||||
<section>
|
||||
<h2 class="block-title">انتخاب بر اساس کاربرد</h2>
|
||||
<p class="block-sub">دسته موردنظر خود را انتخاب کنید</p>
|
||||
<div class="usage-grid scroll-x">
|
||||
<div class="usage-grid">
|
||||
<button
|
||||
v-for="item in usageCategories"
|
||||
:key="item.id"
|
||||
@@ -238,22 +238,17 @@ function openSeason(id: string) {
|
||||
}
|
||||
|
||||
.usage-grid {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 8px;
|
||||
margin-inline: calc(-1 * var(--page-padding));
|
||||
padding-inline: var(--page-padding);
|
||||
padding-bottom: 4px;
|
||||
scroll-snap-type: x proximity;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.usage-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
flex: 0 0 148px;
|
||||
width: 148px;
|
||||
scroll-snap-align: start;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
border: none;
|
||||
@@ -538,13 +533,6 @@ function openSeason(id: string) {
|
||||
|
||||
.usage-grid {
|
||||
gap: 16px;
|
||||
margin-inline: 0;
|
||||
padding-inline: 0;
|
||||
}
|
||||
|
||||
.usage-card {
|
||||
flex-basis: 168px;
|
||||
width: 168px;
|
||||
}
|
||||
|
||||
.usage-card__body strong {
|
||||
|
||||
@@ -9,9 +9,10 @@ import { fetchMySuggestions, type ProductSuggestionDto } from '@/services/sugges
|
||||
import IconBell from '@/components/icons/IconBell.vue'
|
||||
import IconChevronLeft from '@/components/icons/IconChevronLeft.vue'
|
||||
import levelMedalIcon from '@/assets/images/level-medal.webp'
|
||||
import quickClubCrownIcon from '@/assets/images/quick-club-crown.webp'
|
||||
// import quickClubCrownIcon from '@/assets/images/quick-club-crown.webp'
|
||||
import quickCategoriesGridIcon from '@/assets/images/quick-categories-grid.webp'
|
||||
import quickCatalogRequestIcon from '@/assets/images/quick-catalog-request.webp'
|
||||
import latestOrderStatus from '@/assets/images/latest-order-status.webp'
|
||||
import quickNewProductsIcon from '@/assets/images/quick-new-products.webp'
|
||||
import IconHeart from '@/components/icons/IconHeart.vue'
|
||||
import IconChevronBack from '@/components/icons/IconChevronBack.vue'
|
||||
@@ -51,14 +52,14 @@ type QuickAction = {
|
||||
const customerActions: QuickAction[] = [
|
||||
{ id: 'qa-new', label: 'محصولات جدید', to: '/products', image: quickNewProductsIcon },
|
||||
{ id: 'qa-cat', label: 'دسته بندی', to: '/categories', image: quickCategoriesGridIcon },
|
||||
{ id: 'qa-club', label: 'آخرین وضعیت سفارش', to: '/orders/latest-status', image:'/' },
|
||||
{ id: 'qa-club', label: 'آخرین وضعیت سفارش', to: '/orders/latest-status', image:latestOrderStatus },
|
||||
{ id: 'qa-swatch', label: 'آخرین درخواست کالیته', to: '/catalog-requests/latest-status', image: quickCatalogRequestIcon },
|
||||
]
|
||||
|
||||
const agentActions: QuickAction[] = [
|
||||
{ id: 'qa-new', label: 'محصولات جدید', to: '/products', image: quickNewProductsIcon },
|
||||
{ id: 'qa-cat', label: 'دسته بندی', to: '/categories', image: quickCategoriesGridIcon },
|
||||
{ id: 'qa-customers', label: 'آخرین وضعیت سفارش', to: '/orders/latest-status', image: '/' },
|
||||
{ id: 'qa-customers', label: 'آخرین وضعیت سفارش', to: '/orders/latest-status', image: latestOrderStatus },
|
||||
{ id: 'qa-swatch', label: 'آخرین درخواست کالیته', to: '/catalog-requests/latest-status', image: quickCatalogRequestIcon },
|
||||
]
|
||||
|
||||
|
||||
@@ -6,9 +6,17 @@ import PageSkeleton from '@/components/ui/PageSkeleton.vue'
|
||||
import { useFavoritesStore } from '@/stores/favorites'
|
||||
import { useCrmStore } from '@/stores/crm'
|
||||
import type { CatalogProductCard } from '@/types/crm'
|
||||
import IconHeart from '@/components/icons/IconHeart.vue'
|
||||
import { formatNumber } from '@/utils/format'
|
||||
import { colorImageAt, colorSwatchStyle } from '@/utils/colorSwatch'
|
||||
import IconBookmark from '@/components/icons/IconBookmark.vue'
|
||||
import IconChevronLeft from '@/components/icons/IconChevronLeft.vue'
|
||||
|
||||
const SEASON_LABEL: Record<string, string> = {
|
||||
summer: 'تابستانه',
|
||||
winter: 'زمستانه',
|
||||
all_season: 'چهارفصل',
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
const favorites = useFavoritesStore()
|
||||
const crm = useCrmStore()
|
||||
@@ -30,6 +38,18 @@ onMounted(async () => {
|
||||
}
|
||||
})
|
||||
|
||||
function seasonLabel(season: string) {
|
||||
return SEASON_LABEL[season] ?? '—'
|
||||
}
|
||||
|
||||
function productImage(item: CatalogProductCard) {
|
||||
return colorImageAt(item.colors, item.colorImages, item.imageUrls, 0, item.imageUrl)
|
||||
}
|
||||
|
||||
function openProduct(id: string) {
|
||||
router.push({ path: '/product', query: { id } })
|
||||
}
|
||||
|
||||
async function remove(id: string) {
|
||||
await favorites.toggle(id)
|
||||
products.value = products.value.filter((p) => p.id !== id)
|
||||
@@ -52,22 +72,50 @@ async function remove(id: string) {
|
||||
<article
|
||||
v-for="item in products"
|
||||
:key="item.id"
|
||||
class="row"
|
||||
@click="router.push({ path: '/product', query: { id: item.id } })"
|
||||
class="product-item"
|
||||
@click="openProduct(item.id)"
|
||||
>
|
||||
<div class="row__body">
|
||||
<strong>{{ item.name }}</strong>
|
||||
<span>کد {{ item.code }}</span>
|
||||
<div
|
||||
class="product-item__image"
|
||||
:style="
|
||||
productImage(item)
|
||||
? { backgroundImage: `url(${productImage(item)})` }
|
||||
: colorSwatchStyle(item.colors[0] ?? '')
|
||||
"
|
||||
/>
|
||||
<div class="product-item__body">
|
||||
<div class="product-item__head">
|
||||
<div class="product-item__title">
|
||||
<strong>{{ item.name }}</strong>
|
||||
<span v-if="item.isNew" class="new-tag">جدید</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="bookmark"
|
||||
aria-label="حذف از علاقهمندیها"
|
||||
@click.stop="remove(item.id)"
|
||||
>
|
||||
<IconBookmark :size="18" filled color="var(--color-primary)" />
|
||||
</button>
|
||||
</div>
|
||||
<ul class="product-item__specs">
|
||||
<li>عرض: {{ formatNumber(item.widthCm) }} سانتیمتر</li>
|
||||
<li>ترکیب: {{ item.composition || '—' }}</li>
|
||||
<li>مناسب: {{ seasonLabel(item.season) }}</li>
|
||||
</ul>
|
||||
<div v-if="item.colors.length" class="swatches">
|
||||
<span
|
||||
v-for="(color, idx) in item.colors.slice(0, 6)"
|
||||
:key="idx"
|
||||
class="swatch"
|
||||
:style="colorSwatchStyle(color, item.colorImages?.[idx] || item.imageUrls?.[idx])"
|
||||
/>
|
||||
</div>
|
||||
<button type="button" class="details-link" @click.stop="openProduct(item.id)">
|
||||
مشاهده جزئیات
|
||||
<IconChevronLeft :size="14" />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="bookmark"
|
||||
aria-label="حذف از نشانشدهها"
|
||||
@click.stop="remove(item.id)"
|
||||
>
|
||||
<IconHeart :size="18" filled color="#0a353c" />
|
||||
</button>
|
||||
<IconChevronLeft class="row__chevron" :size="16" color="#9aa3a0" />
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,47 +126,129 @@ async function remove(id: string) {
|
||||
padding: 12px var(--page-padding) 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
color: var(--color-text-muted);
|
||||
padding: 32px 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
.product-item {
|
||||
display: grid;
|
||||
grid-template-columns: 112px 1fr;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 12px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.row__body {
|
||||
flex: 1;
|
||||
.product-item__image {
|
||||
border-radius: 12px;
|
||||
background:
|
||||
linear-gradient(145deg, #2a3544, #111827);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
min-height: 112px;
|
||||
}
|
||||
|
||||
.product-item__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.row__body strong {
|
||||
display: block;
|
||||
.product-item__head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.row__body span {
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.8rem;
|
||||
.product-item__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.product-item__title strong {
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.new-tag {
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bookmark {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin-inline-start: auto;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.product-item__specs {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.55;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.swatches {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.swatch {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.details-link {
|
||||
margin-top: auto;
|
||||
align-self: flex-end;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--color-info);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
padding: 0;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
@@ -133,7 +263,7 @@ async function remove(id: string) {
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
@@ -141,13 +271,13 @@ async function remove(id: string) {
|
||||
padding: 48px 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
box-shadow: var(--shadow-card);
|
||||
border: 1px solid var(--color-border);
|
||||
.product-item {
|
||||
grid-template-columns: 120px 1fr;
|
||||
min-height: 140px;
|
||||
}
|
||||
|
||||
.row__chevron {
|
||||
display: none;
|
||||
.product-item__image {
|
||||
min-height: 116px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import IconBell from '@/components/icons/IconBell.vue'
|
||||
import IconSettings from '@/components/icons/IconSettings.vue'
|
||||
import IconChevronLeft from '@/components/icons/IconChevronLeft.vue'
|
||||
import IconCart from '@/components/icons/IconCart.vue'
|
||||
import IconHeart from '@/components/icons/IconHeart.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import PageSkeleton from '@/components/ui/PageSkeleton.vue'
|
||||
import UserAvatar from '@/components/ui/UserAvatar.vue'
|
||||
@@ -41,21 +42,31 @@ const profile = ref<AgentProfileDto | null>(null)
|
||||
const sampleProduct = ref<CatalogProductCard>(SAMPLE_PRODUCT)
|
||||
const loading = ref(false)
|
||||
|
||||
const agentQuickActions = [
|
||||
{ label: 'ثبت مشتری جدید', to: '/customers', icon: 'vuesax-linear:add' },
|
||||
{ label: 'سفارشها', to: '/orders', icon: 'vuesax-linear:document-text' },
|
||||
{ label: 'مشتریان من', to: '/customers', icon: 'vuesax-linear:people' },
|
||||
{ label: 'گزارشها', to: '/reminders', icon: 'vuesax-linear:chart-2' },
|
||||
{ label: 'درخواست کالیته', to: '/categories', icon: 'vuesax-linear:category' },
|
||||
{ label: 'قیمتگذاری', to: '/categories', icon: 'vuesax-linear:money-4' },
|
||||
] as const
|
||||
type QuickAction = {
|
||||
id: string
|
||||
label: string
|
||||
to: string
|
||||
icon?: string
|
||||
useHeart?: boolean
|
||||
}
|
||||
|
||||
const customerQuickActions = [
|
||||
{ label: 'سفارشها', to: '/orders', icon: 'vuesax-linear:document-text' },
|
||||
{ label: 'دستهبندی', to: '/categories', icon: 'vuesax-linear:category-2' },
|
||||
{ label: 'درخواست کالیته', to: '/categories', icon: 'vuesax-linear:category' },
|
||||
{ label: 'علاقهمندیها', to: '/favorites', icon: 'vuesax-linear:heart' },
|
||||
] as const
|
||||
const agentQuickActions: QuickAction[] = [
|
||||
{ id: 'add-customer', label: 'ثبت مشتری جدید', to: '/customers', icon: 'vuesax-linear:add' },
|
||||
{ id: 'orders', label: 'سفارشها', to: '/orders', icon: 'vuesax-linear:document-text' },
|
||||
{ id: 'customers', label: 'مشتریان من', to: '/customers', icon: 'vuesax-linear:people' },
|
||||
{ id: 'reports', label: 'گزارشها', to: '/reminders', icon: 'vuesax-linear:chart-2' },
|
||||
{ id: 'catalog', label: 'درخواست کالیته', to: '/categories', icon: 'vuesax-linear:box-1' },
|
||||
{ id: 'pricing', label: 'قیمتگذاری', to: '/categories', icon: 'vuesax-linear:money-4' },
|
||||
]
|
||||
|
||||
const customerQuickActions: QuickAction[] = [
|
||||
{ id: 'orders', label: 'سفارشها', to: '/orders', icon: 'vuesax-linear:document-text' },
|
||||
{ id: 'categories', label: 'دستهبندی', to: '/categories', icon: 'vuesax-linear:element-3' },
|
||||
{ id: 'products', label: 'محصولات', to: '/products', icon: 'vuesax-linear:box-search' },
|
||||
{ id: 'favorites', label: 'علاقهمندیها', to: '/favorites', useHeart: true },
|
||||
{ id: 'order-status', label: 'وضعیت سفارش', to: '/orders/latest-status', icon: 'vuesax-linear:timer-1' },
|
||||
{ id: 'catalog', label: 'درخواست کالیته', to: '/categories', icon: 'vuesax-linear:box-1' },
|
||||
]
|
||||
|
||||
const quickActions = computed(() =>
|
||||
auth.isAgent ? agentQuickActions : customerQuickActions,
|
||||
@@ -281,13 +292,23 @@ onMounted(async () => {
|
||||
<div class="quick-grid">
|
||||
<button
|
||||
v-for="item in quickActions"
|
||||
:key="item.label"
|
||||
:key="item.id"
|
||||
type="button"
|
||||
class="quick-item"
|
||||
@click="router.push(item.to)"
|
||||
>
|
||||
<span class="quick-item__icon">
|
||||
<BasicIcon :icon="item.icon" :size="22" :stroke-width="1.5" />
|
||||
<IconHeart
|
||||
v-if="item.useHeart"
|
||||
:size="22"
|
||||
:color="'var(--color-primary)'"
|
||||
/>
|
||||
<BasicIcon
|
||||
v-else-if="item.icon"
|
||||
:icon="item.icon"
|
||||
:size="22"
|
||||
:stroke-width="1.5"
|
||||
/>
|
||||
</span>
|
||||
{{ item.label }}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user