# 小程序跨页传值规范性深度调研(P1-3 + P1-4 触发) > 日期: 2026-05-04 > 触发: Neo 在 04b P1-3 + P1-4 反馈"同意初步判断,但谨慎起见,要从页面和产品设计出发,对业务进行理解的情况下,深入调研这个问题(尤其整个 APP 页面与角色的传值规范性方面)" > 范围: 小程序 21 页全部跨页跳转 + 角色权限相关传值 + 公共组件 ai-float-button / board-tab-bar > 调研口径: **只读不改**, 单文档产出 > 状态机考量: 仅 5 类跳转 API: `wx.navigateTo` / `wx.redirectTo` / `wx.switchTab` / `wx.reLaunch` / `wx.navigateBack` --- ## 一、跳转矩阵全表 下表覆盖小程序 21 页全部 `wx.navigateTo` / `wx.redirectTo` / `wx.switchTab` / `wx.reLaunch` 调用(`wx.navigateBack` 仅在"目标页期望"列出现)。 代号约定: - `id` 默认指资源主键(taskId / customerId / coachId / historyId, 视目标页而定) - `--` 表示无参数(空 URL) - onLoad 期望字段以代码实际读取为准 | # | 源页 | 跳转方法 | 目标页 | 参数 key:value | 目标页 onLoad 期望字段 | 是否一致 | 问题类型 | | --- | --- | --- | --- | --- | --- | --- | --- | | 1 | login | reLaunch | task-list / board-finance / my-profile (动态首页) | -- | -- | 一致 | -- | | 2 | login | reLaunch | reviewing | -- | -- | 一致 | -- | | 3 | login | reLaunch | apply | -- | -- | 一致 | -- | | 4 | login | reLaunch | no-permission | -- | -- | 一致 | -- | | 5 | apply | reLaunch | login (兜底) | -- | -- | 一致 | -- | | 6 | apply | reLaunch | reviewing | -- | -- | 一致 | -- | | 7 | apply | reLaunch | no-permission | -- | -- | 一致 | -- | | 8 | apply | reLaunch | <动态首页 by getRoleHome> | -- | -- | 一致 | -- | | 9 | apply | navigateBack(fail→reLaunch login) | 上一页 / login | -- | -- | 一致 | -- | | 10 | reviewing | reLaunch | <动态首页> / no-permission / apply / login | siteCode + role + phone + employeeNumber (cancel 重申请) | apply.onLoad 解 4 字段 | 一致 | -- | | 11 | no-permission | reLaunch | login | -- | -- | 一致 | -- | | 12 | no-permission | reLaunch | <动态首页> | -- | -- | 一致 | -- | | 13 | no-permission | reLaunch | apply | siteCode + role + phone + employeeNumber | apply.onLoad 同上 | 一致 | -- | | 14 | no-permission | reLaunch | reviewing | -- | -- | 一致 | -- | | 15 | task-list | navigateTo | task-detail | id= | id 或 memberId | 一致 | -- | | 16 | task-list | navigateTo | performance | -- | scrollToBottom 可选 | 一致 | -- | | 17 | task-list | navigateTo | performance | scrollToBottom=1 | scrollToBottom 解析 '1' | 一致 | -- | | 18 | task-list | navigateTo | chat | taskId= | taskId 分支 | 一致 | -- | | 19 | my-profile | navigateTo (utils/router.navigateTo) | chat-history / performance / notes | -- | -- | 一致 | -- | | 20 | my-profile | reLaunch | login | -- | -- | 一致 | -- | | 21 | task-detail | navigateBack | 上一页 | -- | -- | 一致 | -- | | 22 | task-detail | navigateTo | chat | taskId= | taskId 分支(contextType=task) | 一致 | -- | | 23 | task-detail | navigateTo | customer-service-records | customerId= | customerId 或 id | **不一致(B)** | P1-3 | | 24 | performance | navigateBack(fail→switchTab task-list) | 上一页 / 任务 tab | -- | -- | 一致 | -- | | 25 | performance | navigateTo | performance-records | -- | -- | 一致 | -- | | 26 | performance | navigateTo | task-detail | memberId= | id 或 memberId | 一致(2026-03-25 修复) | 历史 P1-4 | | 27 | performance | navigateTo | task-detail | id= 或 memberId= | id 或 memberId | 一致 | -- | | 28 | performance | navigateTo | performance-records | -- | -- | 一致 | -- | | 29 | performance-records | navigateBack(fail→switchTab) | 上一页 | -- | -- | 一致 | -- | | 30 | performance-records | navigateTo | task-detail | memberId= | id 或 memberId | 一致 | -- | | 31 | board-finance | switchTab/redirectTo | board-finance / board-customer / board-coach | -- | -- | 一致 | -- | | 32 | board-customer | switchTab/redirectTo | 同上 | -- | -- | 一致 | -- | | 33 | board-customer | navigateTo | customer-detail | id= | id 或 customerId | 一致 | -- | | 34 | board-coach | switchTab/redirectTo | 同上 | -- | -- | 一致 | -- | | 35 | board-coach | navigateTo | coach-detail | id= | id (仅) | 一致 | -- | | 36 | customer-detail | navigateTo | customer-records | customerId= | customerId 或 id | 一致 | **D(命名/语义混乱)** P1-10 | | 37 | customer-detail | navigateTo | chat | customerId= | customerId 分支 | 一致 | -- | | 38 | customer-records | -- | (无下游跳转) | -- | -- | -- | -- | | 39 | customer-service-records | navigateBack | 上一页 | -- | -- | 一致 | -- | | 40 | coach-detail | navigateTo | customer-detail | id= (3 个不同入口: 最近服务客户/收藏客户/常客) | id 或 customerId | 一致 | -- | | 41 | coach-detail | navigateTo | coach-service-records | coachId= | coachId(必填,缺失则退回) | 一致 | -- | | 42 | coach-detail | navigateTo | chat | coachId= | coachId 分支 | 一致 | -- | | 43 | coach-service-records | navigateBack(fail→switchTab board-finance) | 上一页 / 看板 | -- | -- | 一致 | -- | | 44 | coach-service-records | navigateTo | customer-detail | id= | id 或 customerId | 一致(memberId<=0 拦截) | 关联 P1-12 | | 45 | chat | navigateBack | 上一页 | -- | -- | 一致 | -- | | 46 | chat | navigateTo | <动态 link>(消息内可点链接) | -- | -- | 取决于 link 内容 | **D(无校验)** | | 47 | chat-history | navigateBack | 上一页 | -- | -- | 一致 | -- | | 48 | chat-history | navigateTo | chat | historyId= | historyId 分支 | 一致 | -- | | 49 | dev-tools | reLaunch | <任意页 by dataset.url> | (跟随 url 拼接) | -- | 一致 | -- | | 50 | ai-float-button(组件,被 6 页引用) | navigateTo | chat | sourcePage / pageFilters / customerId(可选) | sourcePage 分支(看板类) | 一致 | -- | | 51 | board-tab-bar(组件) | switchTab | task-list / board-finance / my-profile | -- | -- | 一致 | -- | | 52 | dev-fab(组件) | navigateTo | dev-tools | -- | -- | 一致 | -- | | 53 | notes | navigateBack | 上一页 | -- | -- | 一致 | -- | 合计: 53 条跳转(合并重复入口后), 其中 **2 条不一致 / 命名混乱**(行 23、36), 1 条无校验(行 46)。 --- ## 二、规范性问题清单(按严重度) ### P0 级(语义错位,功能不通) #### 问题 P0-1: task-detail → customer-service-records 传 detail.id 当 customerId 用 (即 P1-3 后半段) - 源页: `pages/task-detail/task-detail.ts` L437-441 - 目标页: `pages/customer-service-records/customer-service-records.ts` - 现状: ```ts const customerId = (this.data.detail as any)?.customerId || this.data.detail?.id || '' wx.navigateTo({ url: `/pages/customer-service-records/customer-service-records?customerId=${customerId}` }) ``` 当 TASK-2 响应未返回 `customerId` 字段时, fallback 拿 `detail.id`(taskId), 把 taskId 当作 customerId 拼到 URL. - 目标页 onLoad: `const id = options?.customerId || options?.id || ''`, 拿到的是 taskId, 后续按 taskId 调 `fetchCustomerServiceRecords` 必然返回空或错乱. - 期望: TASK-2 响应里加 `customer_id` / `member_id` 字段, 前端不再用 fallback. - 修复方案: - 后端: `GET /api/xcx/tasks/{id}` 响应增加 `customerId`(JOIN dim_member); - 前端: 删除 `|| this.data.detail?.id` 的 fallback, 拿不到 customerId 时显式 toast"客户信息缺失". #### 问题 P0-2: chat 多入口路由当前实现一致性不足 (P1-11) - 源页: 3 入口 - `task-detail` → `chat?taskId=`(已正确, 走 contextType=task) - `customer-detail` → `chat?customerId=`(已正确, contextType=customer) - `coach-detail` → `chat?coachId=`(已正确, contextType=coach) - `chat-history` → `chat?historyId=`(走历史 chatId) - `task-list 上下文菜单"问问助手"` → `chat?taskId=`(已正确) - `ai-float-button` → `chat?sourcePage=...&pageFilters=...&customerId=...`(看板类入口) - 目标页 onLoad: 已经根据 `historyId / taskId / customerId / coachId / sourcePage / 无参` 6 分支处理 - 现状评估: 与 04b P1-11 描述存在偏差 — chat.ts L214-263 已经做了 6 分支, P1-11 描述的"loadMessages 仅用 customerId"已不适用(代码已演进) - 残留风险: - 后端接口侧: `fetchChatMessagesByContext(contextType, contextId)` 是否后端已支持 4 种 contextType(task / customer / coach / general / board-*) 待验证 - `general` / `board-*` 几个 contextType 的 chatId 派生策略是否后端已实现待与后端核对 - 修复方案: 与后端核对 `GET /api/xcx/chat/messages?contextType=...&contextId=...` 是否已上线全部 contextType 路由 - 建议判定: **降为 P1**(前端代码已修, 后端契约待补) ### P1 级(命名/语义混乱, 功能可走通但易踩坑) #### 问题 P1-1: customer-detail "消费记录"卡片绑定的方法名是 onViewServiceRecords 但实际跳消费记录页 (P1-10 的根因) - 源页: `customer-detail.wxml` L177-181 ```xml 消费记录 ``` - 处理: `onViewServiceRecords` 实际跳 `customer-records`(消费视角), 名字写成"Service"完全是误导. - 影响: 看代码读不出真实跳转目标; 改 bug 时容易跳错页面. - 期望: 方法名改为 `onViewConsumptionRecords` / `goConsumptionRecords`, 与文案"消费记录"一致. - 修复方案: 简单重命名(WXML + TS), 不影响功能. - 与 P1-10 关系: 04b P1-10 询问"查看消费记录跳哪个目标页", 答案是 **customer-records**(消费记录页, 2026-03-29 新建), 现状已正确, 但 **方法命名误导**. #### 问题 P1-2: task-detail.onLoad fallback 优先级模糊 - 现状: `onLoad({ id?, memberId? })` 同时支持两种语义, 但是当 url 里 **同时** 出现 `?id=xxx&memberId=yyy` 时 优先使用 id 走 loadData, 不走 memberId. - 入口分布: 5 个入口都只传一个键, 故无实际冲突, 但接口边界模糊(若未来其他页传两个键, 行为不直观). - 期望: 显式声明"id 优先, 仅 id 缺失时才用 memberId", 在文档里写清楚. #### 问题 P1-3: 字段命名风格不统一 (camelCase vs lowercase) - 全局清单(纯 URL key, 不含值): - `id`(单字母 / 没有所属命名空间) → 使用面: 大量(task-list, board-customer, board-coach, coach-service-records, customer-records, customer-service-records 等都用) - `customerId` / `coachId` / `taskId` / `historyId` / `memberId` / `siteCode` / `employeeNumber` / `sourcePage` / `pageFilters` / `scrollToBottom` / `phone` / `role` / `timeDimension` / `areaFilter` / `dimension` / `typeFilter` / `projectFilter` - 风格: 以 camelCase 为主. 问题: - **`id` 缺乏所属语义**: 同一个 `id` 在 task-list 是 taskId, 在 board-customer 是 customerId, 在 board-coach 是 coachId. 排查时容易看 url 看错. - **混用 `id` 与 `customerId`**: customer-records / customer-service-records / customer-detail 三页的 onLoad 都做了 `options?.customerId || options?.id` 兼容, 这种"二选一"兼容是历史污渍. - 期望: 统一约定"目标页接收明确语义键(taskId / customerId / coachId), 不再接受裸 `id`"; 兼容期保留 `id || customerId` 的回退, 但所有 navigateTo 调用方迁移到明确键. #### 问题 P1-4: 字段类型(string vs number)隐式不一致 - url 参数本质是 string, 但有些目标页直接 `Number()` 转换(如 coach-service-records.onLoad), 有些直接用 string(如 customer-records 把 id 写入 setData 用作 string). - 现状: - coach-service-records: `Number(options?.coachId)` 后判断 `Finite && >0`, 否则退回(已正确) - customer-detail / customer-records / customer-service-records / coach-detail: 全部用 string, 后端调用时再做转换 - task-detail.loadByMember: `String(detail.id)` 显式转换 - 期望: URL 参数全部按 string 处理, 调后端时转换由 service 层做; 业务侧不要混用. ### P2 级(兜底缺失 / 体验问题) #### 问题 P2-1: 多数目标页缺少必填字段缺失时的 toast / fallback - 现状: 仅 `coach-service-records` 在 coachId 缺失时有 `wx.showToast('缺少助教标识') + setTimeout navigateBack` 的兜底. - 其他页(customer-detail / customer-records / customer-service-records / customer-detail / coach-detail / task-detail / chat)在拿不到必填字段时, 大多数走"setData empty / pageState='empty'"或者直接调后端拿空响应, **不会 toast 提醒**. - 期望: 关键详情页(customer-detail / coach-detail / task-detail / customer-service-records / coach-service-records / customer-records / chat) 全部加必填字段缺失 toast. #### 问题 P2-2: chat 内嵌消息 link 跳转无安全校验 - chat.ts L552-556: `wx.navigateTo({ url: link })` — link 来自 AI 回复消息中的可点链接, 无白名单校验. - 风险: - link 若指向 tabBar 页面会失败(navigateTo 不能去 tab 页) - link 包含恶意构造参数时无防护 - 期望: 增加白名单(只允许 `/pages/...` 前缀 + 已知页面路径), navigateTo 失败时降级 switchTab. #### 问题 P2-3: dev-tools.ts 的 reLaunch 跳"任意页"无白名单校验 - dev-tools.ts L156-158: `const url = "/" + e.currentTarget.dataset.url; wx.reLaunch({ url })` — 来自 dataset, 调试页可接受, 但生产编译要确保 dev-tools 入口被关闭(已有 `wx:if="{{false}}"` 隐藏 dev-fab). #### 问题 P2-4: customer-detail 跳 customer-records 时 banner 字段重复加载 - customer-detail 已有完整客户信息, customer-records.onLoad 只接 customerId, 然后再调 `fetchCustomerConsumptionRecords` 重新拉 banner. - 后果: 多一次接口往返, 但跳转后用户在 customer-records 看到的 banner 数据是新 fetch 的, 与 customer-detail 一致性不强. - 期望: 后端响应里 banner 字段(name/avatar/storage)由 customer-records 自己拉(已是现状), 不需要前端透传; 若考虑性能, 可走 globalData 暂存上一页客户对象, 但这是优化项. ### 角色相关传值问题清单(独立维度) #### 问题 R-1: 跳转链路中没有携带角色信息 - 现状: 所有 navigateTo / redirectTo 调用 **都不带 role 参数**. 目标页通过 `checkPageAccess(pageRoute)` 在 onShow 调 `auth-guard` 模块从 globalData(后端 fetchMe 返回)读取角色和权限码. - 这是合理设计: URL 不应携带角色, 角色应来自后端权威源. - 但意味着: 如果后端 permissions 与页面预期角色不匹配(例如散客访问助教页), 由 auth-guard 拦截并跳 no-permission, 不靠 URL 角色. #### 问题 R-2: site_id(门店 ID)切换不影响传值 - site_id 不出现在任何 URL 参数里, 后端通过 JWT + `app.current_site_id` 会话变量过滤. 这是 RLS 双 schema 设计, 跨店切换由后端处理, 前端 URL 不感知, **正确无问题**. #### 问题 R-3: 散客模式(P1-12)的判断分散 - 当前 `coach-service-records` 用 `Number(options?.coachId) > 0` 判合法, `performance.onCustomerTap` 用 `mid <= 0` 判散客拦截. - 散客约定不统一(NULL / 0 / -1 / <=0 都有兼容代码), 这是 P1-12 的范畴, 与传值规范同源. - 期望: 散客统一约定 + 跳转拦截统一抽到 utils 函数(如 `isScattered(memberId)`). --- ## 三、传值规范建议 ### 3.1 字段命名规范 强制约定: - URL 参数键统一使用 **camelCase**(已是事实标准, 文档化) - **禁止使用裸 `id`**, 必须带语义前缀: `taskId` / `customerId` / `coachId` / `historyId` / `memberId` / `noteId` / `recordId` - 兼容期 `id || customerId` 的双键兼容保留 6 个月, 之后强制只接受语义键 ### 3.2 参数 key 命名约定(全集 + 语义) | key | 含义 | 类型 | 来源 / 出现页 | | --- | --- | --- | --- | | `taskId` | 任务 id | string(数字字符串) | task-list / chat / task-detail / performance | | `customerId` | 客户(会员) id, 等价 memberId | string | task-detail / customer-detail / customer-records / customer-service-records / chat | | `coachId` | 助教 id | string | coach-detail / coach-service-records / chat | | `historyId` | 对话历史 chatId | string | chat-history / chat | | `memberId` | 会员 id (与 customerId 同义) | string(数字字符串) | performance / performance-records / task-detail / coach-service-records | | `siteCode` | 门店编码(申请预填) | string(URI 编码) | reviewing → apply / no-permission → apply | | `employeeNumber` | 员工号(申请预填) | string(URI 编码) | 同上 | | `phone` | 手机号(申请预填) | string(URI 编码) | 同上 | | `role` | 角色(申请预填) | string(URI 编码) | 同上 | | `sourcePage` | AI 上下文来源页 | string(枚举) | ai-float-button → chat | | `pageFilters` | AI 看板筛选参数集 | string(URI + JSON) | ai-float-button → chat | | `scrollToBottom` | 业绩页滚到底部标记 | string('1' / 缺省) | task-list → performance | | `timeDimension` 等单键过滤 | 旧入口兼容 | string | ai-float-button → chat(回退路径) | **统一约定**: - `customerId` 与 `memberId` **同义**(后端 dim_member.id), 但小程序前端两套用法都存在. 期望: 跨页 URL 统一 `customerId`, 内部页面 data 里可以叫 `memberId`(看后端字段名). 迁移历史 url 期 `memberId` 兼容期 6 个月, 之后只接 `customerId`. ### 3.3 目标页 onLoad 必填字段校验模式 推荐模板(以 coach-service-records 为标杆): ```ts onLoad(options: Record) { const requiredId = Number(options?.coachId) const validId = Number.isFinite(requiredId) && requiredId > 0 ? requiredId : 0 if (validId === 0) { wx.showToast({ title: '缺少助教标识', icon: 'none' }) setTimeout(() => wx.navigateBack({ fail: () => wx.switchTab({ url: '/pages/board-finance/board-finance' }) }), 1000) return } this.setData({ coachId: validId }) this.loadData(validId) } ``` **所有详情页应遵循这个模板**: 1. 把 `options?.` 提取出来做类型/合法性校验 2. 缺失时明确 toast(中文文案 + icon='none') 3. setTimeout 后 navigateBack(并提供 fail 兜底, 防止从分享链接首页直入) 4. 合法时再 setData + 触发数据加载 ### 3.4 跨角色 / 跨店传值约定 - **角色**: 不通过 URL 携带, 由 auth-guard 从 globalData / fetchMe 读取 - **门店**: 不通过 URL 携带, 由 JWT + 后端 RLS 处理 - **散客判断**: 在跳转源头拦截(`memberId <= 0` 一律不跳, toast"未知客户不提供查看详情"), 等待 P1-12 决策后将判断函数集中到 `utils/customer.ts`(待新建) --- ## 四、修复方案分组 ### 必修(P0): 后端补字段 + 前端去 fallback | 项 | 模块 | 改动 | 工作量 | | --- | --- | --- | --- | | F1 | 后端 TASK-2 | `GET /api/xcx/tasks/{id}` 响应增加 `customerId`(JOIN dim_member 由 task.member_id 派生) | 小 | | F2 | 前端 task-detail | 删除 `customerId = detail?.customerId || detail?.id` 的 fallback, 缺失时显式 toast | 小 | | F3 | 后端 chat by-context | 验证 `GET /api/xcx/chat/messages?contextType=task/customer/coach/general/board-*&contextId=` 已支持全部 contextType | 中 | ### 应修(P1): 字段命名/类型统一 + 命名重构 | 项 | 模块 | 改动 | 工作量 | | --- | --- | --- | --- | | F4 | customer-detail.ts + customer-detail.wxml | `onViewServiceRecords` 重命名为 `onViewConsumptionRecords`, WXML bindtap 同步 | 极小 | | F5 | board-customer / board-coach | 跳 customer-detail / coach-detail 时, 把 `?id=` 改为 `?customerId=` / `?coachId=`(语义化), 目标页保留兼容期 | 小 | | F6 | task-list | 跳 task-detail 时, `?id=` 改为 `?taskId=`(目标页兼容期保留 id) | 小 | | F7 | coach-service-records | 跳 customer-detail 时, `?id=${memberId}` 改为 `?customerId=${memberId}` | 极小 | | F8 | docs(SPEC) | 制定"小程序跨页传值规范"SPEC, 见 §五.建议 | 中 | ### 可修(P2): 兜底补全 + 安全加固 | 项 | 模块 | 改动 | 工作量 | | --- | --- | --- | --- | | F9 | customer-detail / coach-detail / task-detail / customer-records / customer-service-records / coach-service-records / chat | 必填字段缺失统一加 toast + 退回上一页 | 中 | | F10 | chat 消息 link 跳转 | 增加白名单(`/pages/` 前缀 + 已知页面集), 失败降级 switchTab | 小 | | F11 | utils/customer.ts | 新建 `isScattered(memberId)` 函数, 统一散客判断, 等 P1-12 决策后填实现 | 小 | ### 已确认无需修(误报或已修) - **performance → task-detail 传 customerName 而非 task_id (P1-4)**: 已于 2026-03-25 修复, 现 `onCustomerTap` 传 `memberId`, `onRecordTap` 优先传 `taskId` fallback `memberId`. **04b P1-4 描述已过时, 应在 04b 反馈中标注"已修复"**. - **chat.loadMessages 仅用 customerId (P1-11)**: 已于多次迭代修复, 现 chat.onLoad 走 6 分支(historyId / taskId / customerId / coachId / sourcePage / 无参), **04b P1-11 描述已过时**, 仅后端契约待核对. --- ## 五、给 Neo 的决策清单 ### 决策 D1: 是否同意"必修"清单全部进 Wave 1-3? **子项**: - D1a: F1 + F2(后端 TASK-2 补 customerId, 前端去 fallback) — 是否进 Wave 1? - D1b: F3(后端 chat by-context 全 contextType 验证) — 是否单独立项核对后端实现? ### 决策 D2: 是否同意"应修"清单的命名重构? **子项**: - D2a: F4(customer-detail 方法名重命名) — 极小工作量, 建议直接合并到 P0 修复 PR - D2b: F5 + F6 + F7(URL 参数从裸 `id` 迁移到语义键) — 涉及 4 页, 建议在 Wave 2 单独立项, 跨页协调 - D2c: F8(SPEC 化) — 是否新建 `docs/miniprogram-dev/spec/cross-page-params-spec.md`? ### 决策 D3: 是否同意"可修"清单的优先级排序? **子项**: - D3a: F9(必填字段 toast 兜底) — 7 个页面, 中等工作量, 体验提升明显 - D3b: F10(chat link 白名单) — 安全加固, 轻量 - D3c: F11(散客判断集中) — 等 P1-12 决策后再做 ### 决策 D4: P1-4 与 P1-11 在 04b 文档中的状态更新 - 是否同意将 P1-4 标注"已修复(2026-03-25), 仅文档过时"? - 是否同意将 P1-11 标注"前端已修(6 分支), 后端契约待核对"? ### 决策 D5: 是否制定独立 SPEC 建议新建 `docs/miniprogram-dev/spec/cross-page-params-spec.md`, 内容包含: - §3.1-3.4 的命名规范、key 全集、onLoad 模板、跨角色约定 - 历史兼容期(双键)的退役时间表 - 测试矩阵(每个跳转的合法/缺失/类型错路径) --- ## 六、调研附录 ### 6.1 调研覆盖度 - 21 页 100% 覆盖(login / apply / reviewing / no-permission / task-list / board-finance / my-profile / task-detail / notes / performance / performance-records / board-customer / board-coach / customer-detail / customer-service-records / customer-records / coach-detail / coach-service-records / chat / chat-history / dev-tools) - 公共组件 ai-float-button / board-tab-bar / dev-fab 100% 覆盖 - utils/router.ts / utils/auth-guard.ts(getRoleHome / checkPageAccess) 已查 - 共抓取 53 条跳转(去重前约 70 条), 含组件触发跳转 ### 6.2 调研口径限制 - 仅调研代码现状, 未跑实际跳转流程验证 - 未深入后端 API 契约 — F3(chat by-context) 待与后端核对 - 未涉及 H5 原型 / demo-miniprogram(MOCK 标杆禁改) — 设计参考另议 ### 6.3 与 04b 已知问题对照 | 04b 问题 | 调研结论 | 后续动作 | | --- | --- | --- | | P1-3 (task-detail → chat / customer-service-records 传 detail.id) | chat 路径已修, customer-service-records 路径仍是 fallback bug | F1+F2 必修 | | P1-4 (performance → task-detail 传 customerName) | 已于 2026-03-25 修, 04b 描述过时 | 仅更新 04b 状态 | | P1-10 (customer-detail "查看消费记录"跳哪) | 跳 customer-records(消费记录页, 现状正确), 但方法名 onViewServiceRecords 误导 | F4 重命名 | | P1-11 (chat 多入口 / loadMessages 仅用 customerId) | 前端已 6 分支, 后端契约待核 | F3 待核对 | | P1-12 (散客 memberId 取值约定) | 与 R-3 / F11 同源 | 等 Neo 决策 + 抽函数 | --- > 本调研结论与 Neo 反馈的"初步判断不变"一致: **同意必修后端补 task_id / customer_id 字段 + 前端改跳转参数**, 且额外发现 P1-1(命名误导)、P1-3(裸 id 不规范)等若干非 P1-3/P1-4 问题, 建议一并制定 SPEC 系统化解决.