feat: add customer service chat, optimize case and homepage, fix api proxy

这一提交完成了多项功能升级与优化:
1.  新增全局浮动客服组件,集成腾讯云TRTC聊天能力并添加错误格式化工具
2.  新增图片资源并调整部分静态文件结构
3.  优化案例页面:重构筛选逻辑、新增空状态处理、添加加载更多功能
4.  优化首页布局:修复统计数字动画、调整移动端适配样式、优化轮播逻辑
5.  重构官方内容获取工具:添加缓存机制、优化媒体资源处理
6.  优化API代理配置,移除默认本地代理并新增环境变量配置
7.  新增页面数据恢复刷新逻辑,优化页面交互体验
8.  修复按钮组件冗余代码,调整头部导航移动端样式
This commit is contained in:
2026-07-24 18:55:51 +08:00
parent 314cd6ccd7
commit 2ff1064de7
25 changed files with 4596 additions and 327 deletions
+37 -9
View File
@@ -5,9 +5,11 @@ import SiteFooter from '~/components/site/SiteFooter.vue'
const {
ALL_LABEL,
LATEST_LABEL,
buildMediaMap,
bySortAndTime,
categoryList,
fetchPublicCategories,
fetchPublicContent,
fetchPublicMediaAsset,
normalizeArticle,
normalizeWhitepaper
} = useOfficialContent()
@@ -17,17 +19,30 @@ const visibleCount = ref(4)
const { openConsultation } = useConsultation()
const { data: pageData } = await useAsyncData('public-insights', async () => {
const [articleRows, whitepaperRows] = await Promise.all([
const [articleRows, whitepaperRows, categories] = await Promise.all([
fetchPublicContent('ARTICLE'),
fetchPublicContent('WHITEPAPER')
fetchPublicContent('WHITEPAPER'),
fetchPublicCategories().catch(() => ({}))
])
const whitepaperAssetIds = Array.from(
new Set(
whitepaperRows.flatMap((item) => [item.coverAssetId, item.documentAssetId]).filter(Boolean)
)
)
const whitepaperMediaRows = await Promise.all(
whitepaperAssetIds.map((id) => fetchPublicMediaAsset(id).catch(() => null))
)
const whitepaperMediaMap = buildMediaMap(whitepaperMediaRows.filter(Boolean))
return {
articles: articleRows.sort(bySortAndTime).map((item) => normalizeArticle(item, new Map())),
whitepapers: whitepaperRows.sort(bySortAndTime).map((item) => normalizeWhitepaper(item, new Map()))
whitepapers: whitepaperRows
.sort(bySortAndTime)
.map((item) => normalizeWhitepaper(item, whitepaperMediaMap)),
categories: categories || {}
}
})
useRefreshNuxtDataOnResume('public-insights')
const insights = computed(() => pageData.value?.articles || [])
const whitepapers = computed(() => pageData.value?.whitepapers || [])
const featuredInsight = computed(
@@ -36,7 +51,15 @@ const featuredInsight = computed(
const featuredWhitepaper = computed(
() => whitepapers.value.find((item) => item.isFeatured) || whitepapers.value[0] || null
)
const insightCategories = computed(() => categoryList(insights.value, 'category', [LATEST_LABEL]))
const insightCategories = computed(() => [
ALL_LABEL,
LATEST_LABEL,
...Array.from(
new Set(
(pageData.value?.categories?.insightCategories || []).map((item) => item.name).filter(Boolean)
)
)
])
useHead({
title: '增长洞察|大马棒·云途全域 GEO',
@@ -74,7 +97,7 @@ function requestWhitepaper(source) {
openConsultation({
title: featuredWhitepaper.value?.title || '获取行业白皮书',
need: featuredWhitepaper.value?.title || '行业白皮书',
need: '行业白皮书',
source
})
}
@@ -227,9 +250,14 @@ function articleTags(article) {
<div class="page-width whitepaper-grid">
<div class="whitepaper-number"><span>REPORT</span><strong>2026</strong></div>
<div class="whitepaper-copy">
<p>{{ featuredWhitepaper?.category || '行业白皮书' }}</p>
<!-- <p>{{ featuredWhitepaper?.category || '行业白皮书' }}</p>-->
<p>行业白皮书</p>
<h2>{{ featuredWhitepaper?.title || 'AI 搜索与品牌增长观察' }}</h2>
<span>{{ featuredWhitepaper?.excerpt || '用户行为 · 内容信源 · 衡量框架 · 行业实践' }}</span>
<!-- <h2>AI 搜索与品牌增长观察</h2>-->
<span>{{
featuredWhitepaper?.excerpt || '用户行为 · 内容信源 · 衡量框架 · 行业实践'
}}</span>
</div>
<button type="button" @click="requestWhitepaper('增长洞察页白皮书')">
{{ featuredWhitepaper?.cta || '获取白皮书' }} <AppIcon name="arrow-right" />