Skip to content

feat(library): 添加扫码借书&续借等接口流程提示优化&安全性优化#154

Closed
clever-max wants to merge 5 commits into
BenderBlog:mainfrom
clever-max:codex/library-scan-borrow
Closed

feat(library): 添加扫码借书&续借等接口流程提示优化&安全性优化#154
clever-max wants to merge 5 commits into
BenderBlog:mainfrom
clever-max:codex/library-scan-borrow

Conversation

@clever-max

@clever-max clever-max commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

背景

为图书馆模块补充"扫码借书"流程:扫描馆藏条码 → 按条码查询书籍 → 确认借书提交。同时修复续借的 toast 提示问题。

新增功能

  • 扫码借书:图书馆页面新增扫码借书入口,扫描馆藏条码后查询书籍详情并确认借出。
  • 搜索页扫码借书:搜索结果页不直接借书,改为"扫码借阅此书",进入扫码页后校验实际扫描结果与所选书籍是否一致,防止误借。
  • 续借提示修复:续借成功不再误弹"图书馆接口异常"等脏提示,按后端 code == 1 精确判断,补齐缺失参数。

安全性与误操作控制

  • 搜索结果不能直接借书,必须进入扫码流程。
  • 真实借书仅在用户扫描实体馆藏条码并点击最终确认后发生。
  • 从搜索页选择书籍进入扫码页时,校验扫描结果是否匹配所选书籍,防止扫错。
  • 不可借或已借出的馆藏仍展示书籍信息,但不允许提交借书。

具体改动

新增文件

lib/page/library/scan_borrow_window.dart — 扫码借书页面,复用项目已有 qr_code_dart_scan,无新增依赖。

  • 扫描条码 → 停扫 → 调 getScannedBorrowBook(barcode) 查询书籍。
  • 查询成功展示完整 BookDetailCard,失败 toast 报错并恢复扫描。
  • _borrowStatusFor 四层判定:预期书不匹配 / 条码精确命中在架 → 可借 / 命中但不在架 → 展示原因 / 无命中取首个在架副本 / 均不满足 → 无可借馆藏。
  • _submitBorrow 仅可借时调用 borrowBook() 发起真实借书,成功后刷新借阅列表并退出。

修改文件

lib/repository/xidian_ids/library_session.dart — 图书馆接口层

  • 新增 getScannedBorrowBook(barcode):请求 api/search/list.htmlsearchFiled: "barcode",解析第一本为 BookInfo,补封面。
  • 新增 borrowBook(barcode, bookInfo, searchCode):请求 api/borrow/borrow.html,提交 barNumber/cardNumber/bookName/author/searchCode。内部通过 _getUserBarcode() 提前获取读者条码作为 cardNumber
  • 新增 borrowScannedBook() 作为语义入口转发到 borrowBook
  • 修复 renew():按 code == 1 判断成功并返回固定"续借成功",失败抛出 LibraryOperationException;补齐 bookName/isbn/author 参数。
  • 新增 LibraryOperationException 异常类及 _throwIfLibrarySessionExpired 辅助判断。

lib/page/library/book_detail_card.dart — 搜索结果页防误借

  • 新增 showBorrowAction/onBorrowRequest 参数。
  • 可借馆藏存在时展示警告文案:"搜索结果不能直接借出,请到馆拿书后扫描馆藏条码"。
  • 点击按钮通过回调跳转 ScanBorrowWindow(expectedBook: bookInfo)

lib/page/library/search_book_window.dart — 搜索页借书入口

  • 详情页借书操作改为跳转 ScanBorrowWindow(expectedBook: bookInfo)

lib/page/library/library_window.dart — 图书馆主页

  • AppBar 新增扫码按钮,点击进入 ScanBorrowWindow()(自由扫码模式)。

lib/page/library/borrow_info_card.dart — 借阅列表续借

  • 续借按钮改为 async/try/catch/finallyfinally 保证加载框关闭。
  • 成功后 toast 结果并刷新列表,失败 toast 异常信息。

国际化

zh_CN.yaml / zh_TW.yaml / en_US.yaml 新增扫码引导、状态反馈、误扫提示、防误借警告等文案。

测试

flutter build apk --release --target-platform android-arm64

构建成功。

@BenderBlog

Copy link
Copy Markdown
Owner

我之前写过类似的,感兴趣去看看我之前咋搞的。同时,顺便看看提交记录有没有我删去这个功能的备注,我当时有可能是“对远端服务器数据造成修改的风险”,或者“减少多余的摄像机依赖”而删了。
不要用 AI 去完成上述任务,暂时不用管代码的事情。

Comment thread assets/flutter_i18n/zh_CN.yaml Outdated
@BenderBlog

Copy link
Copy Markdown
Owner

代码审阅完了,应该改成:“添加扫码”和“续借等接口优化流程”

@clever-max clever-max changed the title feat(library): add scan-to-borrow flow feat(library): 添加扫码借书&续借等接口流程提示优化 Jul 3, 2026
@clever-max

clever-max commented Jul 4, 2026

Copy link
Copy Markdown
Contributor Author

附:借书流程优化与缺陷修复

修复

  • 空 toast:借书成功后偶尔弹出空白 toast。根因是后端 code==1msg 可能返回空字符串 "",Dart 的 ?? 运算符只判 null 不判空串。改为三级显式检查。
  • 异常消息国际化library_session.dart 中 10 处 throw 的硬编码中文消息(馆藏条码为空查询图书失败 等)改为通过 i18nKey 字段走三语翻译,scan_borrow_window.dartborrow_info_card.dart 的 catch 块同步适配。
  • 兜底位置不误导_findLocationByBarcode() 未能精确匹配到具体副本时,不再展示可能错误的馆藏位置,改为通用提示并设 location = null,避免用户被错误信息误导。

交互改进

  • 借书二次确认弹窗:点「确认借书」后新增居中 Dialog,展示封面、书名、馆藏位置,5 秒倒计时自动取消。按钮改为「确认借书」+「取消(N)」,去掉原按钮上的「将真实借出」字样。
  • 详情页编排号码移除BookDetailCard 中的 barCodesStr 字段在多副本场景下只展示第一个编目号,既不准确又与下方 BookPlaceCard 各副本的独立 书籍编号 重复,已移除。

改动文件

  1. library_session.dart(改)
  • borrowBook() 空 toast:data["msg"]?.toString() ?? ... → 三级显式判空串
  • 异常类加 i18nKey 字段,10 处 throw 站点全部补齐
  1. scan_borrow_window.dart(改)
  • _exceptionMsg():有 i18nKey 走翻译,否则 toString()
  • _handleCapture / _submitBorrow catch 块改用 _exceptionMsg(e)
  • _submitBorrow() 中间插确认弹窗,确认后才 _submitting=true
  • 兜底分支 location=null + scan_borrow_fallback
  • 按钮 confirm_borrow_real_action → confirm_borrow
  1. borrow_confirm_dialog.dart(新)
  • 居中 Dialog:封面 + 书名 + 位置 → FilledButton 确认 + TextButton「取消(N)」
  • 5 秒 Timer.periodic 倒计时,到 0 自动 pop(false)
  1. book_detail_card.dart(改)
  • 删除 barCodesStr 展示块(编排号码,不准确且重复)
  1. borrow_info_card.dart(改)
  • renew 失败 catch 块按 i18nKey 翻译
  1. zh_CN/TW/en_US.yaml(改)
  • +8 个 library.error_*(异常消息三语)
  • +1 个 scan_borrow_fallback(兜底提示三语)

国际化

  • zh_CN/TW/en_US.yaml:新增 8 个 library.error_* 键 + 1 个 scan_borrow_fallback

续借功能有赖后续测试

@clever-max clever-max changed the title feat(library): 添加扫码借书&续借等接口流程提示优化 feat(library): 添加扫码借书&续借等接口流程提示优化&图书馆功能优化 Jul 5, 2026
@clever-max clever-max changed the title feat(library): 添加扫码借书&续借等接口流程提示优化&图书馆功能优化 feat(library): 添加扫码借书&续借等接口流程提示优化&安全性优化 Jul 5, 2026
@clever-max

Copy link
Copy Markdown
Contributor Author

修复借阅列表可能返回 0 本

根因getBorrowList() 的 session 守卫使用了 userId == 0 && token == ""(AND 逻辑),而其余 5 个方法均使用 ||(OR)。当 token 因过期被清空但 userId 仍在时,AND 短路不触发 initSession(),带着空凭散发请求,服务端不报错返回空数据。

修复:改为 || 统一守卫逻辑;同时补齐缺失的 _throwIfLibrarySessionExpired() 调用,确保 code == -1 时自动清理凭据并重新登录。

修复搜索结果顺序不确定

根因searchBook()Pool(5) 并发下载封面后 toReturn.add(e),插入顺序取决于 Future 完成顺序而非 API 响应顺序。

修复:预分配定长列表,按索引 toReturn[i].imageUrl = ... 写入,保序。

修复借阅列表封面获取浪费

根因getBorrowList() 并发池回调中 LibrarySession().bookCover(...) 每次 new 一个 LibrarySession 实例,触发构造函数链 initSession() → CAS 预热。bookCover() 调用的是 findxidian.libsp.cn 封面 API,不依赖图书馆 session。

修复:直接调用 bookCover(...) 复用当前实例。

借阅列表排序优化

原来仅按 normReturnDateTime 排序。增加次键 loanDateTime(借阅日期),还书期限相同时按借阅先后排列。

改动文件

lib/repository/xidian_ids/library_session.dart(+24/-18)

@BenderBlog

Copy link
Copy Markdown
Owner

有重大变化,但不要关闭,就在这上面接着改吧

@BenderBlog

Copy link
Copy Markdown
Owner

#157 替代

@BenderBlog BenderBlog closed this Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants