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>
Showing
4 changed files
with
137 additions
and
6 deletions
| ... | @@ -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> | ... | ... |
-
Please register or login to post a comment