update
Some checks failed
deploy / deploy (push) Has been cancelled

This commit is contained in:
toom1996
2026-08-26 19:42:10 +08:00
parent d64a046f82
commit eee2265e15
29 changed files with 337 additions and 2506 deletions

View File

@ -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
}