Repository navigation
feat(mobile): OCR 相册来源选择 + fix 账单日期 NaN 与 sync 422 - #59
Merged
Merged
Conversation
点击 OCR 📷 按钮不再直接进入拍照,而是弹出「拍照 / 相册」来源选择面板, 满足用户已在相册里(朋友发的截图、微信保存的图)直接选图识别的场景。 - 新增 ImageSourceSheet 悬浮卡片(输入框上方 2 列 Grid) - useCamera 扩展 pickFromLibrary,权限/base64 行为与 pickImage 对齐 - ChatInputBar props 从 onCamera 拆成 onPickCamera/onPickLibrary,与 voiceMode/plusExpanded 互斥 - app.json 补 photosPermission 文案,避免 iOS 14+ 首次访问相册因缺 NSPhotoLibraryUsageDescription 崩溃 - theme.sizes 新增 7xl: 32 供 emoji 字号复用 Co-Authored-By: Claude <noreply@anthropic.com>
根因:后端 LLM prompt 让模型在识别不到日期时返回空字符串,前端用
?? 做兜底但空串是 falsy 不 nullish,`new Date("")` 得到 Invalid Date,
最终卡片显示 "NaN年NaN月NaN日";同时本地 SQLite 里的坏数据被
sync push 时 Pydantic 判定为非法 datetime,整批返回 422 拖累其他记录。
三层防御:
- 后端 routers/ocr.py: occurred_at 为空/None 时用 datetime.now(UTC) 兜底,
统一 Z 后缀(与项目其他 ISO 格式一致)
- 后端 schemas/sync.py: TransactionRow.occurred_at 加 field_validator,
拦空串/None 防止单条坏数据阻塞整批 push
- 后端 schemas/ocr.py: occurred_at 加 Field(min_length=1),合约层明确非空
- 前端 useChat.ts: ?? 改 ||,拦截空字符串
- 前端 lib/format.ts: formatDate 提取 + isNaN 兜底,救旧数据的展示
- 前端 lib/sync/sync-service.ts: push 前 sanitizeTransactions 用 created_at 兜底
测试:后端新增 2 条 ocr 兜底测试,前端新增 4 条 formatDate 测试。
Co-Authored-By: Claude <noreply@anthropic.com>
hinson0
added a commit
that referenced
this pull request
Apr 20, 2026
- docs/cc/plans/todo-ocr-indexed-volcano.md: feature-dev 流程产出的 实施计划(Context / UI 设计 / 5 步实施 / 验证清单) - apps/mobile/docs/playground/ocr-source-sheet.html: 单文件可交互的 UI/UX 原型,左控制面板调参、右实时预览、输出 RN StyleSheet 片段 两份均为 PR #59 功能落地前的设计产物,便于后续回溯设计决策。 Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
NaN年NaN月NaN日— 根因是 LLM 无日期返回""、前端??不拦空串occurred_at=""让 Pydantic 拒掉整次推送主要改动
功能(commit 562deae)
ImageSourceSheet:2 列 Grid 悬浮卡片,参考QuickActions的条件渲染模式,自带onClose职责下沉useCamera.pickFromLibrary:launchImageLibraryAsync,权限/base64 行为与pickImage对齐ChatInputBar:三态互斥(plusExpanded / sourceSheetOpen / voiceMode)app.json:补photosPermission,避免 iOS 14+ 首次访问相册因缺NSPhotoLibraryUsageDescription闪退theme.sizes."7xl": 32:emoji 字号进设计系统修复(commit 3b12a97)
三层防御根治 NaN + 422:
routers/ocr.pydatetime.now(UTC).isoformat().replace("+00:00","Z")兜底schemas/ocr.pyField(min_length=1)合约层明确非空schemas/sync.py@field_validator(mode="before")空值 → 当前时间,防单条坏数据拖累整批 pushhooks/useChat.ts?? → ||拦截空串写入lib/format.tsformatDate加isNaN(d.getTime())兜底救旧数据lib/sync/sync-service.tssanitizeTransactionspush 前用created_at兜底Test plan
pytest tests/49 通过(新增test_ocr_empty_occurred_at_falls_back_to_now+test_ocr_null_occurred_at_falls_back_to_now)just cicd-fe18 套件 177 测试通过(新增 4 条formatDate用例)注意事项
photosPermission自定义中文文案需 EAS build 后才能在 iOS 系统弹框生效;Expo Go 下显示 Expo Go 的默认文案,功能正常occurred_at=""行仍在数据库里,但 sanitize + 后端 validator 双层防御保证 push 时被修正到 PostgreSQL(用户下次 pull 回来就是合法值)Co-Authored-By: Claude noreply@anthropic.com