Skip to content

Commit b3aa4a9

Browse files
committed
refactor(rust): 拆 commands_goals 读侧视图(673→501)
1 parent 233528a commit b3aa4a9

6 files changed

Lines changed: 214 additions & 194 deletions

File tree

‎app/src-tauri/src/app_commands.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,9 @@ pub fn handle() -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync
126126
crate::commands_contracts::week_contract_status,
127127
// v0.18.0(REQ-248~250):学习目标层——目标 CRUD/绑定/进度/埋点(无 AI)
128128
crate::commands_goals::create_goal,
129-
crate::commands_goals::list_goals,
130-
crate::commands_goals::get_goal_detail,
131-
crate::commands_goals::get_goal_progress,
129+
crate::commands_goals::views::list_goals,
130+
crate::commands_goals::views::get_goal_detail,
131+
crate::commands_goals::views::get_goal_progress,
132132
crate::commands_goals::update_goal,
133133
crate::commands_goals::update_goal_interview,
134134
crate::commands_goals::delete_goal,

‎app/src-tauri/src/commands_goals.rs‎

Lines changed: 8 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,25 @@
99
//! @ai-context: inner 函数统一收 &Db(commands_groups/commands_settlement 先例)
1010
//! ——内存库单测直连,不构造重量级 AppState。
1111
12-
use serde::{Deserialize, Serialize};
12+
use serde::Deserialize;
1313
use tauri::State;
1414

1515
use crate::commands::{normalize_title, AppState};
1616
use crate::db::{unix_seconds, Db};
17-
use crate::goal_interview::{
18-
assemble_declaration, derive_criteria, horizon_end_secs,
19-
};
20-
use crate::goal_progress::{build_report, progress_statement, GoalProgressReport, GoalSignals};
21-
use crate::goal_rules::graduation_readiness;
17+
use crate::goal_interview::{derive_criteria, horizon_end_secs};
18+
use crate::goal_progress::GoalSignals;
2219
use crate::goal_schema::{
2320
Goal, GoalIntent, GoalMilestone, NewGoal, NewMilestone, SuccessCriteria, CRITERIA_GROUP_SETTLED,
2421
CRITERIA_MANUAL, MILESTONE_DONE, MILESTONE_IN_PROGRESS, MILESTONE_PENDING, MILESTONE_SKIPPED,
2522
TIER_DEFAULT,
2623
};
2724
use crate::video_profile_domain::DomainKind;
2825

26+
/// 读侧视图层(5 个视图 DTO + 3 条读命令 + 3 个读 inner;0 emit)。
27+
/// `pub(crate)`:注册清单在 app_commands.rs(crate 根的兄弟模块)按 `commands_goals::views::x` 解析。
28+
#[path = "commands_goals_views.rs"]
29+
pub(crate) mod views;
30+
2931
/// 一周秒数(草案 due_at 换算:第 N 周 = created_at + N*7d)。
3032
const WEEK_SECS: i64 = 7 * 86_400;
3133
/// 访谈答案文本上限(防御超大 payload;chips/填空兜底的答案均为短文本)。
@@ -75,61 +77,6 @@ pub struct GoalMilestoneInput {
7577
pub due_weeks: usize,
7678
}
7779

78-
/// 目标卡视图(列表项:单行折叠=名称/状态/一句话进度/可毕业徽标)。
79-
#[derive(Debug, Clone, Serialize)]
80-
#[serde(rename_all = "camelCase")]
81-
pub struct GoalCardView {
82-
pub goal: Goal,
83-
/// 一句话进度("62% · 里程碑 2/4")
84-
pub statement: String,
85-
pub percent: f64,
86-
pub milestone_done: usize,
87-
pub milestone_total: usize,
88-
/// 🎓 可毕业(判据配方全达标——状态必须 active)
89-
pub ready: bool,
90-
}
91-
92-
/// 目标详情视图(详情页一次取全:里程碑/组/判据/进度/可毕业)。
93-
#[derive(Debug, Clone, Serialize)]
94-
#[serde(rename_all = "camelCase")]
95-
pub struct GoalDetailView {
96-
pub goal: Goal,
97-
/// 判据检查(可毕业明细——毕业确认仪式数据源)
98-
pub criteria: Vec<ReadinessView>,
99-
pub progress: GoalProgressView,
100-
pub milestones: Vec<GoalMilestone>,
101-
pub groups: Vec<GoalGroupView>,
102-
/// 宣言回显(重新访谈/详情页展示)
103-
pub declaration: String,
104-
}
105-
106-
/// 目标绑定组视图(详情关联组区)。
107-
#[derive(Debug, Clone, Serialize)]
108-
#[serde(rename_all = "camelCase")]
109-
pub struct GoalGroupView {
110-
pub id: i64,
111-
pub name: String,
112-
}
113-
114-
/// 判据检查视图。
115-
#[derive(Debug, Clone, Serialize)]
116-
#[serde(rename_all = "camelCase")]
117-
pub struct ReadinessView {
118-
pub label: String,
119-
pub met: bool,
120-
pub detail: String,
121-
}
122-
123-
/// 进度视图(现算信号 + 一句话进度 + 可毕业判定)。
124-
#[derive(Debug, Clone, Serialize)]
125-
#[serde(rename_all = "camelCase")]
126-
pub struct GoalProgressView {
127-
pub progress: GoalProgressReport,
128-
pub statement: String,
129-
pub ready: bool,
130-
pub checks: Vec<ReadinessView>,
131-
}
132-
13380
/// 新建目标(访谈确认后一步创建——status=active,无 draft 仪式)。
13481
#[tauri::command]
13582
pub fn create_goal(state: State<'_, AppState>, input: GoalCreateInput) -> Result<Goal, String> {
@@ -139,24 +86,6 @@ pub fn create_goal(state: State<'_, AppState>, input: GoalCreateInput) -> Result
13986
Ok(goal)
14087
}
14188

142-
/// 全部目标卡(列表;每卡现算进度——聚合皆毫秒级查询)。
143-
#[tauri::command]
144-
pub fn list_goals(state: State<'_, AppState>) -> Result<Vec<GoalCardView>, String> {
145-
list_goals_inner(&state.db)
146-
}
147-
148-
/// 目标详情(里程碑/绑定组/判据/进度一次取全)。
149-
#[tauri::command]
150-
pub fn get_goal_detail(state: State<'_, AppState>, id: i64) -> Result<GoalDetailView, String> {
151-
get_goal_detail_inner(&state.db, id)
152-
}
153-
154-
/// 进度刷新(详情页动作后局部刷新;与 get_goal_detail 同口径)。
155-
#[tauri::command]
156-
pub fn get_goal_progress(state: State<'_, AppState>, id: i64) -> Result<GoalProgressView, String> {
157-
get_goal_progress_inner(&state.db, id)
158-
}
159-
16089
/// 编辑目标(名称/领域/时限——重访谈走 update_goal_interview)。
16190
#[tauri::command]
16291
pub fn update_goal(
@@ -373,85 +302,6 @@ pub(crate) fn create_goal_inner(db: &Db, input: &GoalCreateInput) -> Result<Goal
373302
Ok(goal)
374303
}
375304

376-
pub(crate) fn list_goals_inner(db: &Db) -> Result<Vec<GoalCardView>, String> {
377-
let goals = db.list_goals().map_err(|e| e.to_string())?;
378-
let mut cards = Vec::new();
379-
for goal in goals {
380-
let (statement, percent, done, total, ready) = goal_card_metrics(db, &goal)?;
381-
cards.push(GoalCardView {
382-
goal,
383-
statement,
384-
percent,
385-
milestone_done: done,
386-
milestone_total: total,
387-
ready,
388-
});
389-
}
390-
Ok(cards)
391-
}
392-
393-
pub(crate) fn get_goal_detail_inner(db: &Db, id: i64) -> Result<GoalDetailView, String> {
394-
require_goal(db, id)?;
395-
let goal = db
396-
.get_goal(id)
397-
.map_err(|e| e.to_string())?
398-
.ok_or_else(|| format!("目标不存在: {}", id))?;
399-
let milestones = db.list_milestones(id).map_err(|e| e.to_string())?;
400-
let group_ids = db.list_goal_group_ids(id).map_err(|e| e.to_string())?;
401-
let mut groups = Vec::new();
402-
for gid in group_ids {
403-
if let Some(g) = db.get_group(gid).map_err(|e| e.to_string())? {
404-
groups.push(GoalGroupView { id: gid, name: g.name });
405-
}
406-
}
407-
let signals = collect_signals(db, id)?;
408-
let progress = build_report(&signals);
409-
let statement = progress_statement(&progress);
410-
let criteria = parse_criteria(&goal)?;
411-
let ready = graduation_readiness(&goal.status, &progress, &criteria);
412-
let intent: GoalIntent = serde_json::from_str(&goal.intent_json).unwrap_or_default();
413-
let declaration = assemble_declaration(
414-
&goal.name,
415-
intent.scenario.as_deref(),
416-
intent.criteria_statement.as_deref(),
417-
&criteria.statement,
418-
intent.non_scope.as_deref(),
419-
intent.horizon.as_deref(),
420-
);
421-
Ok(GoalDetailView {
422-
goal,
423-
criteria: ready.checks.into_iter().map(client_check).collect(),
424-
progress: GoalProgressView {
425-
progress,
426-
statement,
427-
ready: ready.ready,
428-
checks: vec![],
429-
},
430-
milestones,
431-
groups,
432-
declaration,
433-
})
434-
}
435-
436-
pub(crate) fn get_goal_progress_inner(db: &Db, id: i64) -> Result<GoalProgressView, String> {
437-
require_goal(db, id)?;
438-
let goal = db
439-
.get_goal(id)
440-
.map_err(|e| e.to_string())?
441-
.ok_or_else(|| format!("目标不存在: {}", id))?;
442-
let signals = collect_signals(db, id)?;
443-
let progress = build_report(&signals);
444-
let statement = progress_statement(&progress);
445-
let criteria = parse_criteria(&goal)?;
446-
let ready = graduation_readiness(&goal.status, &progress, &criteria);
447-
Ok(GoalProgressView {
448-
progress,
449-
statement,
450-
ready: ready.ready,
451-
checks: ready.checks.into_iter().map(client_check).collect(),
452-
})
453-
}
454-
455305
pub(crate) fn update_goal_inner(
456306
db: &Db,
457307
id: i64,
@@ -636,23 +486,6 @@ fn build_intent(input: &GoalCreateInput) -> GoalIntent {
636486
}
637487
}
638488

639-
/// 目标卡指标(现算;判据 JSON 损坏 → ready=false 诚实降级不崩溃)。
640-
fn goal_card_metrics(db: &Db, goal: &Goal) -> Result<(String, f64, usize, usize, bool), String> {
641-
let signals = collect_signals(db, goal.id)?;
642-
let progress = build_report(&signals);
643-
let ready = match parse_criteria(goal) {
644-
Ok(criteria) => graduation_readiness(&goal.status, &progress, &criteria).ready,
645-
Err(_) => false,
646-
};
647-
Ok((
648-
progress_statement(&progress),
649-
progress.percent,
650-
progress.milestone_done,
651-
progress.milestone_total,
652-
ready,
653-
))
654-
}
655-
656489
/// 进度信号收集(详情/列表共用——口径单一;lifecycle 命令组复用)。
657490
pub(crate) fn collect_signals(db: &Db, goal_id: i64) -> Result<GoalSignals, String> {
658491
db.goal_progress_signals(goal_id, unix_seconds()).map_err(|e| e.to_string())
@@ -663,11 +496,6 @@ pub(crate) fn parse_criteria(goal: &Goal) -> Result<SuccessCriteria, String> {
663496
serde_json::from_str(&goal.success_criteria_json).map_err(|e| e.to_string())
664497
}
665498

666-
/// ReadinessCheck → 客户端视图。
667-
fn client_check(c: crate::goal_rules::ReadinessCheck) -> ReadinessView {
668-
ReadinessView { label: c.label, met: c.met, detail: c.detail }
669-
}
670-
671499
#[cfg(test)]
672500
#[path = "commands_goals_tests.rs"]
673501
mod tests;

‎app/src-tauri/src/commands_goals_tests.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! commands_goals 命令层单测(inner 纯编排——内存库 AAA 模式)。
22
3+
use crate::commands_goals::views::{get_goal_detail_inner, get_goal_progress_inner, list_goals_inner};
34
use crate::commands_goals::{
45
add_goal_milestone_inner, bind_goal_group_inner, create_goal_inner, delete_goal_inner,
5-
get_goal_detail_inner, get_goal_progress_inner, list_goals_inner, require_goal,
6-
set_goal_milestone_status_inner, unbind_goal_group_inner, update_goal_inner,
6+
require_goal, set_goal_milestone_status_inner, unbind_goal_group_inner, update_goal_inner,
77
update_goal_interview_inner, update_goal_status_inner, GoalCreateInput, GoalMilestoneInput,
88
};
99
use crate::db::Db;

0 commit comments

Comments
 (0)