hookehuyr

feat(pages): 实现分类资料列表跳转功能

- 为 onboarding、family-office、signing 三个页面的 item 添加 categoryId
- 点击 item 时跳转到 material-list 页面并传递分类 ID 参数
- material-list 页面使用 useLoad 接收 categoryId 并预留 API 调用接口
- 保持向后兼容,无 categoryId 时显示所有资料

技术实现:
- 使用 useSectionList composable 的自定义点击处理函数
- 统一的 ID 命名规范:{page}-{module}-{feature}
- 完善的日志输出和错误处理

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
...@@ -29,11 +29,13 @@ const FAMILY_OFFICE_SECTIONS = [ ...@@ -29,11 +29,13 @@ const FAMILY_OFFICE_SECTIONS = [
29 title: '家庭成员', 29 title: '家庭成员',
30 items: [ 30 items: [
31 { 31 {
32 + id: 'family-member-list',
32 title: '成员列表', 33 title: '成员列表',
33 subtitle: '管理家庭成员信息', 34 subtitle: '管理家庭成员信息',
34 icon: 'my' 35 icon: 'my'
35 }, 36 },
36 { 37 {
38 + id: 'family-member-add',
37 title: '新增成员', 39 title: '新增成员',
38 subtitle: '添加家庭成员', 40 subtitle: '添加家庭成员',
39 icon: 'edit' 41 icon: 'edit'
...@@ -44,11 +46,13 @@ const FAMILY_OFFICE_SECTIONS = [ ...@@ -44,11 +46,13 @@ const FAMILY_OFFICE_SECTIONS = [
44 title: '健康档案', 46 title: '健康档案',
45 items: [ 47 items: [
46 { 48 {
49 + id: 'family-health-checkup',
47 title: '体检报告', 50 title: '体检报告',
48 subtitle: '查看家庭成员体检记录', 51 subtitle: '查看家庭成员体检记录',
49 icon: 'order' 52 icon: 'order'
50 }, 53 },
51 { 54 {
55 + id: 'family-health-medical',
52 title: '就医记录', 56 title: '就医记录',
53 subtitle: '家庭成员就医历史', 57 subtitle: '家庭成员就医历史',
54 icon: 'clock' 58 icon: 'clock'
...@@ -59,11 +63,13 @@ const FAMILY_OFFICE_SECTIONS = [ ...@@ -59,11 +63,13 @@ const FAMILY_OFFICE_SECTIONS = [
59 title: '资产管理', 63 title: '资产管理',
60 items: [ 64 items: [
61 { 65 {
66 + id: 'family-asset-policy',
62 title: '保单管理', 67 title: '保单管理',
63 subtitle: '家庭保单汇总', 68 subtitle: '家庭保单汇总',
64 icon: 'star' 69 icon: 'star'
65 }, 70 },
66 { 71 {
72 + id: 'family-asset-overview',
67 title: '资产总览', 73 title: '资产总览',
68 subtitle: '家庭资产分布', 74 subtitle: '家庭资产分布',
69 icon: 'find' 75 icon: 'find'
...@@ -74,11 +80,13 @@ const FAMILY_OFFICE_SECTIONS = [ ...@@ -74,11 +80,13 @@ const FAMILY_OFFICE_SECTIONS = [
74 title: '生活服务', 80 title: '生活服务',
75 items: [ 81 items: [
76 { 82 {
83 + id: 'family-service-medical',
77 title: '高端医疗', 84 title: '高端医疗',
78 subtitle: '预约高端医疗服务', 85 subtitle: '预约高端医疗服务',
79 icon: 'service' 86 icon: 'service'
80 }, 87 },
81 { 88 {
89 + id: 'family-service-health',
82 title: '康养服务', 90 title: '康养服务',
83 subtitle: '健康养生服务', 91 subtitle: '健康养生服务',
84 icon: 'playCircleFill' 92 icon: 'playCircleFill'
...@@ -87,8 +95,19 @@ const FAMILY_OFFICE_SECTIONS = [ ...@@ -87,8 +95,19 @@ const FAMILY_OFFICE_SECTIONS = [
87 } 95 }
88 ] 96 ]
89 97
90 -// 使用 useSectionList composable 管理列表数据 98 +/**
91 -const { sections, handleItemClick } = useSectionList(FAMILY_OFFICE_SECTIONS) 99 + * 处理项目点击事件
100 + *
101 + * @description 点击列表项时跳转到资料列表页,并带上分类 ID
102 + * @param {Object} item - 被点击的项目数据
103 + * @param {Function} go - 导航函数
104 + */
105 +const handleItemClickWithNav = (item, go) => {
106 + go('/pages/material-list/index', { categoryId: item.id })
107 +}
108 +
109 +// 使用 useSectionList composable 管理列表数据,传入自定义点击处理
110 +const { sections, handleItemClick } = useSectionList(FAMILY_OFFICE_SECTIONS, handleItemClickWithNav)
92 </script> 111 </script>
93 112
94 <script> 113 <script>
......
...@@ -17,6 +17,19 @@ ...@@ -17,6 +17,19 @@
17 </div> 17 </div>
18 </div> 18 </div>
19 19
20 + <!-- Category Tabs -->
21 + <!-- 根据是否有分类数据决定是否显示 tab -->
22 + <div v-if="categories && categories.length > 0" class="px-[32rpx] mt-[32rpx]">
23 + <div class="flex overflow-x-auto no-scrollbar mb-[40rpx] space-x-[24rpx]">
24 + <div v-for="(category, index) in categories" :key="index"
25 + class="px-[32rpx] py-[16rpx] rounded-full text-[28rpx] whitespace-nowrap transition-colors"
26 + :class="activeCategoryIndex === index ? 'bg-[#2563EB] text-white' : 'bg-[#F3F4F6] text-[#6B7280]'"
27 + @tap="activeCategoryIndex = index">
28 + {{ category.name }}
29 + </div>
30 + </div>
31 + </div>
32 +
20 <!-- Material List --> 33 <!-- Material List -->
21 <div class="px-[32rpx] mt-[32rpx]"> 34 <div class="px-[32rpx] mt-[32rpx]">
22 <div class="flex flex-col gap-[24rpx]"> 35 <div class="flex flex-col gap-[24rpx]">
...@@ -78,6 +91,7 @@ ...@@ -78,6 +91,7 @@
78 91
79 <script setup> 92 <script setup>
80 import { ref } from 'vue' 93 import { ref } from 'vue'
94 +import { useLoad } from '@tarojs/taro'
81 import NavHeader from '@/components/NavHeader.vue' 95 import NavHeader from '@/components/NavHeader.vue'
82 import TabBar from '@/components/TabBar.vue' 96 import TabBar from '@/components/TabBar.vue'
83 import IconFont from '@/components/IconFont.vue' 97 import IconFont from '@/components/IconFont.vue'
...@@ -87,6 +101,7 @@ import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons' ...@@ -87,6 +101,7 @@ import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons'
87 import Taro from '@tarojs/taro' 101 import Taro from '@tarojs/taro'
88 102
89 const searchValue = ref('') 103 const searchValue = ref('')
104 +const categoryId = ref('')
90 105
91 /** 106 /**
92 * 资料列表数据 107 * 资料列表数据
...@@ -197,12 +212,67 @@ const list = ref([ ...@@ -197,12 +212,67 @@ const list = ref([
197 ]) 212 ])
198 213
199 /** 214 /**
215 + * 页面加载时接收参数
216 + *
217 + * @description 使用 Taro 的 useLoad hook 接收路由参数
218 + */
219 +useLoad((options) => {
220 + console.log('[Material List] 页面参数:', options)
221 +
222 + // 接收 categoryId 参数
223 + if (options.categoryId) {
224 + categoryId.value = options.categoryId
225 + console.log('[Material List] 分类 ID:', categoryId.value)
226 +
227 + // 根据 categoryId 加载对应的资料列表
228 + loadMaterialsByCategory(categoryId.value)
229 + } else {
230 + console.log('[Material List] 无分类 ID,显示所有资料')
231 + }
232 +})
233 +
234 +/**
235 + * 根据分类 ID 加载资料列表
236 + *
237 + * @description 根据 categoryId 从 API 获取对应的资料列表
238 + * @param {string} categoryId - 分类 ID
239 + */
240 +const loadMaterialsByCategory = async (id) => {
241 + try {
242 + Taro.showLoading({ title: '加载中...', mask: true })
243 +
244 + // TODO: 调用真实的 API 接口
245 + // const res = await getMaterialsByCategoryAPI({ categoryId: id })
246 + // if (res.code === 1) {
247 + // list.value = res.data
248 + // }
249 +
250 + // 模拟 API 调用延迟
251 + await new Promise(resolve => setTimeout(resolve, 500))
252 +
253 + console.log(`[Material List] 已加载分类 "${id}" 的资料列表`)
254 +
255 + Taro.hideLoading()
256 + } catch (error) {
257 + console.error('[Material List] 加载资料列表失败:', error)
258 + Taro.showToast({
259 + title: '加载失败,请重试',
260 + icon: 'none'
261 + })
262 + } finally {
263 + Taro.hideLoading()
264 + }
265 +}
266 +
267 +/**
200 * 搜索处理函数 268 * 搜索处理函数
201 * 269 *
202 * @description 处理用户搜索操作 270 * @description 处理用户搜索操作
203 */ 271 */
204 const onSearch = () => { 272 const onSearch = () => {
205 console.log('Searching for:', searchValue.value) 273 console.log('Searching for:', searchValue.value)
274 + console.log('当前分类:', categoryId.value)
275 + // TODO: 根据 categoryId 和 searchValue 进行搜索
206 } 276 }
207 277
208 /** 278 /**
......
...@@ -29,16 +29,19 @@ const ONBOARDING_SECTIONS = [ ...@@ -29,16 +29,19 @@ const ONBOARDING_SECTIONS = [
29 title: '入职前', 29 title: '入职前',
30 items: [ 30 items: [
31 { 31 {
32 + id: 'onboarding-exam',
32 icon: '', 33 icon: '',
33 title: '考试报名', 34 title: '考试报名',
34 subtitle: '报名参加代理人资格考试' 35 subtitle: '报名参加代理人资格考试'
35 }, 36 },
36 { 37 {
38 + id: 'onboarding-interview',
37 icon: '', 39 icon: '',
38 title: '面试结果查询', 40 title: '面试结果查询',
39 subtitle: '查看面试状态和结果' 41 subtitle: '查看面试状态和结果'
40 }, 42 },
41 { 43 {
44 + id: 'onboarding-materials',
42 icon: '', 45 icon: '',
43 title: '入职材料提交', 46 title: '入职材料提交',
44 subtitle: '上传入职所需证件和资料' 47 subtitle: '上传入职所需证件和资料'
...@@ -49,16 +52,19 @@ const ONBOARDING_SECTIONS = [ ...@@ -49,16 +52,19 @@ const ONBOARDING_SECTIONS = [
49 title: '入职中', 52 title: '入职中',
50 items: [ 53 items: [
51 { 54 {
55 + id: 'onboarding-timeline',
52 icon: '', 56 icon: '',
53 title: '各个进度时间线表格', 57 title: '各个进度时间线表格',
54 subtitle: '查看入职流程关键节点' 58 subtitle: '查看入职流程关键节点'
55 }, 59 },
56 { 60 {
61 + id: 'onboarding-tasks',
57 icon: '', 62 icon: '',
58 title: '待办事项清单', 63 title: '待办事项清单',
59 subtitle: '你需要完成的任务列表' 64 subtitle: '你需要完成的任务列表'
60 }, 65 },
61 { 66 {
67 + id: 'onboarding-contract',
62 icon: '', 68 icon: '',
63 title: '签署合同', 69 title: '签署合同',
64 subtitle: '电子合同在线签署' 70 subtitle: '电子合同在线签署'
...@@ -69,16 +75,19 @@ const ONBOARDING_SECTIONS = [ ...@@ -69,16 +75,19 @@ const ONBOARDING_SECTIONS = [
69 title: '入职后', 75 title: '入职后',
70 items: [ 76 items: [
71 { 77 {
78 + id: 'onboarding-training',
72 icon: '', 79 icon: '',
73 title: '新人培训', 80 title: '新人培训',
74 subtitle: '参加新人岗前培训课程' 81 subtitle: '参加新人岗前培训课程'
75 }, 82 },
76 { 83 {
84 + id: 'onboarding-target',
77 icon: '', 85 icon: '',
78 title: '业绩目标设定', 86 title: '业绩目标设定',
79 subtitle: '制定首月业绩目标' 87 subtitle: '制定首月业绩目标'
80 }, 88 },
81 { 89 {
90 + id: 'onboarding-team',
82 icon: '', 91 icon: '',
83 title: '团队介绍', 92 title: '团队介绍',
84 subtitle: '了解你的团队和主管' 93 subtitle: '了解你的团队和主管'
...@@ -87,8 +96,19 @@ const ONBOARDING_SECTIONS = [ ...@@ -87,8 +96,19 @@ const ONBOARDING_SECTIONS = [
87 } 96 }
88 ] 97 ]
89 98
90 -// 使用 useSectionList composable 管理列表数据 99 +/**
91 -const { sections, handleItemClick } = useSectionList(ONBOARDING_SECTIONS) 100 + * 处理项目点击事件
101 + *
102 + * @description 点击列表项时跳转到资料列表页,并带上分类 ID
103 + * @param {Object} item - 被点击的项目数据
104 + * @param {Function} go - 导航函数
105 + */
106 +const handleItemClickWithNav = (item, go) => {
107 + go('/pages/material-list/index', { categoryId: item.id })
108 +}
109 +
110 +// 使用 useSectionList composable 管理列表数据,传入自定义点击处理
111 +const { sections, handleItemClick } = useSectionList(ONBOARDING_SECTIONS, handleItemClickWithNav)
92 </script> 112 </script>
93 113
94 <script> 114 <script>
......
...@@ -29,11 +29,13 @@ const SIGNING_SECTIONS = [ ...@@ -29,11 +29,13 @@ const SIGNING_SECTIONS = [
29 title: '培训板块', 29 title: '培训板块',
30 items: [ 30 items: [
31 { 31 {
32 + id: 'signing-training-company',
32 icon: 'shop', 33 icon: 'shop',
33 title: '公司介绍', 34 title: '公司介绍',
34 subtitle: '企业背景及发展历程' 35 subtitle: '企业背景及发展历程'
35 }, 36 },
36 { 37 {
38 + id: 'signing-training-product',
37 icon: 'category', 39 icon: 'category',
38 title: '产品介绍及更新', 40 title: '产品介绍及更新',
39 subtitle: '最新产品资料库' 41 subtitle: '最新产品资料库'
...@@ -44,11 +46,13 @@ const SIGNING_SECTIONS = [ ...@@ -44,11 +46,13 @@ const SIGNING_SECTIONS = [
44 title: '签单前', 46 title: '签单前',
45 items: [ 47 items: [
46 { 48 {
49 + id: 'signing-pre-underwriting',
47 icon: 'check', 50 icon: 'check',
48 title: '预核保', 51 title: '预核保',
49 subtitle: '核保流程指引' 52 subtitle: '核保流程指引'
50 }, 53 },
51 { 54 {
55 + id: 'signing-pre-plan',
52 icon: 'edit', 56 icon: 'edit',
53 title: '做计划书', 57 title: '做计划书',
54 subtitle: '方案设计工具' 58 subtitle: '方案设计工具'
...@@ -59,16 +63,19 @@ const SIGNING_SECTIONS = [ ...@@ -59,16 +63,19 @@ const SIGNING_SECTIONS = [
59 title: '签单中', 63 title: '签单中',
60 items: [ 64 items: [
61 { 65 {
66 + id: 'signing-process-info',
62 icon: 'checklist', 67 icon: 'checklist',
63 title: '信息收集及健康告知模板', 68 title: '信息收集及健康告知模板',
64 subtitle: '标准表格及注意事项' 69 subtitle: '标准表格及注意事项'
65 }, 70 },
66 { 71 {
72 + id: 'signing-process-payment',
67 icon: 'cart', 73 icon: 'cart',
68 title: '缴费方式银行开户', 74 title: '缴费方式银行开户',
69 subtitle: '支付渠道办理指南' 75 subtitle: '支付渠道办理指南'
70 }, 76 },
71 { 77 {
78 + id: 'signing-process-checkup',
72 icon: 'people', 79 icon: 'people',
73 title: '体检经验', 80 title: '体检经验',
74 subtitle: '体检流程及常见问题' 81 subtitle: '体检流程及常见问题'
...@@ -79,16 +86,19 @@ const SIGNING_SECTIONS = [ ...@@ -79,16 +86,19 @@ const SIGNING_SECTIONS = [
79 title: '签单后', 86 title: '签单后',
80 items: [ 87 items: [
81 { 88 {
89 + id: 'signing-post-endorsement',
82 icon: 'order', 90 icon: 'order',
83 title: '批单跟进', 91 title: '批单跟进',
84 subtitle: '保单变更处理流程' 92 subtitle: '保单变更处理流程'
85 }, 93 },
86 { 94 {
95 + id: 'signing-post-pending',
87 icon: 'clock', 96 icon: 'clock',
88 title: '核保/pending', 97 title: '核保/pending',
89 subtitle: '核保进度查询' 98 subtitle: '核保进度查询'
90 }, 99 },
91 { 100 {
101 + id: 'signing-post-renewal',
92 icon: 'refresh', 102 icon: 'refresh',
93 title: '续保', 103 title: '续保',
94 subtitle: '续期服务指引' 104 subtitle: '续期服务指引'
...@@ -99,6 +109,7 @@ const SIGNING_SECTIONS = [ ...@@ -99,6 +109,7 @@ const SIGNING_SECTIONS = [
99 title: '售后', 109 title: '售后',
100 items: [ 110 items: [
101 { 111 {
112 + id: 'signing-aftercare-doctor',
102 icon: 'location', 113 icon: 'location',
103 title: '香港医生资源', 114 title: '香港医生资源',
104 subtitle: '专业医疗机构名录' 115 subtitle: '专业医疗机构名录'
...@@ -107,8 +118,19 @@ const SIGNING_SECTIONS = [ ...@@ -107,8 +118,19 @@ const SIGNING_SECTIONS = [
107 } 118 }
108 ] 119 ]
109 120
110 -// 使用 useSectionList composable 管理列表数据 121 +/**
111 -const { sections, handleItemClick } = useSectionList(SIGNING_SECTIONS) 122 + * 处理项目点击事件
123 + *
124 + * @description 点击列表项时跳转到资料列表页,并带上分类 ID
125 + * @param {Object} item - 被点击的项目数据
126 + * @param {Function} go - 导航函数
127 + */
128 +const handleItemClickWithNav = (item, go) => {
129 + go('/pages/material-list/index', { categoryId: item.id })
130 +}
131 +
132 +// 使用 useSectionList composable 管理列表数据,传入自定义点击处理
133 +const { sections, handleItemClick } = useSectionList(SIGNING_SECTIONS, handleItemClickWithNav)
112 </script> 134 </script>
113 135
114 <script> 136 <script>
......