@ -1,20 +1,14 @@
|
||||
---
|
||||
import Breadcrumb from "@/components/Breadcrumb.astro"
|
||||
import { getBrands, getSsgPopularBrands, type BrandEntry } from "@/lib/api"
|
||||
import { getSsgHotBrands } from "@/lib/api"
|
||||
import { getI18n } from '@/i18n/utils'
|
||||
|
||||
|
||||
const { locale, t, getRelativeLocaleUrl } = getI18n(Astro)
|
||||
|
||||
let sidebarBrands: BrandEntry[] = []
|
||||
|
||||
try {
|
||||
sidebarBrands = (await getBrands({ size: 300, only_with_articles: 1, featured: 1 }))
|
||||
.filter((b) => b.id && b.name)
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
} catch {}
|
||||
|
||||
// 热门品牌:构建期走 SSG 内部接口(/api/ssg/brands/popular),不可用时回落假数据先看效果
|
||||
// 热门品牌:走 SSG 专属接口 /api/v1/ssg/brands/hot,后端固定返回热度前 30 个、按热度顺序排列。
|
||||
// 侧栏 filter 展示前 10 个(模板内 slice(0,10)),品牌弹窗 HOT 标签展示全部 30 个。
|
||||
// 接口不可用时回落假数据先看效果。
|
||||
const FAKE_HOT_BRANDS = [
|
||||
{ id: "hot-chanel", name: "Chanel", article_count: 342 },
|
||||
{ id: "hot-dior", name: "Dior", article_count: 318 },
|
||||
@ -31,8 +25,9 @@ const FAKE_HOT_BRANDS = [
|
||||
]
|
||||
let hotBrands: { id: string; name: string; article_count: number }[] = []
|
||||
try {
|
||||
const ssg = await getSsgPopularBrands(12)
|
||||
if (ssg.length) hotBrands = ssg.map((b) => ({ id: String(b.id), name: b.brand || "", article_count: 0 }))
|
||||
hotBrands = (await getSsgHotBrands())
|
||||
.filter((b) => b.id && b.name)
|
||||
.map((b) => ({ id: String(b.id), name: b.name, article_count: b.article_count }))
|
||||
} catch {}
|
||||
if (!hotBrands.length) hotBrands = FAKE_HOT_BRANDS
|
||||
|
||||
@ -284,7 +279,7 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
:disabled="!modalSelected.includes(b.id) && modalMaxReached"
|
||||
@change="toggleModalBrand(b.id)"
|
||||
/>
|
||||
<span class="showsmodal-name" x-text="b.name"></span>
|
||||
<span class="showsmodal-name" x-text="b.display || b.name"></span>
|
||||
<span class="showsmodal-ct" x-text="b.article_count ? b.article_count : ''"></span>
|
||||
</label>
|
||||
</li>
|
||||
@ -302,7 +297,6 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
</div>
|
||||
|
||||
|
||||
<script id="showsbrands-data" type="application/json" set:html={JSON.stringify(sidebarBrands)}></script>
|
||||
<script id="showshotbrands-data" type="application/json" set:html={JSON.stringify(hotBrands)}></script>
|
||||
|
||||
<style>
|
||||
@ -609,14 +603,11 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.data("showsPage", () => {
|
||||
const node = document.getElementById("showsbrands-data")
|
||||
const allBrands: BrandEntry[] = node?.textContent ? JSON.parse(node.textContent) : []
|
||||
const hotNode = document.getElementById("showshotbrands-data")
|
||||
const hotBrands = hotNode?.textContent ? JSON.parse(hotNode.textContent) : []
|
||||
|
||||
return {
|
||||
locale: '',
|
||||
allBrands,
|
||||
hotBrands,
|
||||
SPIN_SVG,
|
||||
collapsedGroups: {
|
||||
@ -629,7 +620,6 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
selectedCt: [] as string[],
|
||||
selectedSeason: [] as string[],
|
||||
selectedYear: [] as string[],
|
||||
brandsExpanded: false,
|
||||
|
||||
// 品牌筛选弹窗状态
|
||||
modalOpen: false,
|
||||
@ -656,35 +646,6 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
this.loadPage(1, false)
|
||||
},
|
||||
|
||||
// 计算属性:侧边栏设计师列表的分组渲染
|
||||
get visibleBrandItems() {
|
||||
const result: any[] = []
|
||||
const map = new Map<string, BrandEntry[]>()
|
||||
for (const b of this.allBrands) {
|
||||
const letter = (b.name[0] || "?").toUpperCase()
|
||||
if (!map.has(letter)) map.set(letter, [])
|
||||
map.get(letter)!.push(b)
|
||||
}
|
||||
const grouped = [...map.entries()].sort((a, b) => a[0].localeCompare(b[0]))
|
||||
|
||||
let shown = 0
|
||||
const MAX_INITIAL = 60
|
||||
for (const [letter, list] of grouped) {
|
||||
if (!this.brandsExpanded && shown >= MAX_INITIAL) break
|
||||
result.push({ type: "letter", letter, key: `letter-${letter}` })
|
||||
for (const b of list) {
|
||||
if (!this.brandsExpanded && shown >= MAX_INITIAL) break
|
||||
result.push({ type: "brand", id: b.id, name: b.name, count: b.article_count, key: b.id })
|
||||
shown++
|
||||
}
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
get hasMoreBrands() {
|
||||
return this.allBrands.length > 60
|
||||
},
|
||||
|
||||
// 骨架屏数量与首屏 data 数量一致,保证「加载中」与「数据完成」两阶段的网格高度相同,消除抖动
|
||||
get skeletonCount() {
|
||||
return this.size
|
||||
@ -694,7 +655,7 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
get pills() {
|
||||
const list: { label: string; clear: () => void }[] = []
|
||||
if (this.selectedBrands.length) {
|
||||
const findName = (id: any) => this.allBrands.find((b) => b.id === id)?.name ?? this.hotBrands.find((b) => b.id === id)?.name ?? `#${id}`
|
||||
const findName = (id: any) => this.hotBrands.find((b) => b.id === id)?.name ?? this.modalResults.find((b) => b.id === id)?.name ?? `#${id}`
|
||||
const labels = this.selectedBrands
|
||||
.map((id) => findName(id))
|
||||
.slice(0, 4)
|
||||
@ -755,9 +716,9 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
this.modalLetter = "HOT"
|
||||
this.modalOpen = true
|
||||
// 锁根滚动并补偿滚动条宽度,避免背景页面横向偏移
|
||||
const sbw = window.innerWidth - document.documentElement.clientWidth
|
||||
document.documentElement.style.overflow = "hidden"
|
||||
if (sbw > 0) document.documentElement.style.paddingRight = sbw + "px"
|
||||
// const sbw = window.innerWidth - document.documentElement.clientWidth
|
||||
// document.documentElement.style.overflow = "hidden"
|
||||
// if (sbw > 0) document.documentElement.style.paddingRight = sbw + "px"
|
||||
await this.modalLoadHot()
|
||||
},
|
||||
closeBrandModal() {
|
||||
@ -769,9 +730,7 @@ const seasonOptions: { value: string; label: string }[] = [
|
||||
this.modalLetter = "HOT"
|
||||
this.modalLoading = true
|
||||
try {
|
||||
this.modalResults = this.hotBrands.length
|
||||
? this.hotBrands.map((b) => ({ id: b.id, name: b.name, article_count: b.article_count || 0 }))
|
||||
: this.allBrands.slice(0, 50)
|
||||
this.modalResults = this.hotBrands.map((b) => ({ id: b.id, name: b.name, article_count: b.article_count || 0 }))
|
||||
} finally {
|
||||
this.modalLoading = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user