dev-manager-tauri/src-tauri/src/commands/project_tools.rs
2026-09-21 12:52:37 +09:00

219 lines
6.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::db::pool;
use rusqlite::params;
use serde::{Deserialize, Serialize};
use std::process::Command as StdCommand;
// ── 数据结构 ──────────────────────────────────────────────────────────────────
#[derive(Debug, Serialize)]
pub struct ProjectTool {
pub id: String,
pub project_id: String,
pub name: String,
pub icon: String,
pub exe_path: String,
pub args: Option<String>,
pub sort_order: i32,
}
#[derive(Debug, Deserialize)]
pub struct ProjectToolInput {
pub name: String,
pub icon: String,
pub exe_path: String,
pub args: Option<String>,
pub sort_order: Option<i32>,
}
// ── Tauri 命令 ────────────────────────────────────────────────────────────────
/// 获取某个项目的所有工具
#[tauri::command]
pub fn get_project_tools(project_id: String) -> Result<Vec<ProjectTool>, String> {
let conn = pool().get().map_err(|e| e.to_string())?;
let mut stmt = conn
.prepare(
"SELECT id, project_id, name, icon, exe_path, args, sort_order
FROM project_tools
WHERE project_id = ?1
ORDER BY sort_order ASC, rowid ASC",
)
.map_err(|e| e.to_string())?;
let rows = stmt
.query_map(params![project_id], |row| {
Ok(ProjectTool {
id: row.get(0)?,
project_id: row.get(1)?,
name: row.get(2)?,
icon: row.get(3)?,
exe_path: row.get(4)?,
args: row.get(5)?,
sort_order: row.get(6)?,
})
})
.map_err(|e| e.to_string())?
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.to_string());
rows
}
/// 添加工具到项目
#[tauri::command]
pub fn add_project_tool(project_id: String, input: ProjectToolInput) -> Result<String, String> {
let conn = pool().get().map_err(|e| e.to_string())?;
let id = uuid::Uuid::new_v4().to_string();
conn.execute(
"INSERT INTO project_tools (id, project_id, name, icon, exe_path, args, sort_order)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
params![
id,
project_id,
input.name,
input.icon,
input.exe_path,
input.args,
input.sort_order.unwrap_or(0),
],
)
.map_err(|e| e.to_string())?;
Ok(id)
}
/// 更新工具信息
#[tauri::command]
pub fn update_project_tool(id: String, input: ProjectToolInput) -> Result<(), String> {
let conn = pool().get().map_err(|e| e.to_string())?;
conn.execute(
"UPDATE project_tools
SET name = ?1, icon = ?2, exe_path = ?3, args = ?4, sort_order = ?5
WHERE id = ?6",
params![
input.name,
input.icon,
input.exe_path,
input.args,
input.sort_order.unwrap_or(0),
id,
],
)
.map_err(|e| e.to_string())?;
Ok(())
}
/// 删除项目工具
#[tauri::command]
pub fn remove_project_tool(id: String) -> Result<(), String> {
let conn = pool().get().map_err(|e| e.to_string())?;
conn.execute("DELETE FROM project_tools WHERE id = ?1", params![id])
.map_err(|e| e.to_string())?;
Ok(())
}
// ── 全局快启命令(写入 global_tools 表,无项目 FK 约束)────────────────────────
#[tauri::command]
pub fn get_global_tools() -> Result<Vec<ProjectTool>, String> {
let conn = pool().get().map_err(|e| e.to_string())?;
let mut stmt = conn
.prepare(
"SELECT id, name, icon, exe_path, args, sort_order
FROM global_tools
ORDER BY sort_order ASC, rowid ASC",
)
.map_err(|e| e.to_string())?;
let rows = stmt
.query_map([], |row| {
Ok(ProjectTool {
id: row.get(0)?,
project_id: "__global__".to_string(),
name: row.get(1)?,
icon: row.get(2)?,
exe_path: row.get(3)?,
args: row.get(4)?,
sort_order: row.get(5)?,
})
})
.map_err(|e| e.to_string())?
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.to_string());
rows
}
#[tauri::command]
pub fn add_global_tool(input: ProjectToolInput) -> Result<String, String> {
let conn = pool().get().map_err(|e| e.to_string())?;
let id = uuid::Uuid::new_v4().to_string();
conn.execute(
"INSERT INTO global_tools (id, name, icon, exe_path, args, sort_order)
VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
params![
id,
input.name,
input.icon,
input.exe_path,
input.args,
input.sort_order.unwrap_or(0),
],
)
.map_err(|e| e.to_string())?;
Ok(id)
}
#[tauri::command]
pub fn update_global_tool(id: String, input: ProjectToolInput) -> Result<(), String> {
let conn = pool().get().map_err(|e| e.to_string())?;
conn.execute(
"UPDATE global_tools
SET name = ?1, icon = ?2, exe_path = ?3, args = ?4, sort_order = ?5
WHERE id = ?6",
params![
input.name,
input.icon,
input.exe_path,
input.args,
input.sort_order.unwrap_or(0),
id,
],
)
.map_err(|e| e.to_string())?;
Ok(())
}
#[tauri::command]
pub fn remove_global_tool(id: String) -> Result<(), String> {
let conn = pool().get().map_err(|e| e.to_string())?;
conn.execute("DELETE FROM global_tools WHERE id = ?1", params![id])
.map_err(|e| e.to_string())?;
Ok(())
}
/// 启动工具(通用:exe 路径 + 可选参数)
#[tauri::command]
pub fn launch_tool(exe_path: String, args: Option<String>) -> Result<(), String> {
#[cfg(target_os = "windows")]
{
use std::os::windows::process::CommandExt;
let mut cmd = StdCommand::new("cmd");
cmd.args(["/c", &exe_path]);
if let Some(a) = &args {
let trimmed = a.trim();
if !trimmed.is_empty() {
cmd.raw_arg(trimmed);
}
}
cmd.spawn().map_err(|e| format!("启动失败: {e}"))?;
}
#[cfg(not(target_os = "windows"))]
{
let mut cmd = StdCommand::new(&exe_path);
if let Some(a) = &args {
let trimmed = a.trim();
if !trimmed.is_empty() {
cmd.args(trimmed.split_whitespace());
}
}
cmd.spawn().map_err(|e| format!("启动失败: {e}"))?;
}
Ok(())
}