新增: AI Chat多项增强(审批去重/编辑重发/导出/实体引用/会话置顶搜索)+任务推进链df-nodes落地
This commit is contained in:
@@ -68,18 +68,22 @@ fn validate_transition(from: &str, to: &str) -> Result<(), String> {
|
||||
// CRUD
|
||||
// ============================================================
|
||||
|
||||
/// 列出知识 — 可按 status 筛选,status=None 时默认排除 archived
|
||||
/// 列出知识 — 可按 status 筛选,status=None 时默认仅返回 published
|
||||
///
|
||||
/// 默认范围说明(F-260616-02 决策 a):
|
||||
/// - status=None → library tab 的数据源,语义为「已发布知识库」,仅 published。
|
||||
/// 不再混杂 pending_review(pending_review 归 inbox 收件箱,见 knowledge_list_candidates)。
|
||||
/// - 显式传 status 时按该 status 过滤(含 archived)。
|
||||
#[tauri::command]
|
||||
pub async fn knowledge_list(
|
||||
state: State<'_, AppState>,
|
||||
status: Option<String>,
|
||||
) -> Result<Vec<KnowledgeRecord>, String> {
|
||||
match status {
|
||||
// 显式查 archived 时原样返回(含归档项)
|
||||
Some(s) if s == "archived" => state.knowledge.list_by_status("archived").await.map_err(err_str),
|
||||
// 显式传 status 时按该 status 过滤(含 archived)
|
||||
Some(s) => state.knowledge.list_by_status(&s).await.map_err(err_str),
|
||||
// 默认:列出非 archived 的全部(单查询 status != 'archived')
|
||||
None => state.knowledge.list_non_archived().await.map_err(err_str),
|
||||
// 默认:library 仅 published(F-260616-02 决策 a,职责清晰:library=published,inbox=待处理)
|
||||
None => state.knowledge.list_by_status("published").await.map_err(err_str),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,16 +212,64 @@ pub async fn knowledge_record_reuse(
|
||||
.map_err(err_str)
|
||||
}
|
||||
|
||||
/// 审核收件箱 — 列出 candidate(按 confidence 语义排序)
|
||||
/// 收件箱 — 列出待处理条目(candidate + pending_review),按 confidence 语义排序
|
||||
///
|
||||
/// 语义(F-260616-02 决策 a):inbox = 「待处理」收件箱,聚合 candidate(待评估)
|
||||
/// 与 pending_review(待发布审核)两种待处理状态。library 仅 published。
|
||||
///
|
||||
/// 实现:list_by_status 单状态查询,这里合并 candidate 与 pending_review 两路结果。
|
||||
/// 两路各自已按 `confidence DESC, created_at DESC` 排序,有序合并保持同一规则。
|
||||
#[tauri::command]
|
||||
pub async fn knowledge_list_candidates(
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<Vec<KnowledgeRecord>, String> {
|
||||
state
|
||||
.knowledge
|
||||
.list_by_status("candidate")
|
||||
.await
|
||||
.map_err(err_str)
|
||||
let (candidates, pending) = tokio::try_join!(
|
||||
state.knowledge.list_by_status("candidate"),
|
||||
state.knowledge.list_by_status("pending_review"),
|
||||
)
|
||||
.map_err(err_str)?;
|
||||
Ok(merge_by_confidence(candidates, pending))
|
||||
}
|
||||
|
||||
/// 有序合并两列(各自已按 confidence DESC, created_at DESC 排序),结果保持同序。
|
||||
///
|
||||
/// confidence 排序权重:high=3, medium=2, low=1, 其他=0;同权重按 created_at DESC
|
||||
/// (字符串毫秒时间戳字典序 = 时间序)。等价 SQL `ORDER BY CASE confidence ... DESC, created_at DESC`。
|
||||
fn merge_by_confidence(
|
||||
mut a: Vec<KnowledgeRecord>,
|
||||
mut b: Vec<KnowledgeRecord>,
|
||||
) -> Vec<KnowledgeRecord> {
|
||||
use std::cmp::Ordering;
|
||||
fn rank(c: &str) -> i8 {
|
||||
match c {
|
||||
"high" => 3,
|
||||
"medium" => 2,
|
||||
"low" => 1,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
let cmp = |x: &KnowledgeRecord, y: &KnowledgeRecord| -> Ordering {
|
||||
let rx = rank(x.confidence.as_deref().unwrap_or(""));
|
||||
let ry = rank(y.confidence.as_deref().unwrap_or(""));
|
||||
ry.cmp(&rx) // confidence DESC
|
||||
.then_with(|| y.created_at.cmp(&x.created_at)) // created_at DESC
|
||||
};
|
||||
a.sort_by(cmp);
|
||||
b.sort_by(cmp);
|
||||
let mut out = Vec::with_capacity(a.len() + b.len());
|
||||
let (mut i, mut j) = (0, 0);
|
||||
while i < a.len() && j < b.len() {
|
||||
if cmp(&a[i], &b[j]) != Ordering::Greater {
|
||||
out.push(a[i].clone());
|
||||
i += 1;
|
||||
} else {
|
||||
out.push(b[j].clone());
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
out.extend_from_slice(&a[i..]);
|
||||
out.extend_from_slice(&b[j..]);
|
||||
out
|
||||
}
|
||||
|
||||
/// 归档(软删除) — UPDATE status='archived'
|
||||
|
||||
Reference in New Issue
Block a user