新增合作与反馈入口配置
This commit is contained in:
@@ -4,10 +4,7 @@ import { ElMessage } from 'element-plus'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { uploadAdminFile } from '@/shared/api/files'
|
||||
import {
|
||||
defaultAWRecycleConfig,
|
||||
type AWRecycleConfig,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import type { AWRecycleConfig } from '@/features/listings/api/homeConfig'
|
||||
import { updateSystemConfig, type SystemConfig } from '@/features/admin/api/systemConfigs'
|
||||
import { safeParseJSON } from '@/shared/utils/json'
|
||||
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||
@@ -15,6 +12,10 @@ import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
config: SystemConfig
|
||||
defaults: AWRecycleConfig
|
||||
dialogTitle: string
|
||||
uploadScene: string
|
||||
imageHint: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -25,31 +26,31 @@ const emit = defineEmits<{
|
||||
const submitting = ref(false)
|
||||
const uploading = ref(false)
|
||||
const description = ref('')
|
||||
const draft = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
|
||||
const draft = ref<AWRecycleConfig>({ ...props.defaults })
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
val => {
|
||||
if (!val) return
|
||||
draft.value = parseAWRecycle(props.config.value)
|
||||
draft.value = parseImageEntry(props.config.value)
|
||||
description.value = props.config.description || ''
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
function parseAWRecycle(raw: string): AWRecycleConfig {
|
||||
const parsed = safeParseJSON(raw, defaultAWRecycleConfig)
|
||||
function parseImageEntry(raw: string): AWRecycleConfig {
|
||||
const parsed = safeParseJSON(raw, props.defaults)
|
||||
return {
|
||||
title:
|
||||
typeof parsed.title === 'string' && parsed.title.trim()
|
||||
? parsed.title.trim()
|
||||
: defaultAWRecycleConfig.title,
|
||||
: props.defaults.title,
|
||||
subtitle:
|
||||
typeof parsed.subtitle === 'string' && parsed.subtitle.trim()
|
||||
? parsed.subtitle.trim()
|
||||
: defaultAWRecycleConfig.subtitle,
|
||||
: props.defaults.subtitle,
|
||||
image_url: typeof parsed.image_url === 'string' ? parsed.image_url.trim() : '',
|
||||
enabled: typeof parsed.enabled === 'boolean' ? parsed.enabled : true,
|
||||
enabled: typeof parsed.enabled === 'boolean' ? parsed.enabled : props.defaults.enabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ async function handleUpload(event: Event) {
|
||||
if (!file) return
|
||||
uploading.value = true
|
||||
try {
|
||||
const uploaded = await uploadAdminFile(file, 'aw-recycle')
|
||||
const uploaded = await uploadAdminFile(file, props.uploadScene)
|
||||
draft.value.image_url = uploaded.url
|
||||
ElMessage.success('图片已上传')
|
||||
} catch (error) {
|
||||
@@ -75,8 +76,8 @@ async function handleSave() {
|
||||
try {
|
||||
const value = JSON.stringify(
|
||||
{
|
||||
title: draft.value.title.trim() || defaultAWRecycleConfig.title,
|
||||
subtitle: draft.value.subtitle.trim() || defaultAWRecycleConfig.subtitle,
|
||||
title: draft.value.title.trim() || props.defaults.title,
|
||||
subtitle: draft.value.subtitle.trim() || props.defaults.subtitle,
|
||||
image_url: draft.value.image_url.trim(),
|
||||
enabled: draft.value.enabled,
|
||||
},
|
||||
@@ -101,7 +102,7 @@ async function handleSave() {
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="modelValue"
|
||||
title="编辑 AW炫彩回收"
|
||||
:title="dialogTitle"
|
||||
width="640px"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
>
|
||||
@@ -115,10 +116,10 @@ async function handleSave() {
|
||||
<el-switch v-model="draft.enabled" active-text="显示" inactive-text="隐藏" />
|
||||
</el-form-item>
|
||||
<el-form-item label="标题">
|
||||
<el-input v-model="draft.title" maxlength="32" placeholder="AW炫彩回收" />
|
||||
<el-input v-model="draft.title" maxlength="32" :placeholder="defaults.title" />
|
||||
</el-form-item>
|
||||
<el-form-item label="副标题">
|
||||
<el-input v-model="draft.subtitle" maxlength="64" placeholder="点击查看回收说明" />
|
||||
<el-input v-model="draft.subtitle" maxlength="64" :placeholder="defaults.subtitle" />
|
||||
</el-form-item>
|
||||
<el-form-item label="展示图片">
|
||||
<div class="image-editor">
|
||||
@@ -143,8 +144,7 @@ async function handleSave() {
|
||||
</label>
|
||||
</div>
|
||||
<p class="hint">
|
||||
走后台通用上传(scene=aw-recycle,公开可访问)。首页点击入口后展示此图,建议竖图或说明海报。
|
||||
若旧图路径含 misc/ 且无法预览,请重新上传。
|
||||
{{ imageHint }}
|
||||
</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
@@ -29,7 +29,12 @@ import SalePriceDialog from '../components/SalePriceDialog.vue'
|
||||
import HomeAnnouncementsDialog from '../components/HomeAnnouncementsDialog.vue'
|
||||
import HomeBannersDialog from '../components/HomeBannersDialog.vue'
|
||||
import AwRecycleDialog from '../components/AwRecycleDialog.vue'
|
||||
import { defaultAWRecycleConfig, type AWRecycleConfig } from '@/features/listings/api/homeConfig'
|
||||
import {
|
||||
defaultAWRecycleConfig,
|
||||
defaultCooperationFeedbackConfig,
|
||||
type AWRecycleConfig,
|
||||
type CooperationFeedbackConfig,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import ListingPublishAgreementsDialog from '../components/ListingPublishAgreementsDialog.vue'
|
||||
import OrderAgreementsDialog from '../components/OrderAgreementsDialog.vue'
|
||||
import PostRentalNoticeDialog from '../components/PostRentalNoticeDialog.vue'
|
||||
@@ -75,6 +80,7 @@ const salePriceVisible = ref(false)
|
||||
const announcementsVisible = ref(false)
|
||||
const bannersVisible = ref(false)
|
||||
const awRecycleVisible = ref(false)
|
||||
const cooperationFeedbackVisible = ref(false)
|
||||
const listingPublishAgreementsVisible = ref(false)
|
||||
const agreementsVisible = ref(false)
|
||||
const postRentalNoticeVisible = ref(false)
|
||||
@@ -102,6 +108,9 @@ const homeBannersConfig = computed(
|
||||
const awRecycleConfig = computed(
|
||||
() => configs.value.find(item => item.key === 'mobile.aw_recycle') || null
|
||||
)
|
||||
const cooperationFeedbackConfig = computed(
|
||||
() => configs.value.find(item => item.key === 'mobile.cooperation_feedback') || null
|
||||
)
|
||||
const listingPublishAgreementsConfig = computed(
|
||||
() => configs.value.find(item => item.key === 'listing.publish_agreements') || null
|
||||
)
|
||||
@@ -148,6 +157,7 @@ const regularConfigs = computed(() =>
|
||||
item.key !== 'mobile.home_announcements' &&
|
||||
item.key !== 'mobile.home_banners' &&
|
||||
item.key !== 'mobile.aw_recycle' &&
|
||||
item.key !== 'mobile.cooperation_feedback' &&
|
||||
item.key !== 'listing.publish_agreements' &&
|
||||
item.key !== 'order.agreements' &&
|
||||
item.key !== 'profile.post_rental_notice' &&
|
||||
@@ -201,6 +211,13 @@ const awRecycleStats = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const cooperationFeedbackStats = computed(() => {
|
||||
const item = parseCooperationFeedback(cooperationFeedbackConfig.value?.value || '')
|
||||
return {
|
||||
enabledLabel: item.enabled ? (item.image_url ? '已配置图' : '已开启') : '已隐藏',
|
||||
}
|
||||
})
|
||||
|
||||
const renterGrowthStats = computed(() => {
|
||||
const config = parseRenterGrowthConfig(renterGrowthConfig.value?.value || '')
|
||||
return {
|
||||
@@ -268,6 +285,8 @@ function openEdit(row: SystemConfig) {
|
||||
bannersVisible.value = true
|
||||
} else if (row.key === 'mobile.aw_recycle') {
|
||||
awRecycleVisible.value = true
|
||||
} else if (row.key === 'mobile.cooperation_feedback') {
|
||||
cooperationFeedbackVisible.value = true
|
||||
} else if (row.key === 'listing.publish_agreements') {
|
||||
listingPublishAgreementsVisible.value = true
|
||||
} else if (row.key === 'order.agreements') {
|
||||
@@ -319,6 +338,25 @@ function parseAWRecycle(raw: string): AWRecycleConfig {
|
||||
}
|
||||
}
|
||||
|
||||
function parseCooperationFeedback(raw: string): CooperationFeedbackConfig {
|
||||
const parsed = safeParseJSON(raw, defaultCooperationFeedbackConfig)
|
||||
return {
|
||||
title:
|
||||
typeof parsed.title === 'string' && parsed.title.trim()
|
||||
? parsed.title.trim()
|
||||
: defaultCooperationFeedbackConfig.title,
|
||||
subtitle:
|
||||
typeof parsed.subtitle === 'string' && parsed.subtitle.trim()
|
||||
? parsed.subtitle.trim()
|
||||
: defaultCooperationFeedbackConfig.subtitle,
|
||||
image_url: typeof parsed.image_url === 'string' ? parsed.image_url.trim() : '',
|
||||
enabled:
|
||||
typeof parsed.enabled === 'boolean'
|
||||
? parsed.enabled
|
||||
: defaultCooperationFeedbackConfig.enabled,
|
||||
}
|
||||
}
|
||||
|
||||
function parseOrderAgreements(raw: string) {
|
||||
const parsed = safeParseJSON(raw, defaultOrderAgreements)
|
||||
return {
|
||||
@@ -555,14 +593,19 @@ function formatConfigValue(row: SystemConfig) {
|
||||
</section>
|
||||
|
||||
<section
|
||||
v-if="homeAnnouncementsConfig || homeBannersConfig || awRecycleConfig"
|
||||
v-if="
|
||||
homeAnnouncementsConfig || homeBannersConfig || awRecycleConfig || cooperationFeedbackConfig
|
||||
"
|
||||
class="publish-config-panel"
|
||||
>
|
||||
<div class="publish-config-main">
|
||||
<div>
|
||||
<p class="eyebrow">Home Content</p>
|
||||
<h2>首页运营配置</h2>
|
||||
<span>管理首页公告、轮播图与 AW炫彩回收入口展示图,保存后 PC/移动端从接口读取。</span>
|
||||
<span
|
||||
>管理首页公告、轮播图、AW炫彩回收与合作反馈入口展示图,保存后
|
||||
PC/移动端从接口读取。</span
|
||||
>
|
||||
</div>
|
||||
<div class="panel-actions">
|
||||
<el-button v-if="homeAnnouncementsConfig" @click="openEdit(homeAnnouncementsConfig)"
|
||||
@@ -574,6 +617,12 @@ function formatConfigValue(row: SystemConfig) {
|
||||
<el-button v-if="awRecycleConfig" type="primary" @click="openEdit(awRecycleConfig)"
|
||||
>编辑 AW炫彩回收</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="cooperationFeedbackConfig"
|
||||
type="primary"
|
||||
@click="openEdit(cooperationFeedbackConfig)"
|
||||
>编辑 合作与反馈</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="publish-stat-grid home-stat-grid">
|
||||
@@ -589,6 +638,10 @@ function formatConfigValue(row: SystemConfig) {
|
||||
<strong>{{ awRecycleStats.enabledLabel }}</strong>
|
||||
<span>AW炫彩回收</span>
|
||||
</div>
|
||||
<div class="publish-stat">
|
||||
<strong>{{ cooperationFeedbackStats.enabledLabel }}</strong>
|
||||
<span>合作与反馈</span>
|
||||
</div>
|
||||
<div class="publish-stat">
|
||||
<strong>接口</strong>
|
||||
<span>/api/mobile-home-config</span>
|
||||
@@ -596,7 +649,10 @@ function formatConfigValue(row: SystemConfig) {
|
||||
<div class="publish-stat">
|
||||
<strong>更新</strong>
|
||||
<span>{{
|
||||
formatHomeConfigStatus(awRecycleConfig || homeBannersConfig, '未初始化')
|
||||
formatHomeConfigStatus(
|
||||
cooperationFeedbackConfig || awRecycleConfig || homeBannersConfig,
|
||||
'未初始化'
|
||||
)
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -854,6 +910,21 @@ function formatConfigValue(row: SystemConfig) {
|
||||
v-if="awRecycleConfig"
|
||||
v-model="awRecycleVisible"
|
||||
:config="awRecycleConfig"
|
||||
:defaults="defaultAWRecycleConfig"
|
||||
dialog-title="编辑 AW炫彩回收"
|
||||
upload-scene="aw-recycle"
|
||||
image-hint="走后台通用上传(scene=aw-recycle,公开可访问)。首页点击入口后展示此图,建议竖图或说明海报。"
|
||||
@saved="loadConfigs"
|
||||
/>
|
||||
|
||||
<AwRecycleDialog
|
||||
v-if="cooperationFeedbackConfig"
|
||||
v-model="cooperationFeedbackVisible"
|
||||
:config="cooperationFeedbackConfig"
|
||||
:defaults="defaultCooperationFeedbackConfig"
|
||||
dialog-title="编辑 合作与反馈"
|
||||
upload-scene="cooperation-feedback"
|
||||
image-hint="走后台通用上传(scene=cooperation-feedback,公开可访问)。首页点击入口后展示此图,建议上传合作或反馈联系方式海报。"
|
||||
@saved="loadConfigs"
|
||||
/>
|
||||
|
||||
|
||||
@@ -18,11 +18,19 @@ export interface AWRecycleConfig {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export interface CooperationFeedbackConfig {
|
||||
title: string
|
||||
subtitle: string
|
||||
image_url: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export interface MobileHomeConfig {
|
||||
announcements: string[]
|
||||
banners: HomeBannerSlide[]
|
||||
publish_options: ListingPublishOptions
|
||||
aw_recycle: AWRecycleConfig
|
||||
cooperation_feedback: CooperationFeedbackConfig
|
||||
}
|
||||
|
||||
export const defaultAWRecycleConfig: AWRecycleConfig = {
|
||||
@@ -32,6 +40,13 @@ export const defaultAWRecycleConfig: AWRecycleConfig = {
|
||||
enabled: true,
|
||||
}
|
||||
|
||||
export const defaultCooperationFeedbackConfig: CooperationFeedbackConfig = {
|
||||
title: '合作与反馈',
|
||||
subtitle: '点击查看联系方式',
|
||||
image_url: '',
|
||||
enabled: true,
|
||||
}
|
||||
|
||||
export const defaultHomeAnnouncements = [
|
||||
'平台担保交易,拒绝私下转账/共享验证码,交接全程留痕。',
|
||||
'优先推荐同地区账号,减少异地登录保护触发。',
|
||||
@@ -101,15 +116,38 @@ export function mergeHomeConfig(config?: Partial<MobileHomeConfig>): MobileHomeC
|
||||
? awRaw.subtitle.trim()
|
||||
: defaultAWRecycleConfig.subtitle,
|
||||
image_url:
|
||||
typeof awRaw?.image_url === 'string' ? awRaw.image_url.trim() : defaultAWRecycleConfig.image_url,
|
||||
typeof awRaw?.image_url === 'string'
|
||||
? awRaw.image_url.trim()
|
||||
: defaultAWRecycleConfig.image_url,
|
||||
enabled: typeof awRaw?.enabled === 'boolean' ? awRaw.enabled : defaultAWRecycleConfig.enabled,
|
||||
}
|
||||
|
||||
const cooperationRaw = config?.cooperation_feedback
|
||||
const cooperationFeedback: CooperationFeedbackConfig = {
|
||||
title:
|
||||
typeof cooperationRaw?.title === 'string' && cooperationRaw.title.trim()
|
||||
? cooperationRaw.title.trim()
|
||||
: defaultCooperationFeedbackConfig.title,
|
||||
subtitle:
|
||||
typeof cooperationRaw?.subtitle === 'string' && cooperationRaw.subtitle.trim()
|
||||
? cooperationRaw.subtitle.trim()
|
||||
: defaultCooperationFeedbackConfig.subtitle,
|
||||
image_url:
|
||||
typeof cooperationRaw?.image_url === 'string'
|
||||
? cooperationRaw.image_url.trim()
|
||||
: defaultCooperationFeedbackConfig.image_url,
|
||||
enabled:
|
||||
typeof cooperationRaw?.enabled === 'boolean'
|
||||
? cooperationRaw.enabled
|
||||
: defaultCooperationFeedbackConfig.enabled,
|
||||
}
|
||||
|
||||
return {
|
||||
announcements: announcements.length ? announcements : defaultHomeAnnouncements,
|
||||
banners: banners.length ? banners : defaultHomeBanners,
|
||||
publish_options: mergeListingPublishOptions(config?.publish_options),
|
||||
aw_recycle: awRecycle,
|
||||
cooperation_feedback: cooperationFeedback,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@ import { computed, ref, watch } from 'vue'
|
||||
import { RouterLink, onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
defaultAWRecycleConfig,
|
||||
defaultCooperationFeedbackConfig,
|
||||
defaultHomeAnnouncements,
|
||||
defaultHomeBanners,
|
||||
fetchMobileHomeConfig,
|
||||
type AWRecycleConfig,
|
||||
type CooperationFeedbackConfig,
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import { ElMessage } from 'element-plus'
|
||||
@@ -43,6 +45,8 @@ const announcements = ref<string[]>(defaultHomeAnnouncements)
|
||||
const banners = ref<HomeBannerSlide[]>(defaultHomeBanners)
|
||||
const awRecycle = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
|
||||
const awRecycleDialogVisible = ref(false)
|
||||
const cooperationFeedback = ref<CooperationFeedbackConfig>({ ...defaultCooperationFeedbackConfig })
|
||||
const cooperationFeedbackDialogVisible = ref(false)
|
||||
const publishOptions = ref<ListingPublishOptions>(emptyListingPublishOptions)
|
||||
const sortBy = ref('recommended')
|
||||
const sortOptions = [
|
||||
@@ -156,11 +160,13 @@ async function loadHome() {
|
||||
announcements.value = config.announcements
|
||||
banners.value = config.banners
|
||||
awRecycle.value = config.aw_recycle
|
||||
cooperationFeedback.value = config.cooperation_feedback
|
||||
publishOptions.value = config.publish_options
|
||||
} catch {
|
||||
announcements.value = defaultHomeAnnouncements
|
||||
banners.value = defaultHomeBanners
|
||||
awRecycle.value = { ...defaultAWRecycleConfig }
|
||||
cooperationFeedback.value = { ...defaultCooperationFeedbackConfig }
|
||||
publishOptions.value = emptyListingPublishOptions
|
||||
} finally {
|
||||
loading.value = false
|
||||
@@ -176,6 +182,14 @@ function openAWRecycle() {
|
||||
awRecycleDialogVisible.value = true
|
||||
}
|
||||
|
||||
function openCooperationFeedback() {
|
||||
if (!cooperationFeedback.value.image_url) {
|
||||
ElMessage.warning('合作与反馈图片尚未配置,请稍后再试')
|
||||
return
|
||||
}
|
||||
cooperationFeedbackDialogVisible.value = true
|
||||
}
|
||||
|
||||
function updateFilters(partial: Partial<typeof filters>) {
|
||||
Object.assign(filters, partial)
|
||||
}
|
||||
@@ -366,6 +380,15 @@ loadHome()
|
||||
<strong>{{ awRecycle.title }}</strong>
|
||||
<small>{{ awRecycle.subtitle }}</small>
|
||||
</button>
|
||||
<button
|
||||
v-if="cooperationFeedback.enabled"
|
||||
type="button"
|
||||
class="biz-entry cooperation-feedback"
|
||||
@click="openCooperationFeedback"
|
||||
>
|
||||
<strong>{{ cooperationFeedback.title }}</strong>
|
||||
<small>{{ cooperationFeedback.subtitle }}</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
@@ -387,6 +410,25 @@ loadHome()
|
||||
<el-empty v-else description="暂无展示图片" />
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="cooperationFeedbackDialogVisible"
|
||||
:title="cooperationFeedback.title"
|
||||
width="720px"
|
||||
class="aw-recycle-dialog"
|
||||
align-center
|
||||
destroy-on-close
|
||||
>
|
||||
<AuthImage
|
||||
v-if="cooperationFeedback.image_url"
|
||||
:source="cooperationFeedback.image_url"
|
||||
:alt="cooperationFeedback.title"
|
||||
fit="contain"
|
||||
image-class="aw-recycle-image"
|
||||
:preview-src-list="[cooperationFeedback.image_url]"
|
||||
/>
|
||||
<el-empty v-else description="暂无展示图片" />
|
||||
</el-dialog>
|
||||
|
||||
<HomeFilters
|
||||
:filters="filters"
|
||||
:total-listings="totalListings"
|
||||
@@ -463,7 +505,7 @@ loadHome()
|
||||
|
||||
.biz-entry-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
@@ -514,6 +556,11 @@ loadHome()
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f5f8ff 100%);
|
||||
}
|
||||
|
||||
.biz-entry.cooperation-feedback {
|
||||
border-color: #d9f0e5;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f1fbf6 100%);
|
||||
}
|
||||
|
||||
:deep(.aw-recycle-image) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
@@ -376,6 +376,11 @@
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f5f8ff 100%);
|
||||
}
|
||||
|
||||
.biz-entry.cooperation-feedback {
|
||||
border-color: #d9f0e5;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f1fbf6 100%);
|
||||
}
|
||||
|
||||
.biz-entry strong {
|
||||
color: #17233d;
|
||||
font-size: 15px;
|
||||
|
||||
@@ -15,10 +15,12 @@ import {
|
||||
} from '@/features/listings/api/listings'
|
||||
import {
|
||||
defaultAWRecycleConfig,
|
||||
defaultCooperationFeedbackConfig,
|
||||
defaultHomeAnnouncements,
|
||||
defaultHomeBanners,
|
||||
fetchMobileHomeConfig,
|
||||
type AWRecycleConfig,
|
||||
type CooperationFeedbackConfig,
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import { showImagePreview, showToast } from 'vant'
|
||||
@@ -81,6 +83,8 @@ const announcements = ref<string[]>(defaultHomeAnnouncements)
|
||||
const bannerSlides = ref<HomeBannerSlide[]>(defaultHomeBanners)
|
||||
const awRecycle = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
|
||||
const awRecyclePreviewVisible = ref(false)
|
||||
const cooperationFeedback = ref<CooperationFeedbackConfig>({ ...defaultCooperationFeedbackConfig })
|
||||
const cooperationFeedbackPreviewVisible = ref(false)
|
||||
const supportLoading = ref(false)
|
||||
const showBackTop = ref(false)
|
||||
const mobilePageSize = 10
|
||||
@@ -463,6 +467,7 @@ async function loadHomeConfig() {
|
||||
announcements.value = config.announcements
|
||||
bannerSlides.value = config.banners
|
||||
awRecycle.value = config.aw_recycle
|
||||
cooperationFeedback.value = config.cooperation_feedback
|
||||
publishOptions.value = config.publish_options
|
||||
homeCache.saveHomeConfig({
|
||||
announcements: config.announcements,
|
||||
@@ -473,6 +478,7 @@ async function loadHomeConfig() {
|
||||
announcements.value = defaultHomeAnnouncements
|
||||
bannerSlides.value = defaultHomeBanners
|
||||
awRecycle.value = { ...defaultAWRecycleConfig }
|
||||
cooperationFeedback.value = { ...defaultCooperationFeedbackConfig }
|
||||
publishOptions.value = emptyListingPublishOptions
|
||||
}
|
||||
}
|
||||
@@ -485,6 +491,14 @@ function openAWRecycle() {
|
||||
awRecyclePreviewVisible.value = true
|
||||
}
|
||||
|
||||
function openCooperationFeedback() {
|
||||
if (!cooperationFeedback.value.image_url) {
|
||||
showToast({ message: '合作与反馈图片尚未配置', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
cooperationFeedbackPreviewVisible.value = true
|
||||
}
|
||||
|
||||
function openBannerPreview(slide: HomeBannerSlide) {
|
||||
const url = slide.image_url?.trim()
|
||||
if (!url) return
|
||||
@@ -512,6 +526,7 @@ async function onRefresh() {
|
||||
announcements.value = nextHomeConfig.announcements
|
||||
bannerSlides.value = nextHomeConfig.banners
|
||||
awRecycle.value = nextHomeConfig.aw_recycle
|
||||
cooperationFeedback.value = nextHomeConfig.cooperation_feedback
|
||||
publishOptions.value = nextHomeConfig.publish_options
|
||||
homeCache.saveHomeConfig({
|
||||
announcements: nextHomeConfig.announcements,
|
||||
@@ -894,6 +909,15 @@ syncMobileHomeQuery()
|
||||
<strong>{{ awRecycle.title }}</strong>
|
||||
<small>{{ awRecycle.subtitle }}</small>
|
||||
</button>
|
||||
<button
|
||||
v-if="cooperationFeedback.enabled"
|
||||
type="button"
|
||||
class="biz-entry cooperation-feedback"
|
||||
@click="openCooperationFeedback"
|
||||
>
|
||||
<strong>{{ cooperationFeedback.title }}</strong>
|
||||
<small>{{ cooperationFeedback.subtitle }}</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="zone-strip" aria-label="账号专区">
|
||||
@@ -1111,6 +1135,32 @@ syncMobileHomeQuery()
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-popup
|
||||
v-model:show="cooperationFeedbackPreviewVisible"
|
||||
position="center"
|
||||
round
|
||||
closeable
|
||||
teleport="body"
|
||||
class="aw-recycle-popup"
|
||||
:style="{ width: 'min(92vw, 420px)', maxHeight: '86vh' }"
|
||||
>
|
||||
<div class="aw-recycle-preview">
|
||||
<header class="aw-recycle-preview-head">
|
||||
<h3>{{ cooperationFeedback.title }}</h3>
|
||||
</header>
|
||||
<div class="aw-recycle-preview-body">
|
||||
<AuthImage
|
||||
v-if="cooperationFeedback.image_url"
|
||||
:source="cooperationFeedback.image_url"
|
||||
:alt="cooperationFeedback.title"
|
||||
fit="contain"
|
||||
image-class="aw-recycle-preview-img"
|
||||
/>
|
||||
<van-empty v-else description="暂无展示图片" />
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<MobileBottomNav />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -4,6 +4,7 @@ const IMAGE_UPLOAD_MAX_SIDE: Record<string, number> = {
|
||||
announcement: 1600,
|
||||
'home-banner': 1920,
|
||||
'aw-recycle': 1920,
|
||||
'cooperation-feedback': 1920,
|
||||
listing: 1920,
|
||||
dispute: 1920,
|
||||
handoff: 1920,
|
||||
@@ -17,6 +18,7 @@ const IMAGE_UPLOAD_QUALITY: Record<string, number> = {
|
||||
announcement: 0.84,
|
||||
'home-banner': 0.84,
|
||||
'aw-recycle': 0.84,
|
||||
'cooperation-feedback': 0.84,
|
||||
listing: 0.84,
|
||||
dispute: 0.86,
|
||||
handoff: 0.86,
|
||||
|
||||
Reference in New Issue
Block a user