hookehuyr

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

重构联系客服与问题详情弹窗,提取硬编码数据为常量
使用 NutPopup 组件实现弹窗交互,优化视觉样式
添加富文本内容渲染支持,提升用户体验
...@@ -13,6 +13,7 @@ declare module 'vue' { ...@@ -13,6 +13,7 @@ declare module 'vue' {
13 NavHeader: typeof import('./src/components/NavHeader.vue')['default'] 13 NavHeader: typeof import('./src/components/NavHeader.vue')['default']
14 NutAvatar: typeof import('@nutui/nutui-taro')['Avatar'] 14 NutAvatar: typeof import('@nutui/nutui-taro')['Avatar']
15 NutButton: typeof import('@nutui/nutui-taro')['Button'] 15 NutButton: typeof import('@nutui/nutui-taro')['Button']
16 + NutPopup: typeof import('@nutui/nutui-taro')['Popup']
16 NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] 17 NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar']
17 NutTabPane: typeof import('@nutui/nutui-taro')['TabPane'] 18 NutTabPane: typeof import('@nutui/nutui-taro')['TabPane']
18 NutTabs: typeof import('@nutui/nutui-taro')['Tabs'] 19 NutTabs: typeof import('@nutui/nutui-taro')['Tabs']
......
...@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. ...@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
4 4
5 ## [Unreleased] 5 ## [Unreleased]
6 6
7 +### Changed
8 +- 优化 "帮助中心" 页面 (`src/pages/help-center`):
9 + - 重构 "联系客服" 弹窗,将硬编码数据提取为 `contactMethods` 数组,并优化样式布局
10 + - 重构 "问题详情" 弹窗,使用 `v-html` 渲染富文本内容,并将模拟数据提取为 `mockRichText` 常量
11 + - 优化弹窗样式,使用 Tailwind CSS 提升视觉体验
12 +
7 ### Added 13 ### Added
8 - 新增 "帮助中心" 页面 (`src/pages/help-center`): 14 - 新增 "帮助中心" 页面 (`src/pages/help-center`):
9 - 还原设计稿 (`docs/design/manulife-V1/帮助中心`) 布局与交互 15 - 还原设计稿 (`docs/design/manulife-V1/帮助中心`) 布局与交互
......
1 <!-- 1 <!--
2 * @Date: 2026-01-29 21:30:20 2 * @Date: 2026-01-29 21:30:20
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-30 15:29:14 4 + * @LastEditTime: 2026-01-30 17:16:13
5 * @FilePath: /manulife-weapp/src/components/IconFont.vue 5 * @FilePath: /manulife-weapp/src/components/IconFont.vue
6 * @Description: 图标字体组件 6 * @Description: 图标字体组件
7 --> 7 -->
...@@ -38,7 +38,8 @@ import { ...@@ -38,7 +38,8 @@ import {
38 StarFill, 38 StarFill,
39 Top, 39 Top,
40 Photograph, 40 Photograph,
41 - Del 41 + Del,
42 + Close,
42 } from '@nutui/icons-vue-taro'; 43 } from '@nutui/icons-vue-taro';
43 44
44 const props = defineProps({ 45 const props = defineProps({
...@@ -87,7 +88,8 @@ const icons = { ...@@ -87,7 +88,8 @@ const icons = {
87 StarFill, 88 StarFill,
88 Top, 89 Top,
89 Photograph, 90 Photograph,
90 - Del 91 + Del,
92 + Close,
91 }; 93 };
92 94
93 const iconComponent = computed(() => { 95 const iconComponent = computed(() => {
......
...@@ -7,19 +7,19 @@ ...@@ -7,19 +7,19 @@
7 <!-- Search Bar --> 7 <!-- Search Bar -->
8 <view class="flex items-center w-full h-[88rpx] bg-white rounded-full px-[32rpx] mb-[32rpx] shadow-sm"> 8 <view class="flex items-center w-full h-[88rpx] bg-white rounded-full px-[32rpx] mb-[32rpx] shadow-sm">
9 <IconFont name="Search" class="text-gray-400 mr-[16rpx]" size="18" /> 9 <IconFont name="Search" class="text-gray-400 mr-[16rpx]" size="18" />
10 - <input 10 + <input type="text" placeholder="搜索问题或关键词" placeholder-class="text-gray-400 text-[28rpx]"
11 - type="text" 11 + class="flex-1 text-[28rpx] text-gray-800 h-full" />
12 - placeholder="搜索问题或关键词"
13 - placeholder-class="text-gray-400 text-[28rpx]"
14 - class="flex-1 text-[28rpx] text-gray-800 h-full"
15 - />
16 </view> 12 </view>
17 13
18 <!-- Contact Service --> 14 <!-- Contact Service -->
19 - <view class="flex items-center justify-between w-full bg-white rounded-[24rpx] p-[32rpx] mb-[40rpx] shadow-sm relative overflow-hidden"> 15 + <view
20 - <!-- Background decoration if needed, or just white card --> 16 + class="flex items-center justify-between w-full bg-white rounded-[24rpx] p-[32rpx] mb-[40rpx] shadow-sm relative overflow-hidden"
17 + @tap="showContactPopup = true"
18 + >
21 <view class="flex items-center z-10"> 19 <view class="flex items-center z-10">
22 - <image src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng0bb42ee0fac4d686bb6281afd8462142feb6a7fa9de1286674e2c2010583a3d1" class="w-[80rpx] h-[80rpx] mr-[24rpx]" /> 20 + <view class="w-[80rpx] h-[80rpx] rounded-[16rpx] bg-blue-50 flex items-center justify-center mr-[24rpx]">
21 + <IconFont name="Service" size="24" color="#2563EB" />
22 + </view>
23 <text class="text-[32rpx] text-gray-900 font-medium">联系客服</text> 23 <text class="text-[32rpx] text-gray-900 font-medium">联系客服</text>
24 </view> 24 </view>
25 <view class="z-10"> 25 <view class="z-10">
...@@ -31,12 +31,9 @@ ...@@ -31,12 +31,9 @@
31 <view> 31 <view>
32 <text class="block text-[32rpx] text-gray-900 font-bold mb-[24rpx]">重点问题</text> 32 <text class="block text-[32rpx] text-gray-900 font-bold mb-[24rpx]">重点问题</text>
33 <view class="bg-white rounded-[24rpx] shadow-sm overflow-hidden"> 33 <view class="bg-white rounded-[24rpx] shadow-sm overflow-hidden">
34 - <view 34 + <view v-for="(item, index) in questions" :key="index"
35 - v-for="(item, index) in questions"
36 - :key="index"
37 class="flex items-center justify-between p-[32rpx] border-b border-gray-100 last:border-b-0 active:bg-gray-50 transition-colors" 35 class="flex items-center justify-between p-[32rpx] border-b border-gray-100 last:border-b-0 active:bg-gray-50 transition-colors"
38 - @tap="handleQuestionClick(item)" 36 + @tap="handleQuestionClick(item)">
39 - >
40 <view class="flex items-center"> 37 <view class="flex items-center">
41 <view class="w-[12rpx] h-[12rpx] rounded-full bg-blue-600 mr-[24rpx]"></view> 38 <view class="w-[12rpx] h-[12rpx] rounded-full bg-blue-600 mr-[24rpx]"></view>
42 <text class="text-[28rpx] text-gray-800">{{ item.title }}</text> 39 <text class="text-[28rpx] text-gray-800">{{ item.title }}</text>
...@@ -47,6 +44,74 @@ ...@@ -47,6 +44,74 @@
47 </view> 44 </view>
48 </view> 45 </view>
49 46
47 + <!-- Contact Service Popup -->
48 + <nut-popup
49 + v-model:visible="showContactPopup"
50 + position="bottom"
51 + round
52 + :style="{ height: 'auto', paddingBottom: '40rpx' }"
53 + >
54 + <view class="p-[40rpx]">
55 + <!-- Header -->
56 + <view class="flex items-center justify-between mb-[48rpx]">
57 + <view>
58 + <text class="block text-[40rpx] font-bold text-gray-900 mb-[8rpx]">联系我们</text>
59 + <text class="text-[24rpx] text-gray-500">遇到问题?请通过以下方式联系我们</text>
60 + </view>
61 + <view class="w-[64rpx] h-[64rpx] bg-gray-100 rounded-full flex items-center justify-center" @tap="showContactPopup = false">
62 + <IconFont name="Close" size="18" color="#6B7280" />
63 + </view>
64 + </view>
65 +
66 + <!-- Contact Methods List -->
67 + <view class="flex flex-col gap-[24rpx]">
68 + <view
69 + v-for="(item, index) in contactMethods"
70 + :key="index"
71 + class="flex items-center p-[32rpx] bg-white border border-gray-100 rounded-[24rpx] shadow-sm active:bg-gray-50 transition-colors"
72 + >
73 + <view
74 + class="w-[88rpx] h-[88rpx] rounded-full flex items-center justify-center mr-[24rpx] flex-shrink-0"
75 + :style="{ backgroundColor: `${item.color}15` }"
76 + >
77 + <IconFont :name="item.icon" size="24" :color="item.color" />
78 + </view>
79 + <view class="flex-1">
80 + <view class="flex items-center justify-between mb-[8rpx]">
81 + <text class="text-[28rpx] text-gray-500">{{ item.label }}</text>
82 + </view>
83 + <text class="block text-[32rpx] font-bold text-gray-900 mb-[4rpx]">{{ item.value }}</text>
84 + <text class="text-[22rpx] text-gray-400">{{ item.desc }}</text>
85 + </view>
86 + </view>
87 + </view>
88 + </view>
89 + </nut-popup>
90 +
91 + <!-- Question Detail Popup -->
92 + <nut-popup
93 + v-model:visible="showQuestionPopup"
94 + position="bottom"
95 + :style="{ width: '100%', height: '90vh' }"
96 + >
97 + <view class="h-full flex flex-col bg-white">
98 + <!-- Header -->
99 + <view class="flex-shrink-0 px-[32rpx] py-[20rpx] bg-white border-b border-gray-100 flex items-center">
100 + <view class="w-[64rpx] h-[64rpx] flex items-center justify-center -ml-[16rpx]" @tap="showQuestionPopup = false">
101 + <IconFont name="Close" size="20" color="#374151" />
102 + </view>
103 + <text class="flex-1 text-[34rpx] font-bold text-gray-900 text-center pr-[48rpx] truncate">{{ currentQuestion?.title }}</text>
104 + </view>
105 +
106 + <!-- Content -->
107 + <scroll-view scroll-y class="flex-1 w-full">
108 + <view class="p-[40rpx]">
109 + <view class="rich-text-container text-[30rpx] leading-[1.8] text-gray-800" v-html="currentQuestion?.content"></view>
110 + </view>
111 + </scroll-view>
112 + </view>
113 + </nut-popup>
114 +
50 <TabBar current="me" /> 115 <TabBar current="me" />
51 </view> 116 </view>
52 </template> 117 </template>
...@@ -56,22 +121,110 @@ import { ref } from 'vue' ...@@ -56,22 +121,110 @@ import { ref } from 'vue'
56 import NavHeader from '@/components/NavHeader.vue' 121 import NavHeader from '@/components/NavHeader.vue'
57 import TabBar from '@/components/TabBar.vue' 122 import TabBar from '@/components/TabBar.vue'
58 import IconFont from '@/components/IconFont.vue' 123 import IconFont from '@/components/IconFont.vue'
59 -import { useGo } from '@/hooks/useGo'
60 124
61 -const go = useGo() 125 +// Popup 状态
126 +const showContactPopup = ref(false)
127 +const showQuestionPopup = ref(false)
128 +const currentQuestion = ref(null)
129 +
130 +// Contact methods data
131 +const contactMethods = [
132 + {
133 + icon: 'Location',
134 + label: '客服热线',
135 + value: '400-888-9999',
136 + desc: '工作时间:周一至周五 9:00-18:00',
137 + color: '#2563EB' // blue-600
138 + },
139 + {
140 + icon: 'Service',
141 + label: '微信公众号',
142 + value: '美乐爱觉',
143 + desc: '搜索"美乐爱觉"关注我们',
144 + color: '#16A34A' // green-600
145 + },
146 + {
147 + icon: 'Edit',
148 + label: '邮箱',
149 + value: 'service@manulife.com',
150 + desc: '我们会在24小时内回复您的邮件',
151 + color: '#EA580C' // orange-600
152 + }
153 +]
154 +
155 +// Mock Rich Text Content
156 +const mockRichText = `
157 +<div class="rich-text-content">
158 + <h3 style="font-size: 16px; font-weight: bold; color: #1F2937; margin-bottom: 12px;">操作步骤:</h3>
159 +
160 + <div style="margin-bottom: 8px; color: #374151;">
161 + <span style="color: #EF4444; font-weight: 500;">步骤 1:</span>
162 + <span>登录系统后,点击左侧菜单的"计划书管理"</span>
163 + </div>
164 +
165 + <div style="margin-bottom: 8px; color: #374151;">
166 + <span style="color: #EF4444; font-weight: 500;">步骤 2:</span>
167 + <span>点击右上角"新建计划书"按钮</span>
168 + </div>
169 +
170 + <div style="margin-bottom: 8px; color: #374151;">
171 + <span style="color: #EF4444; font-weight: 500;">步骤 3:</span>
172 + <span>填写客户信息、保障方案等详细内容</span>
173 + </div>
174 +
175 + <div style="margin-bottom: 12px; color: #374151;">
176 + <span style="color: #EF4444; font-weight: 500;">步骤 4:</span>
177 + <span>点击"生成"按钮,系统将自动生成专业的计划书文档</span>
178 + </div>
179 +
180 + <div style="background-color: #FEFCE8; border-left: 4px solid #FACC15; padding: 12px; margin: 16px 0; border-radius: 4px;">
181 + <span style="font-size: 12px; color: #854D0E;">💡 小提示:生成后的计划书可以随时在"我的计划书"中查看和管理。</span>
182 + </div>
183 +
184 + <h3 style="font-size: 16px; font-weight: bold; color: #1F2937; margin: 16px 0 12px;">常见问题:</h3>
185 +
186 + <div style="margin-bottom: 12px;">
187 + <div style="font-weight: 500; color: #374151; margin-bottom: 4px;">Q:如何修改已生成的计划书?</div>
188 + <div style="color: #4B5563;">A:在"我的计划书"列表中,找到对应的计划书,点击"编辑"按钮即可修改内容。</div>
189 + </div>
190 +
191 + <div style="margin-bottom: 12px;">
192 + <div style="font-weight: 500; color: #374151; margin-bottom: 4px;">Q:可以导出为PDF吗?</div>
193 + <div style="color: #4B5563;">A:可以的。在计划书详情页,点击"下载PDF"按钮即可导出高清PDF文件。</div>
194 + </div>
195 +</div>
196 +`
62 197
63 const questions = ref([ 198 const questions = ref([
64 - { title: '如何创建新的计划书?', id: 1 }, 199 + {
65 - { title: 'AI答疑如何使用?', id: 2 }, 200 + title: '如何创建新的计划书?',
66 - { title: '如何修改个人信息?', id: 3 }, 201 + id: 1,
67 - { title: '数据如何同步到云端?', id: 4 }, 202 + content: mockRichText
68 - { title: '忘记密码怎么办?', id: 5 } 203 + },
204 + {
205 + title: 'AI答疑如何使用?',
206 + id: 2,
207 + content: mockRichText
208 + },
209 + {
210 + title: '如何修改个人信息?',
211 + id: 3,
212 + content: mockRichText
213 + },
214 + {
215 + title: '数据如何同步到云端?',
216 + id: 4,
217 + content: mockRichText
218 + },
219 + {
220 + title: '忘记密码怎么办?',
221 + id: 5,
222 + content: mockRichText
223 + }
69 ]) 224 ])
70 225
71 const handleQuestionClick = (item) => { 226 const handleQuestionClick = (item) => {
72 - // Navigate to detail or show answer 227 + currentQuestion.value = item
73 - console.log('Clicked question:', item.title) 228 + showQuestionPopup.value = true
74 - // Example navigation (adjust path as needed)
75 - // go('/pages/help-detail/index', { id: item.id })
76 } 229 }
77 </script> 230 </script>
......