127 lines
5.6 KiB
Vue
127 lines
5.6 KiB
Vue
<!--
|
|
Ported from legacy henza_pwa/src/views/home/index.vue.
|
|
|
|
Honest adaptations:
|
|
- legacy fetched a single curated payload from POST /front (categories
|
|
with icons, a hand-picked "newest" list, a hand-picked "shelf" list, a
|
|
home banner slider config). The new API only exposes GET
|
|
/catalog/products (flat, uncurated), so `configStore` supplies the
|
|
banner slides (placeholder artwork, legacy's exact slide shape) and
|
|
derives the real category list from the product catalogue. The two
|
|
product sections both draw from the same flat product list (first 4 as
|
|
"newest", the rest as the shelf) rather than two independently curated
|
|
lists.
|
|
- the "please login" nudge (DialogVant, 5s after load) is ported and will
|
|
fire, since there is genuinely no login yet — matching legacy's real
|
|
behavior for an unauthenticated visitor.
|
|
- the notification bell (`NotificationList`) was already commented out of
|
|
legacy's own template — not ported, matching legacy's actual current state.
|
|
-->
|
|
<template>
|
|
<Spinner :spinning="loading" tip="درحال دریافت اطلاعات">
|
|
<AppHeader>
|
|
<nav class="flex justify-between items-center">
|
|
<span></span>
|
|
<img src="/img/henza1.svg" alt="هنزاگلد" />
|
|
</nav>
|
|
</AppHeader>
|
|
<container class="px-[16px] pb-[66px]" v-if="flag">
|
|
<HomeSlider class="z-0 mx-[-16px]" :slides="memory.config.main_slider" :height="sliderHeight" />
|
|
<section>
|
|
<h5 class="font-bold">دسته بندی ها</h5>
|
|
<div class="no-scrollbar grid grid-cols-3 gap-4 mt-[16px] items-stretch">
|
|
<Category class="h-full" v-for="item in memory.cats" :key="item.id" :value="item" />
|
|
</div>
|
|
<Divider class="border-grey"><img v-lazy="vectorIcon" alt="svg" class="mx-[10px]" /></Divider>
|
|
<h4 class="font-bold">محصولات جدید</h4>
|
|
<ProductHorizontal class="mt-[10px]" v-for="item in newestProducts" :key="item.id" :value="item" />
|
|
<router-link :to="{ name: 'newestProduct' }">
|
|
<Button :type="('light' as any)" class="mt-[16px]" block size="large">
|
|
<template #icon>
|
|
<Icon icon="vuesax-linear:arrow-left-1" class="cursor-pointer text-primary" size="25" />
|
|
</template>
|
|
مشاهده همه
|
|
</Button>
|
|
</router-link>
|
|
<Divider class="border-grey"><img v-lazy="vectorIcon" alt="svg" class="mx-[10px]" /></Divider>
|
|
<div class="no-scrollbar flex overflow-x-auto mt-[16px] mx-[-16px] px-[16px]">
|
|
<ProductVertical class="flex-[0_0_280px] ml-[16px]" v-for="item in shelfProducts" :key="item.id" :value="item" />
|
|
<ViewAll class="last:ml-0 flex-[0_0_280px]" to="/search" />
|
|
</div>
|
|
</section>
|
|
</container>
|
|
<DialogVant :timeOut="-1" v-model:show="loginNotify" :closeOnClickOverlay="true">
|
|
<template v-slot:img>
|
|
<img :src="loginDialogImage" alt="" class="opacity-80" />
|
|
</template>
|
|
<template v-slot:title>
|
|
<div class="p-8 text-justify">برای دسترسی به تمامی امکانات نرم افزار هنزاگلد، ابتدا گزینه ورود/ثبت نام را لمس کنید و در صورت نداشتن حساب کاربری، ثبت نام نمایید.</div>
|
|
</template>
|
|
<template v-slot:button>
|
|
<div class="text-center text-[#1C2D56]" @click="router.push({ name: 'login' })">ورود/ثبت نام</div>
|
|
<div class="text-center text-danger" @click="loginNotify = false">بیخیال</div>
|
|
</template>
|
|
</DialogVant>
|
|
</Spinner>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, onMounted, ref } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { Button, Divider } from 'ant-design-vue'
|
|
import Icon from '../components/icon/Icon.vue'
|
|
import AppHeader from '../components/AppHeader.vue'
|
|
import Spinner from '../components/Spinner.vue'
|
|
import DialogVant from '../components/DialogVant.vue'
|
|
import Category from '../components/product/Category.vue'
|
|
import ProductHorizontal from '../components/product/ProductHorizontal.vue'
|
|
import ProductVertical from '../components/product/ProductVertical.vue'
|
|
import ViewAll from '../components/ViewAll.vue'
|
|
import HomeSlider from '../components/slider/HomeSlider.vue'
|
|
import vectorIcon from '../assets/img/Vector.svg'
|
|
import loginDialogImage from '../assets/img/empty/dialogEmpty1.svg'
|
|
import { useWindowDataStore } from '../stores/windowDataStore'
|
|
import { useConfigStore } from '../stores/configStore'
|
|
import { isUserLoggedIn } from '../utils/checkAccess'
|
|
import { api, type ProductSummary } from '../api/client'
|
|
|
|
const router = useRouter()
|
|
const windowData = useWindowDataStore()
|
|
// legacy's `memory` — the global config store (banner slider + categories)
|
|
const memory = useConfigStore()
|
|
|
|
const loading = ref(false)
|
|
const flag = ref(false)
|
|
const loginNotify = ref(false)
|
|
const products = ref<ProductSummary[]>([])
|
|
|
|
const newestProducts = computed(() => products.value.slice(0, 4))
|
|
const shelfProducts = computed(() => products.value.slice(4))
|
|
|
|
const sliderHeight = computed(() => Math.min(windowData.width, 768) / 2.2125 + 'px')
|
|
|
|
const getFront = async () => {
|
|
try {
|
|
loading.value = true
|
|
products.value = await api.listProducts()
|
|
flag.value = true
|
|
|
|
setTimeout(() => {
|
|
if (!isUserLoggedIn()) {
|
|
loginNotify.value = true
|
|
}
|
|
}, 5000)
|
|
} catch (e) {
|
|
console.log(e)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
// legacy home/index.vue ran getFront() alongside the global store init, which
|
|
// is what populated the slider + category grid.
|
|
await Promise.all([getFront(), memory.init()])
|
|
})
|
|
</script>
|