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:
+76
-6
@@ -5,11 +5,11 @@ import SiteFooter from '~/components/site/SiteFooter.vue'
|
||||
|
||||
const pageRoot = ref(null)
|
||||
const { openConsultation } = useConsultation()
|
||||
const { fetchPublicSiteConfig } = useOfficialContent()
|
||||
const { fetchPublicMediaAsset, fetchPublicSiteConfig } = useOfficialContent()
|
||||
let animationContext
|
||||
|
||||
const { data: siteConfigRows } = await useAsyncData('public-site-config-about', () =>
|
||||
fetchPublicSiteConfig()
|
||||
fetchPublicSiteConfig({ fresh: true })
|
||||
)
|
||||
|
||||
function parseConfigValue(value, fallback) {
|
||||
@@ -31,6 +31,35 @@ const contactConfig = computed(() =>
|
||||
address: '待补充'
|
||||
})
|
||||
)
|
||||
const footerConfig = computed(() => parseConfigValue(siteConfig.value.FOOTER, {}))
|
||||
const contactQrAssetId = computed(() => footerConfig.value.qrAssetId || '')
|
||||
const isDirectAssetUrl = (value) =>
|
||||
/^(https?:)?\/\//.test(value) || value.startsWith('/') || value.startsWith('data:image/')
|
||||
const directContactQrSrc = computed(() => {
|
||||
const value = String(contactQrAssetId.value || '').trim()
|
||||
return value && isDirectAssetUrl(value) ? value : ''
|
||||
})
|
||||
const { data: contactQrAsset } = await useAsyncData(
|
||||
'public-site-config-about-contact-qr',
|
||||
() => {
|
||||
const id = String(contactQrAssetId.value || '').trim()
|
||||
if (!id || isDirectAssetUrl(id)) return null
|
||||
return fetchPublicMediaAsset(id).catch(() => null)
|
||||
},
|
||||
{ watch: [contactQrAssetId] }
|
||||
)
|
||||
useRefreshNuxtDataOnResume(['public-site-config-about', 'public-site-config-about-contact-qr'])
|
||||
const contactQrSrc = computed(
|
||||
() =>
|
||||
directContactQrSrc.value ||
|
||||
contactQrAsset.value?.url ||
|
||||
contactQrAsset.value?.fileUrl ||
|
||||
contactQrAsset.value?.filePath ||
|
||||
''
|
||||
)
|
||||
const contactQrAlt = computed(
|
||||
() => contactQrAsset.value?.alt || contactQrAsset.value?.name || '社媒二维码'
|
||||
)
|
||||
|
||||
useHead(() => ({
|
||||
title: '关于我们|大马棒·云途全域 GEO',
|
||||
@@ -44,14 +73,28 @@ useHead(() => ({
|
||||
]
|
||||
}))
|
||||
|
||||
const stats = [
|
||||
const fallbackStats = [
|
||||
['1000+', '累计服务客户'],
|
||||
['12+', '覆盖主流行业'],
|
||||
['5 万', '真人内容生产网络'],
|
||||
['5000+', '权威媒体资源']
|
||||
]
|
||||
|
||||
const serviceFlow = [
|
||||
const stats = computed(() => {
|
||||
const rows = parseConfigValue(siteConfig.value.ABOUT_STATS, [])
|
||||
if (!Array.isArray(rows) || rows.length === 0) return fallbackStats
|
||||
|
||||
return rows
|
||||
.filter((item) => item.status !== 'OFFLINE')
|
||||
.sort((left, right) => (Number(left.sortOrder) || 0) - (Number(right.sortOrder) || 0))
|
||||
.map((item) => [
|
||||
item.value || item.metricValue || '',
|
||||
item.label || item.metricLabel || item.title || ''
|
||||
])
|
||||
.filter((item) => item[0] || item[1])
|
||||
})
|
||||
|
||||
const fallbackServiceFlow = [
|
||||
['01', '可见性诊断', '测试品牌在主流 AI 平台中的认知、提及与推荐表现。'],
|
||||
['02', '策略规划', '围绕业务目标、用户问题与行业特征确定 GEO 路径。'],
|
||||
['03', '内容建设', '把真实业务信息转化为用户愿意读、AI 能识别的内容。'],
|
||||
@@ -59,6 +102,21 @@ const serviceFlow = [
|
||||
['05', '效果复盘', '持续监测覆盖率、推荐率、流量与咨询线索质量。']
|
||||
]
|
||||
|
||||
const serviceFlow = computed(() => {
|
||||
const rows = parseConfigValue(siteConfig.value.ABOUT_SERVICE_FLOW, [])
|
||||
if (!Array.isArray(rows) || rows.length === 0) return fallbackServiceFlow
|
||||
|
||||
return rows
|
||||
.filter((item) => item.status !== 'OFFLINE')
|
||||
.sort((left, right) => (Number(left.sortOrder) || 0) - (Number(right.sortOrder) || 0))
|
||||
.map((item, index) => [
|
||||
item.step || item.number || String(index + 1).padStart(2, '0'),
|
||||
item.title || item.heading || '',
|
||||
item.description || item.body || ''
|
||||
])
|
||||
.filter((item) => item[1] || item[2])
|
||||
})
|
||||
|
||||
const fallbackTimeline = [
|
||||
{
|
||||
year: '2023',
|
||||
@@ -101,13 +159,24 @@ const timeline = computed(() => {
|
||||
}))
|
||||
})
|
||||
|
||||
const teamCapabilities = [
|
||||
const fallbackTeamCapabilities = [
|
||||
['搜索理解', '经历 PC 搜索、移动搜索到 AI 搜索的持续变化。'],
|
||||
['内容运营', '理解平台规则,也理解真实用户愿意阅读和相信什么。'],
|
||||
['媒体资源', '长期积累权威媒体、垂直信源与真实创作者网络。'],
|
||||
['业务转化', '不止关注曝光,更关注咨询、线索质量与长期资产。']
|
||||
]
|
||||
|
||||
const teamCapabilities = computed(() => {
|
||||
const rows = parseConfigValue(siteConfig.value.ABOUT_TEAM_CAPABILITIES, [])
|
||||
if (!Array.isArray(rows) || rows.length === 0) return fallbackTeamCapabilities
|
||||
|
||||
return rows
|
||||
.filter((item) => item.status !== 'OFFLINE')
|
||||
.sort((left, right) => (Number(left.sortOrder) || 0) - (Number(right.sortOrder) || 0))
|
||||
.map((item) => [item.title || item.heading || '', item.description || item.body || ''])
|
||||
.filter((item) => item[0] || item[1])
|
||||
})
|
||||
|
||||
function requestDiagnosis(source) {
|
||||
openConsultation({ title: '预约免费 GEO 增长诊断', source })
|
||||
}
|
||||
@@ -344,7 +413,8 @@ onBeforeUnmount(() => animationContext?.revert())
|
||||
</div>
|
||||
</dl>
|
||||
<div class="contact-qr">
|
||||
<span aria-hidden="true"></span><strong>扫码添加专属顾问</strong
|
||||
<img v-if="contactQrSrc" :src="contactQrSrc" :alt="contactQrAlt" loading="lazy" />
|
||||
<span v-else aria-hidden="true"></span><strong>扫码添加专属顾问</strong
|
||||
><small>获取 1 对 1 GEO 增长诊断</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user