fix(distribution): 修复分站跑马灯公告把配置 JSON 原文展示出来

分销站公告存在 distribution_sites.announcements_json 的是 { title, content } 对象数组
(分销后台品牌装修写入),而前台跑马灯组件按字符串数组渲染。Vue 对对象会做
JSON.stringify,配合 no-wrap 样式,前台就显示成
{"title":"天域商行专注AWM子弹回收、高比例!不排队!秒结算!","content":""}。

- 新增 shared/utils/announcements.ts:把公告条目归一化为展示文本,兼容纯文本、
  { title, content } 对象,以及被字符串化的对象(历史脏数据)与标题为空回退内容
- distributionSite store 解析 announcements_json 时归一化,跑马灯组件内部再兜底一次
- 首页配置 mergeHomeConfig 同样接受对象形态,主站/移动端公告入口口径统一
- 分销后台装修预览的跑马灯示例按同一口径取值(只有内容时不再空白)
- 补 9 条单测覆盖对象、字符串化对象、普通花括号文案、混排去重与空输入
This commit is contained in:
yml2213
2026-10-01 09:04:28 +08:00
parent 766c923a6a
commit 53b40f8fad
6 changed files with 152 additions and 9 deletions
@@ -1,5 +1,6 @@
import { apiClient } from '@/shared/api/client'
import type { ApiResponse } from '@/shared/types/types'
import { normalizeAnnouncements } from '@/shared/utils/announcements'
import { mergeListingPublishOptions, type ListingPublishOptions } from './listingOptions'
export interface HomeBannerSlide {
@@ -86,10 +87,8 @@ export async function fetchMobileHomeConfig() {
}
export function mergeHomeConfig(config?: Partial<MobileHomeConfig>): MobileHomeConfig {
const announcements =
config?.announcements
?.map(item => (typeof item === 'string' ? item.trim() : ''))
.filter(Boolean) || []
// 公告可能是纯文本,也可能是 { title, content } 对象(分销站装修口径),统一归一化。
const announcements = normalizeAnnouncements(config?.announcements)
const banners =
config?.banners
?.map(item => {
@@ -1,11 +1,17 @@
<script setup lang="ts">
import { computed } from 'vue'
import { Bell } from '@element-plus/icons-vue'
import { normalizeAnnouncements, type AnnouncementLike } from '@/shared/utils/announcements'
interface Props {
announcements: string[]
// 兼容历史形态:纯文本、{ title, content } 对象,或其中任意来源的混合数组。
announcements: Array<string | AnnouncementLike>
}
defineProps<Props>()
const props = defineProps<Props>()
// 组件自身再兜底归一化一次:即使调用方直接传了站点公告对象,也不会渲染出 JSON 原文。
const items = computed(() => normalizeAnnouncements(props.announcements))
</script>
<template>
@@ -18,7 +24,7 @@ defineProps<Props>()
:autoplay="true"
:interval="3200"
>
<el-carousel-item v-for="item in announcements" :key="item">
<el-carousel-item v-for="item in items" :key="item">
<span>{{ item }}</span>
</el-carousel-item>
</el-carousel>