hookehuyr

feat(help-center): 优化帮助中心页面交互与样式

重构联系客服与问题详情弹窗,提取硬编码数据为常量
使用 NutPopup 组件实现弹窗交互,优化视觉样式
添加富文本内容渲染支持,提升用户体验
......@@ -13,6 +13,7 @@ declare module 'vue' {
NavHeader: typeof import('./src/components/NavHeader.vue')['default']
NutAvatar: typeof import('@nutui/nutui-taro')['Avatar']
NutButton: typeof import('@nutui/nutui-taro')['Button']
NutPopup: typeof import('@nutui/nutui-taro')['Popup']
NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar']
NutTabPane: typeof import('@nutui/nutui-taro')['TabPane']
NutTabs: typeof import('@nutui/nutui-taro')['Tabs']
......
......@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
### Changed
- 优化 "帮助中心" 页面 (`src/pages/help-center`):
- 重构 "联系客服" 弹窗,将硬编码数据提取为 `contactMethods` 数组,并优化样式布局
- 重构 "问题详情" 弹窗,使用 `v-html` 渲染富文本内容,并将模拟数据提取为 `mockRichText` 常量
- 优化弹窗样式,使用 Tailwind CSS 提升视觉体验
### Added
- 新增 "帮助中心" 页面 (`src/pages/help-center`):
- 还原设计稿 (`docs/design/manulife-V1/帮助中心`) 布局与交互
......
<!--
* @Date: 2026-01-29 21:30:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2026-01-30 15:29:14
* @LastEditTime: 2026-01-30 17:16:13
* @FilePath: /manulife-weapp/src/components/IconFont.vue
* @Description: 图标字体组件
-->
......@@ -38,7 +38,8 @@ import {
StarFill,
Top,
Photograph,
Del
Del,
Close,
} from '@nutui/icons-vue-taro';
const props = defineProps({
......@@ -87,7 +88,8 @@ const icons = {
StarFill,
Top,
Photograph,
Del
Del,
Close,
};
const iconComponent = computed(() => {
......
......@@ -4,48 +4,113 @@
<!-- Content Section -->
<view class="px-[32rpx] mt-[32rpx]">
<!-- Search Bar -->
<view class="flex items-center w-full h-[88rpx] bg-white rounded-full px-[32rpx] mb-[32rpx] shadow-sm">
<IconFont name="Search" class="text-gray-400 mr-[16rpx]" size="18" />
<input
type="text"
placeholder="搜索问题或关键词"
placeholder-class="text-gray-400 text-[28rpx]"
class="flex-1 text-[28rpx] text-gray-800 h-full"
/>
</view>
<!-- Contact Service -->
<view class="flex items-center justify-between w-full bg-white rounded-[24rpx] p-[32rpx] mb-[40rpx] shadow-sm relative overflow-hidden">
<!-- Background decoration if needed, or just white card -->
<view class="flex items-center z-10">
<image src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng0bb42ee0fac4d686bb6281afd8462142feb6a7fa9de1286674e2c2010583a3d1" class="w-[80rpx] h-[80rpx] mr-[24rpx]" />
<text class="text-[32rpx] text-gray-900 font-medium">联系客服</text>
</view>
<view class="z-10">
<!-- Search Bar -->
<view class="flex items-center w-full h-[88rpx] bg-white rounded-full px-[32rpx] mb-[32rpx] shadow-sm">
<IconFont name="Search" class="text-gray-400 mr-[16rpx]" size="18" />
<input type="text" placeholder="搜索问题或关键词" placeholder-class="text-gray-400 text-[28rpx]"
class="flex-1 text-[28rpx] text-gray-800 h-full" />
</view>
<!-- Contact Service -->
<view
class="flex items-center justify-between w-full bg-white rounded-[24rpx] p-[32rpx] mb-[40rpx] shadow-sm relative overflow-hidden"
@tap="showContactPopup = true"
>
<view class="flex items-center z-10">
<view class="w-[80rpx] h-[80rpx] rounded-[16rpx] bg-blue-50 flex items-center justify-center mr-[24rpx]">
<IconFont name="Service" size="24" color="#2563EB" />
</view>
<text class="text-[32rpx] text-gray-900 font-medium">联系客服</text>
</view>
<view class="z-10">
<IconFont name="RectRight" class="text-gray-400" size="16" />
</view>
</view>
<!-- Important Questions -->
<view>
<text class="block text-[32rpx] text-gray-900 font-bold mb-[24rpx]">重点问题</text>
<view class="bg-white rounded-[24rpx] shadow-sm overflow-hidden">
<view v-for="(item, index) in questions" :key="index"
class="flex items-center justify-between p-[32rpx] border-b border-gray-100 last:border-b-0 active:bg-gray-50 transition-colors"
@tap="handleQuestionClick(item)">
<view class="flex items-center">
<view class="w-[12rpx] h-[12rpx] rounded-full bg-blue-600 mr-[24rpx]"></view>
<text class="text-[28rpx] text-gray-800">{{ item.title }}</text>
</view>
<IconFont name="RectRight" class="text-gray-400" size="16" />
</view>
</view>
</view>
</view>
</view>
</view>
<!-- Contact Service Popup -->
<nut-popup
v-model:visible="showContactPopup"
position="bottom"
round
:style="{ height: 'auto', paddingBottom: '40rpx' }"
>
<view class="p-[40rpx]">
<!-- Header -->
<view class="flex items-center justify-between mb-[48rpx]">
<view>
<text class="block text-[40rpx] font-bold text-gray-900 mb-[8rpx]">联系我们</text>
<text class="text-[24rpx] text-gray-500">遇到问题?请通过以下方式联系我们</text>
</view>
<view class="w-[64rpx] h-[64rpx] bg-gray-100 rounded-full flex items-center justify-center" @tap="showContactPopup = false">
<IconFont name="Close" size="18" color="#6B7280" />
</view>
</view>
<!-- Important Questions -->
<view>
<text class="block text-[32rpx] text-gray-900 font-bold mb-[24rpx]">重点问题</text>
<view class="bg-white rounded-[24rpx] shadow-sm overflow-hidden">
<!-- Contact Methods List -->
<view class="flex flex-col gap-[24rpx]">
<view
v-for="(item, index) in contactMethods"
:key="index"
class="flex items-center p-[32rpx] bg-white border border-gray-100 rounded-[24rpx] shadow-sm active:bg-gray-50 transition-colors"
>
<view
v-for="(item, index) in questions"
:key="index"
class="flex items-center justify-between p-[32rpx] border-b border-gray-100 last:border-b-0 active:bg-gray-50 transition-colors"
@tap="handleQuestionClick(item)"
class="w-[88rpx] h-[88rpx] rounded-full flex items-center justify-center mr-[24rpx] flex-shrink-0"
:style="{ backgroundColor: `${item.color}15` }"
>
<view class="flex items-center">
<view class="w-[12rpx] h-[12rpx] rounded-full bg-blue-600 mr-[24rpx]"></view>
<text class="text-[28rpx] text-gray-800">{{ item.title }}</text>
</view>
<IconFont name="RectRight" class="text-gray-400" size="16" />
<IconFont :name="item.icon" size="24" :color="item.color" />
</view>
</view>
</view>
</view>
<view class="flex-1">
<view class="flex items-center justify-between mb-[8rpx]">
<text class="text-[28rpx] text-gray-500">{{ item.label }}</text>
</view>
<text class="block text-[32rpx] font-bold text-gray-900 mb-[4rpx]">{{ item.value }}</text>
<text class="text-[22rpx] text-gray-400">{{ item.desc }}</text>
</view>
</view>
</view>
</view>
</nut-popup>
<!-- Question Detail Popup -->
<nut-popup
v-model:visible="showQuestionPopup"
position="bottom"
:style="{ width: '100%', height: '90vh' }"
>
<view class="h-full flex flex-col bg-white">
<!-- Header -->
<view class="flex-shrink-0 px-[32rpx] py-[20rpx] bg-white border-b border-gray-100 flex items-center">
<view class="w-[64rpx] h-[64rpx] flex items-center justify-center -ml-[16rpx]" @tap="showQuestionPopup = false">
<IconFont name="Close" size="20" color="#374151" />
</view>
<text class="flex-1 text-[34rpx] font-bold text-gray-900 text-center pr-[48rpx] truncate">{{ currentQuestion?.title }}</text>
</view>
<!-- Content -->
<scroll-view scroll-y class="flex-1 w-full">
<view class="p-[40rpx]">
<view class="rich-text-container text-[30rpx] leading-[1.8] text-gray-800" v-html="currentQuestion?.content"></view>
</view>
</scroll-view>
</view>
</nut-popup>
<TabBar current="me" />
</view>
......@@ -56,22 +121,110 @@ import { ref } from 'vue'
import NavHeader from '@/components/NavHeader.vue'
import TabBar from '@/components/TabBar.vue'
import IconFont from '@/components/IconFont.vue'
import { useGo } from '@/hooks/useGo'
const go = useGo()
// Popup 状态
const showContactPopup = ref(false)
const showQuestionPopup = ref(false)
const currentQuestion = ref(null)
// Contact methods data
const contactMethods = [
{
icon: 'Location',
label: '客服热线',
value: '400-888-9999',
desc: '工作时间:周一至周五 9:00-18:00',
color: '#2563EB' // blue-600
},
{
icon: 'Service',
label: '微信公众号',
value: '美乐爱觉',
desc: '搜索"美乐爱觉"关注我们',
color: '#16A34A' // green-600
},
{
icon: 'Edit',
label: '邮箱',
value: 'service@manulife.com',
desc: '我们会在24小时内回复您的邮件',
color: '#EA580C' // orange-600
}
]
// Mock Rich Text Content
const mockRichText = `
<div class="rich-text-content">
<h3 style="font-size: 16px; font-weight: bold; color: #1F2937; margin-bottom: 12px;">操作步骤:</h3>
<div style="margin-bottom: 8px; color: #374151;">
<span style="color: #EF4444; font-weight: 500;">步骤 1:</span>
<span>登录系统后,点击左侧菜单的"计划书管理"</span>
</div>
<div style="margin-bottom: 8px; color: #374151;">
<span style="color: #EF4444; font-weight: 500;">步骤 2:</span>
<span>点击右上角"新建计划书"按钮</span>
</div>
<div style="margin-bottom: 8px; color: #374151;">
<span style="color: #EF4444; font-weight: 500;">步骤 3:</span>
<span>填写客户信息、保障方案等详细内容</span>
</div>
<div style="margin-bottom: 12px; color: #374151;">
<span style="color: #EF4444; font-weight: 500;">步骤 4:</span>
<span>点击"生成"按钮,系统将自动生成专业的计划书文档</span>
</div>
<div style="background-color: #FEFCE8; border-left: 4px solid #FACC15; padding: 12px; margin: 16px 0; border-radius: 4px;">
<span style="font-size: 12px; color: #854D0E;">💡 小提示:生成后的计划书可以随时在"我的计划书"中查看和管理。</span>
</div>
<h3 style="font-size: 16px; font-weight: bold; color: #1F2937; margin: 16px 0 12px;">常见问题:</h3>
<div style="margin-bottom: 12px;">
<div style="font-weight: 500; color: #374151; margin-bottom: 4px;">Q:如何修改已生成的计划书?</div>
<div style="color: #4B5563;">A:在"我的计划书"列表中,找到对应的计划书,点击"编辑"按钮即可修改内容。</div>
</div>
<div style="margin-bottom: 12px;">
<div style="font-weight: 500; color: #374151; margin-bottom: 4px;">Q:可以导出为PDF吗?</div>
<div style="color: #4B5563;">A:可以的。在计划书详情页,点击"下载PDF"按钮即可导出高清PDF文件。</div>
</div>
</div>
`
const questions = ref([
{ title: '如何创建新的计划书?', id: 1 },
{ title: 'AI答疑如何使用?', id: 2 },
{ title: '如何修改个人信息?', id: 3 },
{ title: '数据如何同步到云端?', id: 4 },
{ title: '忘记密码怎么办?', id: 5 }
{
title: '如何创建新的计划书?',
id: 1,
content: mockRichText
},
{
title: 'AI答疑如何使用?',
id: 2,
content: mockRichText
},
{
title: '如何修改个人信息?',
id: 3,
content: mockRichText
},
{
title: '数据如何同步到云端?',
id: 4,
content: mockRichText
},
{
title: '忘记密码怎么办?',
id: 5,
content: mockRichText
}
])
const handleQuestionClick = (item) => {
// Navigate to detail or show answer
console.log('Clicked question:', item.title)
// Example navigation (adjust path as needed)
// go('/pages/help-detail/index', { id: item.id })
currentQuestion.value = item
showQuestionPopup.value = true
}
</script>
......