修复用户端个人头像展示

This commit is contained in:
czl231
2026-09-02 22:48:47 +08:00
parent 2033a9407e
commit 7cc56f955f
12 changed files with 334 additions and 23 deletions

View File

@@ -67,6 +67,7 @@
| 模块 | 必要功能 | 规则 |
| --- | --- | --- |
| 个人资料 | 展示头像、昵称和脱敏手机号 | 有头像时使用圆形区域居中裁剪显示;头像为空、加载中或加载失败时显示用户名首字母,不显示破图;头像上传与更换作为独立功能实现 |
| 钱包 | 充值套餐、自定义充值、余额、余额明细、提现申请与支付密码 | 充值结果以渠道回调为准;自定义金额有上下限和风控;提现范围与审核规则由平台配置 |
| 押金管理 | 气瓶押金、报警器押金、押金汇总、明细、退瓶退押金 | 按设备/气瓶规格、数量、单价、使用状态和开始时间核算;退押金结果以现场验收和平台审核为准 |
| 用气统计 | 月度/年度用气量、平均用气量、图表、明细和报表导出 | 数据来源、统计周期、单位和最后更新时间须明确;无数据展示空状态 |

View File

@@ -121,7 +121,7 @@
- 银行卡号、身份证号、预留手机号使用 `Global.FieldEncryptionKey` 经 HKDF 派生独立 AES-GCM 加密键和 HMAC 指纹键;接口列表只返回末四位掩码。开发占位密钥不得用于生产。
- 支付密码独立于登录密码,仅允许六位数字,使用 bcrypt 保存;连续失败达到阈值后在 Redis 短时锁定。绑卡、解绑、余额支付和提现均要求支付密码或限定用途的一次性验证码。
- 公共上传接口 `/upload/file` 必须携带平台、气站、配送点、用户或工作人员任一合法 JWT图片/PDF 最大 10MB视频上限从配置读取。上传只返回资源 URI业务接口负责建立关联并记录操作者、采集与接收时间。
- 平台账户资料头像使用专用 `/upload/avatar` 上传入口,仅允许真实 JPG/PNG、最大 2MB、最大 4096×4096并在服务端完成扩展名、MIME、尺寸和完整图片解码校验。头像读取通过 `/heqi/platform/v1/{staff_account|user_account|platform_account}/:identity/avatar` 受 JWT、菜单和对象角色权限保护通用列表及详情响应继续移除 `avatar` 字段。平台总后台的工作人员、用户和平台账户列表可对当前可视记录调用受控接口展示缩略图,必须限制并发、按页缓存、离页取消请求并释放本地 Blob URL,不得将头像 URI 写回列表数据或开放静态目录。普通资料更新未提交 `avatar` 时保持原头像,只有明确上传或恢复默认头像时才修改该字段。
- 平台账户资料头像使用专用 `/upload/avatar` 上传入口,仅允许真实 JPG/PNG、最大 2MB、最大 4096×4096并在服务端完成扩展名、MIME、尺寸和完整图片解码校验。后台头像读取通过 `/heqi/platform/v1/{staff_account|user_account|platform_account}/:identity/avatar` 受 JWT、菜单和对象角色权限保护用户 App 仅可通过 `/heqi/client/v1/user/auth/avatar` 读取当前登录用户自己的头像。通用列表及详情响应继续移除 `avatar` 字段,头像文件目录不得作为公开静态目录。平台总后台的工作人员、用户和平台账户列表可对当前可视记录调用受控接口展示缩略图,必须限制并发、按页缓存、离页取消请求并释放本地 Blob URL。普通资料更新未提交 `avatar` 时保持原头像,只有明确上传或恢复默认头像时才修改该字段。
- 充值、支付、提现、工单证据、轨迹点、内容确认等写入均携带幂等号;资金入账在数据库事务内锁定钱包并同时写不可变流水。
- 钱包可提现余额是当前总余额的子集,始终满足 `0 <= 可提现余额 <= 总余额`。普通消费扣减总余额后,必须同步把可提现余额限制在剩余总余额以内。
- 提现申请在同一数据库事务内锁定钱包、同时预扣总余额和可提现余额并写入不可变流水;驳回只返还该申请实际预扣的两类余额,完成打款只确认外部结果,不得再次扣款。

View File

@@ -0,0 +1,58 @@
# 用户端个人头像展示修复操作日志
操作时间2026-09-02
操作类型:修改、扩展
影响模块:用户端 Flutter App 个人中心、用户端头像读取接口
## 操作前状态
个人资料接口和领域模型已包含 `avatar` 字段,但“我的”页面固定展示用户名首字母,没有读取真实头像。首次尝试直接访问 `/uploads/avatars/...` 后,经管理端与用户端截图对照确认仍回退为首字母;根因是头像文件位于受控目录,管理端使用鉴权接口读取,用户端缺少读取本人头像的对应接口。
## 具体操作
1. 新增 `GET /heqi/client/v1/user/auth/avatar`,复用 `user_app` JWT 和当前用户范围,只返回本人受保护头像二进制内容。
2. Flutter HTTP 客户端新增携带当前登录令牌的二进制读取能力404 按无头像处理,其他失败使用中文异常。
3. 个人资料 Repository 新增本人头像读取方法,不再尝试公开访问受控文件路径。
4. 新增圆形头像组件,真实图片使用 `BoxFit.cover` 居中裁剪。
5. 头像为空、加载中、图片损坏或头像接口失败时继续显示用户名首字母;用户名为空时显示“用”,头像失败不阻塞钱包等其他资料。
6. 个人中心接入真实头像组件,本次不增加上传、更换或资料修改入口。
7. 新增后端路由、鉴权二进制请求和头像状态测试。
## 操作后状态
新增接口部署后,用户资料存在有效头像时,“我的”页面会通过鉴权请求显示真实头像;没有头像或图片不可用时保持原有首字母占位,不会出现空白或破图。登录、钱包、地址、合同、流水和维修功能未改变。
## 代码变更
- `backend/api/internal/routers/client.go`:注册当前用户头像读取路由。
- `backend/api/internal/routers/client_test.go`:验证用户头像路由存在。
- `backend/api/internal/logic/client/user/auth.go`:按当前登录用户读取受保护头像。
- `apps/user_app/lib/data/services/api_client.dart`:新增携带登录令牌的二进制读取方法。
- `apps/user_app/lib/data/repositories/client_repository.dart`:新增当前用户头像读取方法。
- `apps/user_app/lib/ui/features/profile/profile_avatar.dart`:新增真实头像与回退组件。
- `apps/user_app/lib/ui/features/profile/profile_page.dart`:个人资料卡片接入头像组件。
- `apps/user_app/test/data/api_client_test.dart`覆盖头像字节、鉴权请求头、404 和异常文案。
- `apps/user_app/test/ui/profile_avatar_test.dart`:覆盖正常头像、空头像、损坏图片和接口失败状态。
- `docs/03-用户端App需求.md`:补充个人头像展示规则。
- `docs/11-数据接口与安全.md`:补充用户本人头像读取边界。
## 验证结果
- `flutter analyze`:通过,无问题。
- `flutter test`:通过,共 15 项测试。
- `go test ./internal/routers ./internal/logic/upload ./internal/logic/client/user`:通过。
- `go build ./cmd/main/main.go`:通过;临时构建产物已清理。
- `flutter build web --release --dart-define=API_BASE_URL=http://rest.heqiapp.com`:通过。
- 本地后端:已使用开发配置启动,`12426` 正常监听;新增头像接口未登录访问返回 401路由和鉴权守卫生效。
- 本地用户端:已在 `5180` 重新启动并切换到 `http://127.0.0.1:12426`;原登录状态可读取个人资料和钱包。
- 边界案例:空头像、损坏图片、接口 404、接口异常和空用户名均有安全回退。
## 风险评估
- 新接口仅允许 `user_app` 令牌读取当前登录用户自己的头像,不接受目标用户标识,避免越权读取。
- 头像通过客户端鉴权请求读取,不开放受控文件目录;网络或文件异常时界面会安全回退为首字母。
- 本次未实现头像上传和更换,避免扩大文件选择、上传校验与资料更新范围。
- 当前 `rest.heqiapp.com` 运行版本尚未包含新增头像接口;部署服务端后才能在现有本地用户端页面看到真实头像。
- 当前账号记录指向 2026-09-02 上传的头像文件,本地 `runtime/uploads/avatars` 中没有该文件;本地后端虽已正常运行,仍会回退首字母。需要从服务器同步对应头像文件,或在本地重新上传头像后再验证真实图片。