优化首页公告与轮播图
This commit is contained in:
@@ -5,10 +5,15 @@ import { showToast } from "vant";
|
||||
|
||||
import {
|
||||
defaultListingPublishOptions,
|
||||
fetchListingPublishOptions,
|
||||
type ListingPublishOptions,
|
||||
} from "@/api/listingOptions";
|
||||
import { fetchListings, type Listing } from "@/api/listings";
|
||||
import {
|
||||
defaultHomeAnnouncements,
|
||||
defaultHomeBanners,
|
||||
fetchMobileHomeConfig,
|
||||
type HomeBannerSlide,
|
||||
} from "@/api/homeConfig";
|
||||
import MobileHomeFilterSheet, {
|
||||
type FilterSection,
|
||||
} from "./MobileHomeFilterSheet.vue";
|
||||
@@ -45,6 +50,8 @@ const selectedFilters = ref<Record<string, string[]>>({});
|
||||
const rangeFilters = ref<Record<string, { min: string; max: string }>>({});
|
||||
const refreshing = ref(false);
|
||||
const searchValue = ref("");
|
||||
const announcements = ref<string[]>(defaultHomeAnnouncements);
|
||||
const bannerSlides = ref<HomeBannerSlide[]>(defaultHomeBanners);
|
||||
|
||||
const sortOptions = [
|
||||
{ key: "comprehensive", label: "综合排序" },
|
||||
@@ -70,30 +77,6 @@ const rangePresets: Record<string, Array<{ label: string; min: string; max: stri
|
||||
],
|
||||
};
|
||||
|
||||
const bannerSlides = [
|
||||
{
|
||||
eyebrow: "三角洲行动账号专区",
|
||||
title: "高哈夫币 · 安全交接 · 随租随玩",
|
||||
badge: "HOT",
|
||||
pill: "新人领券最高减 20 元",
|
||||
tone: "blue",
|
||||
},
|
||||
{
|
||||
eyebrow: "平台担保交易",
|
||||
title: "交接全程留痕,拒绝私下转账",
|
||||
badge: "SAFE",
|
||||
pill: "租号前先验实名与资料",
|
||||
tone: "green",
|
||||
},
|
||||
{
|
||||
eyebrow: "高效筛选",
|
||||
title: "按区服、段位、哈夫币快速找号",
|
||||
badge: "FAST",
|
||||
pill: "支持扫码号与账密号",
|
||||
tone: "orange",
|
||||
},
|
||||
];
|
||||
|
||||
const fallbackListings = computed(() => buildFallbackListings(publishOptions.value));
|
||||
|
||||
const sourceListings = computed(() =>
|
||||
@@ -178,7 +161,7 @@ function isNavActive(path: string) {
|
||||
|
||||
onMounted(() => {
|
||||
loadListings();
|
||||
loadPublishOptions();
|
||||
loadHomeConfig();
|
||||
});
|
||||
|
||||
async function loadListings() {
|
||||
@@ -193,10 +176,15 @@ async function loadListings() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPublishOptions() {
|
||||
async function loadHomeConfig() {
|
||||
try {
|
||||
publishOptions.value = await fetchListingPublishOptions();
|
||||
const config = await fetchMobileHomeConfig();
|
||||
announcements.value = config.announcements;
|
||||
bannerSlides.value = config.banners;
|
||||
publishOptions.value = config.publish_options;
|
||||
} catch {
|
||||
announcements.value = defaultHomeAnnouncements;
|
||||
bannerSlides.value = defaultHomeBanners;
|
||||
publishOptions.value = defaultListingPublishOptions;
|
||||
}
|
||||
}
|
||||
@@ -204,12 +192,14 @@ async function loadPublishOptions() {
|
||||
async function onRefresh() {
|
||||
refreshing.value = true;
|
||||
try {
|
||||
const [nextListings, nextOptions] = await Promise.all([
|
||||
const [nextListings, nextHomeConfig] = await Promise.all([
|
||||
fetchListings(),
|
||||
fetchListingPublishOptions(),
|
||||
fetchMobileHomeConfig(),
|
||||
]);
|
||||
listings.value = nextListings;
|
||||
publishOptions.value = nextOptions;
|
||||
announcements.value = nextHomeConfig.announcements;
|
||||
bannerSlides.value = nextHomeConfig.banners;
|
||||
publishOptions.value = nextHomeConfig.publish_options;
|
||||
showToast({ message: "刷新成功", icon: "passed" });
|
||||
} catch {
|
||||
// 静默处理
|
||||
@@ -335,7 +325,7 @@ function uniqueOptions(values: string[]) {
|
||||
|
||||
<template>
|
||||
<main class="mobile-shell">
|
||||
<!-- ========== Hero 区域:纯色蓝色头部 ========== -->
|
||||
<!-- ========== Hero 区域:顶部搜索与公告 ========== -->
|
||||
<section class="mobile-hero">
|
||||
<div class="mobile-topbar">
|
||||
<div class="mobile-brand">
|
||||
@@ -345,21 +335,30 @@ function uniqueOptions(values: string[]) {
|
||||
<small>哈夫币租号</small>
|
||||
</div>
|
||||
</div>
|
||||
<van-search
|
||||
v-model="searchValue"
|
||||
shape="round"
|
||||
placeholder="搜区服 / 段位"
|
||||
class="home-search"
|
||||
/>
|
||||
<button class="mobile-service" type="button">客服</button>
|
||||
</div>
|
||||
|
||||
<van-search
|
||||
v-model="searchValue"
|
||||
shape="round"
|
||||
placeholder="搜区服 / 段位 / 哈夫币数量"
|
||||
class="home-search"
|
||||
/>
|
||||
|
||||
<!-- 防骗提示卡片(不用 van-notice-bar) -->
|
||||
<div class="fraud-tip">
|
||||
<van-icon name="warning-o" :size="16" color="#b8860b" />
|
||||
<span class="fraud-dot"></span>
|
||||
<span>平台担保交易,拒绝私下转账/共享验证码,交接全程留痕。</span>
|
||||
<van-swipe
|
||||
class="announcement-swipe"
|
||||
vertical
|
||||
:autoplay="3200"
|
||||
:show-indicators="false"
|
||||
touchable
|
||||
>
|
||||
<van-swipe-item v-for="item in announcements" :key="item">
|
||||
<span>{{ item }}</span>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -370,15 +369,24 @@ function uniqueOptions(values: string[]) {
|
||||
<van-swipe class="banner-swipe" :autoplay="3600" lazy-render>
|
||||
<van-swipe-item
|
||||
v-for="slide in bannerSlides"
|
||||
:key="slide.title"
|
||||
:key="slide.title || slide.image_url"
|
||||
>
|
||||
<div class="mobile-banner" :class="`tone-${slide.tone}`">
|
||||
<div
|
||||
class="mobile-banner"
|
||||
:class="[`tone-${slide.tone}`, { 'has-image': slide.image_url }]"
|
||||
>
|
||||
<img
|
||||
v-if="slide.image_url"
|
||||
class="banner-image"
|
||||
:src="slide.image_url"
|
||||
:alt="slide.title || slide.eyebrow || '首页轮播图'"
|
||||
/>
|
||||
<div>
|
||||
<p>{{ slide.eyebrow }}</p>
|
||||
<h1>{{ slide.title }}</h1>
|
||||
<span>{{ slide.pill }}</span>
|
||||
<p v-if="slide.eyebrow">{{ slide.eyebrow }}</p>
|
||||
<h1 v-if="slide.title">{{ slide.title }}</h1>
|
||||
<span v-if="slide.pill">{{ slide.pill }}</span>
|
||||
</div>
|
||||
<div class="banner-badge">{{ slide.badge }}</div>
|
||||
<div v-if="slide.badge" class="banner-badge">{{ slide.badge }}</div>
|
||||
</div>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
|
||||
Reference in New Issue
Block a user