import { computed } from 'vue' import { useSite } from './useSite' import type { FeatureItem, FeatureSectionSetting, HomeBlocks } from '~/types' /** * 首页「优势模块」统一数据来源 * * 配置来自后台 cms_website_setting.features(经 getSiteInfo 合并进 siteInfo.setting), * 为 JSON 字符串。未配置 / 解析失败时回退到各模板自己的默认数据(defaultFeatures)。 * * 兼容策略: * - 完全未配置(siteSetting.features 不存在)→ 显示 defaultFeatures,标题走兜底 * - 已配置且 enabled=false → enabled=false,上层 v-if 隐藏整块 * - 已配置但 items 为空 → 回退到 defaultFeatures(避免空白区) * - items 超过 4 个 → 截断到 4 个(后台也限制最多 4 个) * * 2026-08-05 新增「首页区块总览」新结构: * { hero, advantages, products, cases, news, banner, cta } * 同时保留对旧结构(顶层 enabled/title/subtitle/items/heroFeatures)的兼容。 * * @param defaultFeatures 模板默认卡片(各模板 FeatureSection 传入自己的硬编码项) */ export function useFeatures(defaultFeatures: FeatureItem[] = []) { const { siteSetting } = useSite() const config = computed(() => { const raw = siteSetting.value?.features if (!raw) return null try { const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw if (parsed && typeof parsed === 'object') return parsed as FeatureSectionSetting return null } catch { return null } }) /** 是否已配置(用于区分「后台显式关闭」与「未接入」) */ const configured = computed(() => !!config.value) /** * 判断是否为新结构(区块化) * 新结构至少包含 hero 或 advantages 字段。 */ const isBlockMode = computed(() => { const c = config.value if (!c) return false return !!(c.hero || c.advantages) }) /** 是否显示优势模块:未配置默认显示;已配置以 enabled 为准(默认 true) */ const enabled = computed(() => { const c = config.value if (!c) return true // 新结构:读 advantages.enabled;旧结构:读顶层 enabled if (isBlockMode.value) { return c.advantages?.enabled !== false } return c.enabled !== false }) const title = computed(() => { const c = config.value if (!c) return '我们的优势' if (isBlockMode.value) return c.advantages?.title || '我们的优势' return c.title || '我们的优势' }) const subtitle = computed(() => { const c = config.value if (!c) return '' if (isBlockMode.value) return c.advantages?.subtitle || '' return c.subtitle || '' }) const items = computed(() => { const c = config.value const cfgItems = isBlockMode.value ? c?.advantages?.items : c?.items if (!cfgItems || !Array.isArray(cfgItems) || cfgItems.length === 0) { return defaultFeatures } return cfgItems.slice(0, 4).map((it) => ({ title: it?.title || '', desc: it?.desc || '', icon: it?.icon || 'box' })) }) /** Hero 首屏右侧特性卡片文案(纯文本),空数组时上层回退模板默认值 */ const heroFeatures = computed(() => { const c = config.value const hf = isBlockMode.value ? c?.hero?.features : c?.heroFeatures if (!hf || !Array.isArray(hf) || hf.length === 0) return [] return hf.slice(0, 4).map((s) => String(s ?? '').trim()).filter(Boolean) }) /** * 首页各区块显示开关。 * 未配置(或旧结构)时,除预留位 products/cases/news/banner/cta 默认 false 外, * hero 与 advantages 默认 true;news/cta 在 template-01 有实际内容,旧结构下默认 true。 */ const homeBlocks = computed>>(() => { const c = config.value const defaults = { hero: true, advantages: true, products: false, cases: false, news: true, banner: true, cta: true } if (!c) return defaults if (isBlockMode.value) { return { hero: c.hero?.enabled !== false, advantages: c.advantages?.enabled !== false, // 产品/案例为预留位,默认不显示,需后台显式开启 products: c.products?.enabled === true, cases: c.cases?.enabled === true, // 新闻/CTA 为多数模板首页实际区块,默认显示,除非后台显式关闭 news: c.news?.enabled !== false, banner: c.banner?.enabled !== false, cta: c.cta?.enabled !== false } } // 旧结构:只有 advantages/hero 的语义;保留 news/cta 默认显示以兼容存量站点 return { hero: c.enabled !== false, advantages: c.enabled !== false, products: false, cases: false, news: true, banner: true, cta: true } }) return { configured, enabled, title, subtitle, items, heroFeatures, homeBlocks, isBlockMode } }