新增首页 AW炫彩回收入口,支持后台配置展示图
首页第三入口点击查看回收说明图;配置项 mobile.aw_recycle 可配标题/图片;aw-recycle 走公开文件链路,首页鉴权预览兼容旧私有地址。
This commit is contained in:
@@ -2,11 +2,15 @@
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { RouterLink, useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
defaultAWRecycleConfig,
|
||||
defaultHomeAnnouncements,
|
||||
defaultHomeBanners,
|
||||
fetchMobileHomeConfig,
|
||||
type AWRecycleConfig,
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||
import {
|
||||
emptyListingPublishOptions,
|
||||
type ListingPublishOptions,
|
||||
@@ -37,6 +41,8 @@ import ListingCard from '../components/ListingCard.vue'
|
||||
|
||||
const announcements = ref<string[]>(defaultHomeAnnouncements)
|
||||
const banners = ref<HomeBannerSlide[]>(defaultHomeBanners)
|
||||
const awRecycle = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
|
||||
const awRecycleDialogVisible = ref(false)
|
||||
const publishOptions = ref<ListingPublishOptions>(emptyListingPublishOptions)
|
||||
const sortBy = ref('recommended')
|
||||
const sortOptions = [
|
||||
@@ -149,16 +155,26 @@ async function loadHome() {
|
||||
const [, config] = await Promise.all([loadListingsPage(true), fetchMobileHomeConfig()])
|
||||
announcements.value = config.announcements
|
||||
banners.value = config.banners
|
||||
awRecycle.value = config.aw_recycle
|
||||
publishOptions.value = config.publish_options
|
||||
} catch {
|
||||
announcements.value = defaultHomeAnnouncements
|
||||
banners.value = defaultHomeBanners
|
||||
awRecycle.value = { ...defaultAWRecycleConfig }
|
||||
publishOptions.value = emptyListingPublishOptions
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openAWRecycle() {
|
||||
if (!awRecycle.value.image_url) {
|
||||
ElMessage.warning('回收说明图片尚未配置,请稍后再试')
|
||||
return
|
||||
}
|
||||
awRecycleDialogVisible.value = true
|
||||
}
|
||||
|
||||
function updateFilters(partial: Partial<typeof filters>) {
|
||||
Object.assign(filters, partial)
|
||||
}
|
||||
@@ -275,8 +291,36 @@ loadHome()
|
||||
<strong>撞车 <em>NEW</em></strong>
|
||||
<small>选购商品 · 支付后进群联系客服</small>
|
||||
</RouterLink>
|
||||
<button
|
||||
v-if="awRecycle.enabled"
|
||||
type="button"
|
||||
class="biz-entry aw-recycle"
|
||||
@click="openAWRecycle"
|
||||
>
|
||||
<strong>{{ awRecycle.title }}</strong>
|
||||
<small>{{ awRecycle.subtitle }}</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
v-model="awRecycleDialogVisible"
|
||||
:title="awRecycle.title"
|
||||
width="720px"
|
||||
class="aw-recycle-dialog"
|
||||
align-center
|
||||
destroy-on-close
|
||||
>
|
||||
<AuthImage
|
||||
v-if="awRecycle.image_url"
|
||||
:source="awRecycle.image_url"
|
||||
:alt="awRecycle.title"
|
||||
fit="contain"
|
||||
image-class="aw-recycle-image"
|
||||
:preview-src-list="[awRecycle.image_url]"
|
||||
/>
|
||||
<el-empty v-else description="暂无展示图片" />
|
||||
</el-dialog>
|
||||
|
||||
<HomeFilters
|
||||
:filters="filters"
|
||||
:total-listings="totalListings"
|
||||
@@ -353,7 +397,7 @@ loadHome()
|
||||
|
||||
.biz-entry-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
@@ -366,6 +410,9 @@ loadHome()
|
||||
border: 1px solid #eef1f5;
|
||||
background: #fff;
|
||||
text-decoration: none;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
transition:
|
||||
border-color 0.18s ease,
|
||||
box-shadow 0.18s ease;
|
||||
@@ -396,6 +443,26 @@ loadHome()
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.biz-entry.aw-recycle {
|
||||
border-color: #e8edff;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f5f8ff 100%);
|
||||
}
|
||||
|
||||
:deep(.aw-recycle-image) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-height: 70vh;
|
||||
object-fit: contain;
|
||||
border-radius: 10px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.biz-entry-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.infinite-load-state {
|
||||
padding: 6px 0 18px;
|
||||
color: #94a3b8;
|
||||
|
||||
@@ -345,8 +345,8 @@
|
||||
|
||||
.biz-entry-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
|
||||
@@ -356,14 +356,22 @@
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
padding: 12px 12px 12px 14px;
|
||||
padding: 12px 10px 12px 12px;
|
||||
border-radius: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #eef1f5;
|
||||
text-decoration: none;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
box-shadow: 0 4px 14px rgba(23, 35, 61, 0.04);
|
||||
}
|
||||
|
||||
.biz-entry.aw-recycle {
|
||||
border-color: #e8edff;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f5f8ff 100%);
|
||||
}
|
||||
|
||||
.biz-entry strong {
|
||||
color: #17233d;
|
||||
font-size: 15px;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { onBeforeRouteLeave, RouterLink, useRoute, useRouter } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import MobileBottomNav from '@/components/MobileBottomNav.vue'
|
||||
import { ensureSupportChat, resolveSupportScene } from '@/features/chats/api/chats'
|
||||
import { formatCent, formatMoney } from '@/shared/utils/money'
|
||||
@@ -15,11 +14,15 @@ import {
|
||||
type PublicListingQuery,
|
||||
} from '@/features/listings/api/listings'
|
||||
import {
|
||||
defaultAWRecycleConfig,
|
||||
defaultHomeAnnouncements,
|
||||
defaultHomeBanners,
|
||||
fetchMobileHomeConfig,
|
||||
type AWRecycleConfig,
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import { showImagePreview, showToast } from 'vant'
|
||||
import { fetchFileBlobByURL } from '@/shared/api/files'
|
||||
import MobileHomeFilterSheet, { type FilterSection } from './MobileHomeFilterSheet.vue'
|
||||
import {
|
||||
clearStoredHomeQuery,
|
||||
@@ -76,6 +79,7 @@ const refreshing = ref(false)
|
||||
const searchValue = ref('')
|
||||
const announcements = ref<string[]>(defaultHomeAnnouncements)
|
||||
const bannerSlides = ref<HomeBannerSlide[]>(defaultHomeBanners)
|
||||
const awRecycle = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
|
||||
const supportLoading = ref(false)
|
||||
const showBackTop = ref(false)
|
||||
const mobilePageSize = 10
|
||||
@@ -457,6 +461,7 @@ async function loadHomeConfig() {
|
||||
const config = await fetchMobileHomeConfig()
|
||||
announcements.value = config.announcements
|
||||
bannerSlides.value = config.banners
|
||||
awRecycle.value = config.aw_recycle
|
||||
publishOptions.value = config.publish_options
|
||||
homeCache.saveHomeConfig({
|
||||
announcements: config.announcements,
|
||||
@@ -466,10 +471,39 @@ async function loadHomeConfig() {
|
||||
} catch {
|
||||
announcements.value = defaultHomeAnnouncements
|
||||
bannerSlides.value = defaultHomeBanners
|
||||
awRecycle.value = { ...defaultAWRecycleConfig }
|
||||
publishOptions.value = emptyListingPublishOptions
|
||||
}
|
||||
}
|
||||
|
||||
async function openAWRecycle() {
|
||||
const source = awRecycle.value.image_url
|
||||
if (!source) {
|
||||
showToast({ message: '回收说明图片尚未配置', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
try {
|
||||
// 私有 /api/files/object 需带鉴权拉取;公开 /api/public/files 可直接预览
|
||||
let previewURL = source
|
||||
if (
|
||||
source.includes('/api/files/object') ||
|
||||
source.includes('/api/admin/files/object')
|
||||
) {
|
||||
const blob = await fetchFileBlobByURL(source)
|
||||
previewURL = URL.createObjectURL(blob)
|
||||
}
|
||||
showImagePreview({
|
||||
images: [previewURL],
|
||||
closeable: true,
|
||||
})
|
||||
} catch {
|
||||
showToast({
|
||||
message: '图片加载失败,请在后台重新上传(需使用公开图)',
|
||||
icon: 'cross',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function onRefresh() {
|
||||
refreshing.value = true
|
||||
try {
|
||||
@@ -477,6 +511,7 @@ async function onRefresh() {
|
||||
const [, nextHomeConfig] = await Promise.all([loadListings(true), fetchMobileHomeConfig()])
|
||||
announcements.value = nextHomeConfig.announcements
|
||||
bannerSlides.value = nextHomeConfig.banners
|
||||
awRecycle.value = nextHomeConfig.aw_recycle
|
||||
publishOptions.value = nextHomeConfig.publish_options
|
||||
homeCache.saveHomeConfig({
|
||||
announcements: nextHomeConfig.announcements,
|
||||
@@ -842,6 +877,15 @@ syncMobileHomeQuery()
|
||||
<small>选购商品 · 一键找客服</small>
|
||||
<em class="biz-entry-badge">NEW</em>
|
||||
</RouterLink>
|
||||
<button
|
||||
v-if="awRecycle.enabled"
|
||||
type="button"
|
||||
class="biz-entry aw-recycle"
|
||||
@click="openAWRecycle"
|
||||
>
|
||||
<strong>{{ awRecycle.title }}</strong>
|
||||
<small>{{ awRecycle.subtitle }}</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="zone-strip" aria-label="账号专区">
|
||||
|
||||
Reference in New Issue
Block a user