const ALL_LABEL = '全部' const LATEST_LABEL = '最新文章' const FALLBACK_IMAGE = '/images/lanhu/slices/home-group95-image21@2x.png' function isUsableUrl(value) { const url = String(value || '').trim() if (!url || url === '#') return false return !/^javascript:/i.test(url) } function pickUrl(asset) { return [asset?.url, asset?.fileUrl, asset?.filePath].find(isUsableUrl) || '' } function buildMediaMap(media = []) { return new Map(media.map((asset) => [asset.id, asset])) } function noCacheOptions(query = {}) { return { query: { ...query, _t: Date.now() }, headers: { 'Cache-Control': 'no-cache' } } } function toTags(value) { if (Array.isArray(value)) return value.filter(Boolean) return String(value || '') .split(/[,,、\s]+/) .map((item) => item.trim()) .filter(Boolean) } function bySortAndTime(left, right) { const leftSort = Number.isFinite(Number(left.sortOrder)) ? Number(left.sortOrder) : 9999 const rightSort = Number.isFinite(Number(right.sortOrder)) ? Number(right.sortOrder) : 9999 if (leftSort !== rightSort) return leftSort - rightSort return String(right.updatedAt || right.publishedAt || '').localeCompare( String(left.updatedAt || left.publishedAt || '') ) } export function useOfficialContent() { const config = useRuntimeConfig() const nuxtApp = useNuxtApp() const apiBase = config.public.officialApiBase || '/api' const siteConfigCache = useState('public-site-config-cache', () => null) const siteConfigLoaded = useState('public-site-config-loaded', () => false) function fetchPublicContent(type) { return $fetch('/public/content', { baseURL: apiBase, ...noCacheOptions({ type }) }) } function fetchPublicCategories() { return $fetch('/public/categories', { baseURL: apiBase, ...noCacheOptions() }) } function fetchHomepageSections() { return $fetch('/public/homepage/sections', { baseURL: apiBase, ...noCacheOptions() }) } function fetchPublicSiteConfig(options = {}) { if (!options.fresh && siteConfigLoaded.value) return siteConfigCache.value || {} nuxtApp._publicSiteConfigPromise ||= $fetch('/public/site-config', { baseURL: apiBase, ...noCacheOptions() }) .then((rows) => { siteConfigCache.value = rows || {} siteConfigLoaded.value = true return siteConfigCache.value }) .finally(() => { nuxtApp._publicSiteConfigPromise = null }) return nuxtApp._publicSiteConfigPromise } function fetchPublicMediaAsset(id) { if (!id) return null return $fetch(`/public/media/${encodeURIComponent(id)}`, { baseURL: apiBase, ...noCacheOptions() }) } function assetUrl(assetId, mediaMap, fallback = FALLBACK_IMAGE) { if (!assetId) return fallback return pickUrl(mediaMap.get(assetId)) || fallback } function assetAlt(assetId, mediaMap, fallback = '') { if (!assetId) return fallback return mediaMap.get(assetId)?.alt || fallback } function normalizeCase(item, mediaMap) { const metric = item.metricValue || '' const metricLabel = item.metricLabel || '' const clientName = item.isAnonymous && item.clientName ? `匿名客户:${item.clientName}` : item.clientName return { ...item, industry: item.industry || item.category || '未分类', client: clientName || '匿名客户', cover: item.coverUrl || assetUrl(item.coverAssetId, mediaMap), coverAlt: item.coverAlt || assetAlt(item.coverAssetId, mediaMap, item.title), summary: item.summary || item.description || '', description: item.description || item.summary || '', metric, metricLabel, metrics: [ [metric, metricLabel], [item.secondary, '辅助成果'] ].filter((row) => row[0]), secondary: item.secondary || '', contentHtml: item.contentHtml || '' } } function normalizeArticle(item, mediaMap) { return { ...item, category: item.category || '未分类', excerpt: item.summary || item.description || '', date: item.publishDate || item.publishedAt?.slice?.(0, 10) || '', readingTime: item.readingTime || '约 5 分钟', views: item.views || '0', cover: item.coverUrl || assetUrl(item.coverAssetId, mediaMap), coverAlt: item.coverAlt || assetAlt(item.coverAssetId, mediaMap, item.title), featured: Boolean(item.isFeatured), tags: toTags(item.tags), contentHtml: item.contentHtml || '' } } function normalizeWhitepaper(item, mediaMap) { const documentAsset = item.documentAssetId ? mediaMap.get(item.documentAssetId) : null return { ...item, category: item.category || '行业白皮书', excerpt: item.summary || item.description || '', cta: item.cta || '获取白皮书', cover: item.coverUrl || assetUrl(item.coverAssetId, mediaMap), documentUrl: isUsableUrl(item.documentUrl) ? item.documentUrl : pickUrl(documentAsset), documentName: item.documentName || documentAsset?.name || item.title, contentHtml: item.contentHtml || '' } } function categoryList(items, field = 'category', extras = []) { const values = items.map((item) => item[field]).filter(Boolean) return [ALL_LABEL, ...extras, ...Array.from(new Set(values))] } return { ALL_LABEL, LATEST_LABEL, bySortAndTime, buildMediaMap, fetchPublicCategories, fetchPublicContent, fetchHomepageSections, fetchPublicMediaAsset, fetchPublicSiteConfig, normalizeCase, normalizeArticle, normalizeWhitepaper, categoryList } }