# A13Rollcall V6.8 更新与开发者指南(补充) > 本文档对应第六代 A13 引擎 V6.8,补充本轮新增的「轮次系统」「TTS 语音朗读」「统计联动」以及设置项修复说明。基础插件语法见《插件开发完全指南.md》。 官网:[https://dkfile.istester.com/zhysppa13/a13callname.html](https://dkfile.istester.com/zhysppa13/a13callname.html) 仓库:[https://github.com/a13zhy/a13rollcall](https://github.com/a13zhy/a13rollcall) 自定义协议:`a13rollcall://` *** ## 1. 轮次系统(Round System) ### 1.1 设计原则 * **必须先有活动轮次才能抽取**。主程序启动后「开始抽取」按钮默认禁用,用户须先点击绿色「新建轮次」。 * 一轮 = 一次完整的课堂点名。每结束一轮,其记录被整体写入 `rounds_history.json`,与统计窗口严格一一对应。 ### 1.2 主界面状态(MainWindow) | 属性 | 含义 | | ------------------------ | ------------------ | | `self._round_active` | 当前是否有进行中的轮次(bool) | | `self._round_id` | 当前轮次编号(int / None) | | `self._round_records` | 当前轮次的抽取记录列表 | | `self._round_start_time` | 本轮开始时间字符串 | ### 1.3 关键方法 * `_start_new_round()`:开始新一轮。若已有活动轮次,先弹确认并保存旧轮次。 * `_finish_round_to_storage()`:把 `_round_records` 汇总成 `round_data` 并 `data_mgr.save_round()`,然后清空活动状态。 * `_reset_round()`:结束并保存当前轮(弹确认),回到「未开始」状态,禁用抽取按钮。 * `closeEvent`:退出时若活动轮次有记录,自动保存,防止丢失。 ### 1.4 记录结构(一条抽取记录) ``` { "student": "张三", "text": "第一课", # 抽到的课文标题,未抽课文则为空 "paragraph": "", "status": "未标记", # 标记后变为 已背过 / 未背熟 / 未背过 "time": "2026-10-06 10:30:15" } ``` ### 1.5 轮次数据结构(保存到磁盘) ``` { "round_id": 3, "start_time": "2026-10-06 10:20:00", "end_time": "2026-10-06 11:05:00", "records": [ ...上面的记录列表... ], "summary": {"total": 40, "mastered": 12, "familiar": 18, "unlearned": 10} } ``` ### 1.6 DataManager 轮次 API | 方法 | 说明 | | ---------------------------- | ------------------------- | | `next_round_id()` | 返回下一个可用轮次编号(现有最大 +1) | | `save_round(round_data)` | 追加保存一轮 | | `get_all_rounds()` | 返回每轮的摘要列表 | | `get_round_detail(round_id)` | 返回某一轮完整 detail(含 records) | | `delete_round(round_id)` | 删除指定轮次 | | `get_draw_records()` | 所有轮次的记录拍平成时间倒序列表 | | `get_text_stats()` | 跨轮次汇总课文抽取统计 | *** ## 2. 统计窗口(StatsDialog)联动 * 整个内容区已包进 `QScrollArea`,**不会再出现图表重叠 / 溢出**。 * 核心方法 `_render_view(round_id)`: * `round_id == -1`(全部轮次):汇总全局累计,学生表、积分排名、全部记录都显示。 * `round_id == 具体轮次`:只渲染该轮。饼图、学生抽取次数柱图、课文柱图、记录表全部基于该轮 `records` 重算;积分排名图与学生明细表清空(积分是跨轮全局概念)。 * 切换轮次下拉框会**立即联动刷新所有图表**,不再残留上一轮数据。 * 右上角 `当前视图` 标签会显示「全部轮次」或「第 N 轮」。 *** ## 3. TTS 离线语音朗读 ### 3.1 依赖 * 使用 `pyttsx3`(Windows SAPI5),**完全离线**,无需联网。 * 若环境无语音组件,朗读自动静默失败,不影响主流程。 ### 3.2 配置项(config.json 新增 `tts` 段) ``` "tts": { "enabled": false, "rate": 150, "volume": 1.0, "speak_text": true } ``` ### 3.3 行为 * 抽取完成后 `MainWindow._speak_result(name)` 朗读「某某同学」。 * `speak_text=true` 时接着朗读课文标题。 * 设置路径:左侧树 → 抽取 → 语音朗读,含开关、课文朗读、语速滑杆、试听按钮。 *** ## 4. 本轮设置项修复 * 权重系统页(动态权重、三档倍率)原本未接入读写,现已接通;开关同时写入 `draw.dynamic_weight` 与 `draw.dynamic_focus`(引擎实际读取后者)。 * 标记提示开关 `ui.mark_toast` 已接通。 * 新增「语音朗读」设置页并完整读写。 *** ## 5. 插件可用上下文补充 插件 `context` 可读取的运行期信息(在 `plugin_manager.PluginContext` 中): * `context.get_draw_modes()`:当前抽取模式列表 * 最后一次抽取结果广播:`draw_finish` 钩子会把结果 student/text 作为参数回调 * 时间模块:插件沙箱已注入 `datetime`(类)与 `datetime_module`(模块),可直接 `datetime.now()` *** ## 6. 打包注意 * 需随程序分发:`students.txt`、`texts.txt`、`config.json`(含 tts 段默认值会自动补全)、`rounds_history.json`(运行时自动生成)。 * TTS 依赖 `pyttsx3`,打包时用 `--hidden-import pyttsx3` 及 SAPI 驱动,确保离线机器可朗读。