修复: 项目详情批量(任务列表联动刷新/工作流降级标注/中文git乱码/子目录错误行内/零工程空态/切tab保活) + 依赖图批量(节点渲染register/环高亮/防环防重/点击选中) + 销账

This commit is contained in:
lxy
2026-08-09 21:35:13 +08:00
parent 4a9f77872e
commit 4df91ed155
15 changed files with 402 additions and 77 deletions
+43 -1
View File
@@ -255,6 +255,25 @@ pub async fn remove_project_module(state: State<'_, AppState>, id: String) -> Re
if let Ok(Some(module)) = state.project_modules.get_by_id(&id).await {
invalidate_git_status_cache(&module.path);
}
// G3:FK 级联 — module_dependencies 的 from/to REFERENCES project_modules(id),参与依赖的
// 工程直接删必 FK 违例失败(foreign_keys=ON)。删工程前先清所有参与该工程的依赖边
// (从/到任一端都算参与),顺序参照 purge_with_descendants(子表先于父表删)。
for dep in state
.module_dependencies
.list_by_field("from_module_id", &id)
.await
.map_err(err_str)?
{
state.module_dependencies.delete(&dep.id).await.map_err(err_str)?;
}
for dep in state
.module_dependencies
.list_by_field("to_module_id", &id)
.await
.map_err(err_str)?
{
state.module_dependencies.delete(&dep.id).await.map_err(err_str)?;
}
state.project_modules.delete(&id).await.map_err(err_str)?;
Ok(())
}
@@ -1065,7 +1084,14 @@ fn collect_git_status_map(dir: &str) -> HashMap<String, String> {
return map;
}
let timeout = std::time::Duration::from_secs(10);
let Some(out) = run_git_cmd(path, &["status", "--porcelain"], timeout) else {
// B1[PD-P1-1]:-c core.quotepath=false 让 git status 直接输出 UTF-8 原名(中文/非 ASCII
// 路径不再八进制转义 \xxx),否则 GitChanges/文件树展示一串转义码。其余特殊字符
// (空格/引号)仍按 C 风格加引号,由下方 strip_prefix 逻辑剥除兜底。
let Some(out) = run_git_cmd(
path,
&["-c", "core.quotepath=false", "status", "--porcelain"],
timeout,
) else {
return map;
};
for line in out.lines() {
@@ -1302,6 +1328,22 @@ pub async fn add_module_dependency(
if project_id.is_empty() || from_module_id.is_empty() || to_module_id.is_empty() {
return Err("project_id / from_module_id / to_module_id 不能为空".to_string());
}
// G9:依赖两端不能是同一工程(自环无意义)。
if from_module_id == to_module_id {
return Err("依赖两端不能是同一工程".to_string());
}
// G6:幂等 — 同 project_id + from + to 已存在则直接返回已存在记录,不重复插入。
let existing = state
.module_dependencies
.list_by_field("project_id", &project_id)
.await
.map_err(err_str)?;
if let Some(found) = existing
.iter()
.find(|d| d.from_module_id == from_module_id && d.to_module_id == to_module_id)
{
return Ok(found.clone());
}
let dep_type = dep_type.unwrap_or_else(|| "library".to_string());
let record = ModuleDependencyRecord {
id: new_id(),