88//! goal_groups 随组删除级联清除,goal_milestones.ref_group_id
99//! SET NULL(绑定组被删 → 里程碑降级手动判定,提示 UI 属 M2)。
1010
11- use rusqlite:: { params , Connection } ;
11+ use rusqlite:: Connection ;
1212
13- use crate :: db:: { unix_seconds, Db } ;
1413use crate :: error:: Result ;
1514
1615// 子模块声明(AGENTS.md §3 单文件 ≤300 行;#[path] 使兄弟文件平铺在同目录,各自带 @ai-context)。
@@ -29,6 +28,9 @@ mod retro;
2928/// 绑定域:目标↔组绑定 + 组结算钩子。
3029#[ path = "db_goals_binding.rs" ]
3130mod binding;
31+ /// 毕业报告域:goal_graduation_reports 快照表读写。
32+ #[ path = "db_goals_graduation.rs" ]
33+ mod graduation;
3234
3335/// 三表 DDL + 索引(幂等:CREATE TABLE IF NOT EXISTS;旧库升级自动补表)。
3436pub ( crate ) fn init ( conn : & Connection ) -> Result < ( ) > {
@@ -81,48 +83,6 @@ pub(crate) fn init(conn: &Connection) -> Result<()> {
8183 Ok ( ( ) )
8284}
8385
84- impl Db {
85-
86- // ─────────────────────── v0.18.1 毕业报告(REQ-255/256) ───────────────────────
87-
88- /// 写毕业报告快照(目标删除后保留;goal_id SET NULL——报告独立于 goals 行)。
89- pub fn create_graduation_report ( & self , goal_id : i64 , goal_name : & str , report_json : & str ) -> Result < i64 > {
90- self . with_conn ( |conn| {
91- conn. execute (
92- "INSERT INTO goal_graduation_reports (goal_id, goal_name, report_json, created_at)
93- VALUES (?1, ?2, ?3, ?4)" ,
94- params ! [ goal_id, goal_name, report_json, unix_seconds( ) ] ,
95- ) ?;
96- Ok ( conn. last_insert_rowid ( ) )
97- } )
98- }
99-
100- /// 目标的毕业报告 JSON(无 → None——毕业仪式只发一次,防重复确认;
101- /// 解析在命令层——AppError 无 serde 变体,存储态原样返回)。
102- pub fn get_graduation_report_json ( & self , goal_id : i64 ) -> Result < Option < String > > {
103- self . with_conn ( |conn| {
104- let mut stmt = conn. prepare (
105- "SELECT report_json FROM goal_graduation_reports WHERE goal_id = ?1 ORDER BY id DESC LIMIT 1" ,
106- ) ?;
107- let mut rows = stmt. query_map ( params ! [ goal_id] , |r| r. get :: < _ , String > ( 0 ) ) ?;
108- match rows. next ( ) {
109- Some ( Ok ( json) ) => Ok ( Some ( json) ) ,
110- Some ( Err ( e) ) => Err ( e. into ( ) ) ,
111- None => Ok ( None ) ,
112- }
113- } )
114- }
115-
116- /// 全部毕业报告 JSON(档案区;已删目标的报告仍列出——解析在命令层)。
117- pub fn list_graduation_reports_json ( & self ) -> Result < Vec < String > > {
118- self . with_conn ( |conn| {
119- let mut stmt = conn. prepare ( "SELECT report_json FROM goal_graduation_reports ORDER BY id ASC" ) ?;
120- let rows = stmt. query_map ( [ ] , |r| r. get :: < _ , String > ( 0 ) ) ?;
121- rows. collect :: < rusqlite:: Result < Vec < _ > > > ( ) . map_err ( Into :: into)
122- } )
123- }
124- }
125-
12686#[ cfg( test) ]
12787#[ path = "db_goals_tests.rs" ]
12888mod tests;
0 commit comments