Răsfoiți Sursa

docs(signature): 手签名横屏适配任务书+需求变更(R1高度未重算/R2 rpx横屏放大/R3 rect未刷新)

Agnes Agent 4 zile în urmă
părinte
comite
a7edf56985

+ 85 - 0
docs/superpowers/specs/2026-11-08-signature-landscape-fix.md

@@ -0,0 +1,85 @@
+# 手签名横屏适配修复 任务书
+
+- 需求编号:DOC-2026-11-08-signature-landscape-fix
+- 需求来源:主理人反馈(小程序端)
+- 状态:待开发
+- 关联需求变更:见 `docs/需求分析/2026-11-08-手签名横屏适配需求变更.md`(随派发同步合入)
+
+---
+
+## 一、需求原话
+
+> 手签名功能,横屏下签名的区域太小了,文字和按钮都过大。而且签名也没显示出笔记来。
+
+## 二、现状核查(已确认根因)
+
+涉改文件(均基于 `origin/cfclub` 最新):
+
+1. `cfc-frontend/pages/signature/signature.vue`(311 行,签名页,横屏全屏,`navigationStyle:custom`)
+2. `cfc-frontend/components/hand-signature/hand-signature.vue`(367 行,通用手签名组件,**当前实际仅 signature.vue 引用**;checkout.vue 仅跳转、不渲染组件,改动零波及)
+
+### 根因 R1:签名区域太小 —— canvasHeight 只在竖屏时算过一次
+
+- `signature.vue onLoad()` 里同步调用 `computeCanvasHeight()`,此时仍处竖屏:`uni.getWindowInfo().windowHeight`(如 844px)− reserved(174/214) → `canvasHeight ≈ 670px`。
+- 随后 `enterLandscape()` 用 `wx.setPageOrientation({orientation:'landscape'})` **异步**切横屏;横屏后视口高 = 短边(如 390px),但 `canvasHeight` **从未重算**。
+- canvas 实际高 670px,而 `.sig-canvas-area{flex:1; overflow:hidden}` 可视高度仅约 216px → **画布被裁剪成顶部窄条,"签名区域太小"**。
+- 微信 `setPageOrientation` 无 success 回调链更新高度;页面也没有 `onResize` / `wx.onWindowResize` / H5 resize 监听 → 旋转后高度永远不更新。
+
+### 根因 R2:文字/按钮过大 —— rpx 基准在横屏下放大 ~2.2 倍
+
+- 微信 rpx 定义:750rpx = 当前**屏幕宽度**。竖屏宽 390 → 1rpx≈0.52px;横屏宽 844 → 1rpx≈1.13px,**所有 rpx 字号相对竖屏放大 ~2.17 倍**。
+- signature.vue:`.sig-title` 32rpx、`.sig-subtitle` 24rpx、`.sig-btn` 30rpx、`.rotate-hint-text` 26rpx —— 横屏全被放大,而 `.sig-btn` 高度 72px / `.sig-footer` 高 92px 是**固定 px 不变** → 文字过大、按钮比例失调。
+- 组件内同理:`.agree-text` 24rpx、`.agree-tick` 22rpx、`.btn-sign-*` 26rpx、`.signature-actions` 按钮 160/200rpx 定宽。
+- 结论:**横屏页字号/按钮尺寸应改用固定 px(或按视口短边换算),不得依赖 rpx**。
+
+### 根因 R3:签名没显示笔记 —— rect 未随旋转刷新,坐标整体错位
+
+- 组件 `loadRect()` 仅在 `mounted`(竖屏)执行一次(+300ms 重试一次);旋转后 canvas 的布局(left/top/width/height)全部变化,但 `this.rect` 仍是竖屏旧值。
+- `getPos()` 用 `clientX-rect.left / clientY-rect.top` 换算画布坐标 → 横屏下整体错位,笔迹画到 canvas 可视区外(被 `overflow:hidden` 裁掉)→ **"签名没显示笔记"**。
+- `handleConfirm` 导出也用旧 rect 尺寸。
+
+### 波及面确认(改动安全):
+
+- `hand-signature` 组件引用方:`grep` 全前端仅 `signature.vue` 实际使用 `<hand-signature>`;checkout.vue 只有 `hasHandSignatureField/purchase-signature-block` 字样,不 import、不渲染 → **组件改动安全,零波及其它页面**。
+- signature 页调用方:health-plan-summary.vue / checkout.vue / consignee-edit.vue(均为 navigateTo 跳转 + eventChannel 回传,不改它们)。
+- 无后端改动,纯前端 2 文件纵切修复。
+
+## 三、需求变更定义
+
+### 变更 S1:横屏尺寸重算 —— canvasHeight 随旋转刷新(signature.vue)
+
+- 页面增加窗口尺寸变化监听(微信 `wx.onWindowResize`、H5 `window.addEventListener('resize')`;`onUnload` 注销,防泄漏),回调内:
+  - 重新 `computeCanvasHeight()`(用 `uni.getWindowInfo()` 当前值,横屏时 windowHeight=短边,如 390)并同步给组件(`ref` 传入的 `height` prop 变化即可,组件只需响应式接收)。
+  - 调用组件公开方法 `refreshRect()`(见 S3)重新 `loadRect()`。
+- `enterLandscape()` 在 `wx.setPageOrientation` 的 success/complete 回调里补一次同样的「重算高度 + refreshRect」兜底(setPageOrientation 即时生效时 onWindowResize 未必触发)。
+- `computeCanvasHeight()` 保留:横屏短边 − reserved(标题 66 + 底部栏 92 + 同意 40 + 留白 16)取 `h>160?h:160`,逻辑不变,只是**在旋转后重跑**。
+
+### 变更 S2:横屏字号/按钮尺寸 px 化(signature.vue + 组件)
+
+- 将签名页与组件内**所有 rpx 字号改为固定 px**(等价竖屏观感,横屏不再放大):
+  - signature.vue:`.sig-title` 32rpx→16px、`.sig-subtitle` 24rpx→12px、`.sig-btn` 30rpx→15px、`.rotate-hint-text` 26rpx→13px(保留 `calc(... * var(--font-scale))` 结构,只是把 rpx 换 px)。
+  - hand-signature.vue:`.agree-text` 24rpx→12px、`.agree-tick` 22rpx→11px、`.btn-sign-clear/.btn-sign-confirm` 26rpx→13px、`.signature-actions` 按钮定宽 160/200rpx→80/100px(margin-right 20rpx→10px)、`.agree-box` 32rpx→16px、`.signature-agree` margin 16rpx→8px。
+- 按钮高度(72px/92px)已是 px 不动;`line-height` 同步为 72px 已具备。
+- 目的:横屏与竖屏观感一致,消除 R2。
+
+### 变更 S3:组件公开 refreshRect() 并修复导出兜底(hand-signature.vue)
+
+- 在组件 methods 新增公开方法 `refreshRect()`:重新执行 `loadRect()`(复用现有 `query.select('.signature-canvas').boundingClientRect`)。
+- `getPos()` 防御:`rect` 为 null 时沿用现行为(回退 raw clientX/Y),不做额外改动;**核心修复由「旋转后调用 refreshRect() 刷新 rect」达成**。
+- `handleConfirm` 导出 x/y/width/height 用刷新后的 `this.rect`(现有代码已是 `var rect = this.rect || {...}`,会自动用新 rect,无需改导出逻辑,仅确认)。
+
+### 不修改:
+
+- 不改成竖屏内嵌签名(需求是"横屏全屏签名",保持)。
+- 不改 `pages.json` 注册、不改 `signature-bus.js`、不改后端。
+- 不改组件 `handleClear` / `_emitSignature` / eventChannel 回传链路。
+
+## 四、TDD 入池建议
+
+- 能力键:`signature.landscape.layout`(前端 UI 纵切,无独立后端接口)
+- 验收:真机/工具横屏下——① 画布高度等于可视区(短边 − 固定栏),无裁剪;② 文字/按钮尺寸与竖屏观感一致;③ 横屏书写笔迹实时可见、导出 dataUrl 完整;④ 旋转后(切回竖屏再横屏)rect 与高度仍正确;⑤ 不回归竖屏下 signature 页与 health summary / checkout / consignee-edit 跳转回传链路。
+
+## 五、风险与关联记录
+
+- 风险:`wx.setPageOrientation` 在部分安卓机型即时旋转时 canvas 会闪烁/重建,若刷新 rect 后仍偶发笔迹偏移,可在 `refreshRect` 的 boundingClientRect 回调成功后置 `hasDrawn` 不变即可(不加重绘逻辑,保持简单)。
+- 关联:无其它任务书依赖;纯前端纵切,可独立合入。

+ 39 - 0
docs/需求分析/2026-11-08-手签名横屏适配需求变更.md

@@ -0,0 +1,39 @@
+# 手签名横屏适配需求变更
+
+> 对齐模板:2026-11-06-成就成长打卡需求变更.md
+> 变更编号:SIG-2026-11-08-L1 | 变更日期:2026-11-08 | 版本:v1.0
+
+## 一、需求原话
+
+> 手签名功能,横屏下签名的区域太小了,文字和按钮都过大。而且签名也没显示出笔记来。
+
+## 二、现状核查
+
+- 手签名页 `cfc-frontend/pages/signature/signature.vue` 为独立横屏全屏签名页(`navigationStyle:custom`),复用通用组件 `components/hand-signature/hand-signature.vue`;组件经 `utils/signature-bus.js` 传 prefill、eventChannel 回传 dataUrl,被 health-plan-summary / checkout / consignee-edit 三个页面 navigateTo 跳转使用。
+- 根因三问同源,均为**横屏旋转后未适配**:
+  1. **签名区域太小(R1)**:`canvasHeight` 在 `onLoad`(竖屏)时以 `windowHeight`(长边,如 844px)算出 ≈670px,随后 `wx.setPageOrientation` 异步切横屏(高=短边 390px),高度**从未重算** → 画布被 `overflow:hidden` 裁剪成顶部窄条。
+  2. **文字/按钮过大(R2)**:rpx 基准是 750rpx=屏宽,横屏屏宽从 390→844,**所有 rpx 字号放大 ~2.2 倍**,而按钮高度是固定 px 不变 → 字大钮小。
+  3. **笔迹不显示(R3)**:组件的 `loadRect()` 只在竖屏 mounted 取一次 `rect`,横屏旋转后 canvas 布局变化但 `rect` 不刷新 → `getPos()` 用 `clientX-rect.left` 换算全部错位,笔迹画到可视区外。
+- 波及面确认:`hand-signature` 组件当前仅 signature.vue 实际渲染,checkout.vue 仅跳转不内嵌 → 改动零波及。
+
+## 三、需求变更定义
+
+| 变更 | 文件 | 内容 |
+|---|---|---|
+| S1 | pages/signature/signature.vue | 监听窗口尺寸变化(微信 `wx.onWindowResize` / H5 resize;onUnload 注销)+ setPageOrientation 回调双保险,旋转后**重算 canvasHeight** 并同步高度 prop、调用组件 `refreshRect()` 刷新坐标 |
+| S2 | signature.vue + hand-signature.vue | 签名页与组件**所有 rpx 字号/定宽改固定 px**(标题 32rpx→16px、按钮字 30rpx→15px 等,保留 `calc(px * var(--font-scale))` 结构),消除横屏 rpx 放大 ~2.2 倍 |
+| S3 | components/hand-signature/hand-signature.vue | 组件新增公开方法 `refreshRect()`(复用 `loadRect()` 重取 `.signature-canvas` boundingClientRect),供页面旋转后调用;`handleConfirm` 导出自动用新 rect(无需改) |
+
+## 四、TDD 入池
+
+- 建议能力键:`signature.landscape.layout`
+- 验收:横屏下画布高度=短边−固定栏无裁剪;文字/按钮与竖屏观感一致;横屏书写笔迹实时可见、导出完整;旋转后 rect/高度仍正确;竖屏及各跳转回传链路不回归。
+
+## 五、风险
+
+- setPageOrientation 即时旋转时个别安卓机型 canvas 闪烁/重建,若偶发笔迹偏移,以 refreshRect 回调后不影响 hasDrawn 为限,不加重绘逻辑。
+
+## 六、关联记录
+
+- 任务书:`docs/superpowers/specs/2026-11-08-signature-landscape-fix.md`
+- 需求分析台账新增本章;无既有变更覆盖。