修复执行环境编辑更新功能和编译错误
主要修复内容: 1. 修复执行环境编辑更新功能 - 简化前端更新逻辑,直接传递所有字段而非复杂的条件判断 - 添加详细的调试日志用于问题排查 - 修复数据刷新机制,保存后自动刷新页面 - 完善错误处理和用户提示 2. 修复编译错误 - 修复 sysinfo 0.30 API 变化问题 - 修复 ExecutionStatistics 字段不匹配问题 - 添加 chrono::Timelike trait 导入 - 修复 MutexGuard 所有权问题 3. 完善环境管理功能 - 实现健康检查命令 health_check_execution_environment - 完善删除、激活状态切换等功能 - 添加确认对话框和成功提示 4. 修复数据序列化问题 - 移除 environment_type 字段的 serde rename 属性 - 确保前后端数据格式一致 技术细节: - 后端使用 UniversalWorkflowService 支持多环境管理 - 前端使用 window.location.reload() 临时解决数据刷新问题 - 添加详细日志便于调试和问题排查
This commit is contained in:
44
Cargo.lock
generated
44
Cargo.lock
generated
@@ -2571,6 +2571,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"sysinfo",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-dialog",
|
||||
@@ -2686,6 +2687,15 @@ version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
@@ -4440,6 +4450,21 @@ dependencies = [
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.30.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"rayon",
|
||||
"windows 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
@@ -5825,6 +5850,16 @@ dependencies = [
|
||||
"windows-version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core 0.52.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
@@ -5857,6 +5892,15 @@ dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
|
||||
@@ -58,6 +58,7 @@ url = "2.5.4"
|
||||
urlencoding = "2.1"
|
||||
bincode = "1.3"
|
||||
zip = "0.6"
|
||||
sysinfo = "0.30"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["sysinfoapi"] }
|
||||
|
||||
@@ -81,7 +81,6 @@ pub struct WorkflowExecutionEnvironment {
|
||||
|
||||
// 基本信息
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub environment_type: EnvironmentType,
|
||||
pub description: Option<String>,
|
||||
|
||||
@@ -124,7 +123,6 @@ pub struct WorkflowExecutionEnvironment {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CreateExecutionEnvironmentRequest {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub environment_type: EnvironmentType,
|
||||
pub description: Option<String>,
|
||||
pub base_url: String,
|
||||
|
||||
@@ -259,6 +259,7 @@ impl WorkflowExecutionEnvironmentRepository {
|
||||
}
|
||||
|
||||
if set_clauses.is_empty() {
|
||||
info!("没有需要更新的字段,跳过更新,ID: {}", id);
|
||||
return Ok(()); // 没有需要更新的字段
|
||||
}
|
||||
|
||||
@@ -274,12 +275,14 @@ impl WorkflowExecutionEnvironmentRepository {
|
||||
set_clauses.join(", ")
|
||||
);
|
||||
|
||||
info!("执行更新SQL: {}, 更新字段: {:?}", sql, set_clauses);
|
||||
|
||||
let param_refs: Vec<&dyn rusqlite::ToSql> = params.iter().map(|p| p.as_ref()).collect();
|
||||
|
||||
conn.execute(&sql, param_refs.as_slice())
|
||||
let rows_affected = conn.execute(&sql, param_refs.as_slice())
|
||||
.map_err(|e| anyhow!("更新工作流执行环境失败: {}", e))?;
|
||||
|
||||
info!("成功更新工作流执行环境,ID: {}", id);
|
||||
info!("成功更新工作流执行环境,ID: {}, 影响行数: {}", id, rows_affected);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -603,10 +603,12 @@ pub fn run() {
|
||||
commands::workflow_commands::get_execution_results,
|
||||
commands::workflow_commands::cancel_execution,
|
||||
commands::workflow_commands::get_execution_history,
|
||||
commands::workflow_commands::get_system_statistics,
|
||||
commands::workflow_commands::get_execution_environments,
|
||||
commands::workflow_commands::create_execution_environment,
|
||||
commands::workflow_commands::update_execution_environment,
|
||||
commands::workflow_commands::delete_execution_environment
|
||||
commands::workflow_commands::delete_execution_environment,
|
||||
commands::workflow_commands::health_check_execution_environment
|
||||
])
|
||||
.setup(|app| {
|
||||
// 初始化日志系统
|
||||
|
||||
@@ -12,8 +12,10 @@ use crate::data::models::workflow_execution_environment::{
|
||||
};
|
||||
use crate::app_state::AppState;
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::State;
|
||||
use tracing::info;
|
||||
use chrono::Timelike;
|
||||
|
||||
/// 获取所有工作流模板
|
||||
#[tauri::command]
|
||||
@@ -146,19 +148,48 @@ pub async fn execute_workflow_with_mapping(
|
||||
.clone()
|
||||
};
|
||||
|
||||
// 创建ComfyUI服务
|
||||
let comfyui_settings = crate::config::ComfyUISettings::default();
|
||||
let comfyui_service = crate::business::services::comfyui_service::ComfyUIService::new(comfyui_settings);
|
||||
// 使用通用工作流服务(支持环境管理)
|
||||
let universal_service = {
|
||||
let service_guard = state.get_universal_workflow_service()
|
||||
.map_err(|e| format!("获取通用工作流服务失败: {}", e))?;
|
||||
|
||||
// 创建工作流执行服务
|
||||
let execution_service = crate::business::services::workflow_execution_service::WorkflowExecutionService::new(comfyui_service);
|
||||
service_guard.as_ref()
|
||||
.ok_or_else(|| "通用工作流服务未初始化,请先配置执行环境".to_string())?
|
||||
.clone()
|
||||
};
|
||||
|
||||
// 转换请求格式到新的统一格式
|
||||
let unified_request = crate::business::services::universal_workflow_service::ExecuteWorkflowRequest {
|
||||
workflow_identifier: format!("template_{}", request.workflow_template_id),
|
||||
version: None,
|
||||
input_data: request.input_data,
|
||||
environment_id: request.execution_environment_id,
|
||||
user_id: None,
|
||||
session_id: None,
|
||||
metadata: request.execution_config_override,
|
||||
};
|
||||
|
||||
// 执行工作流
|
||||
let response = execution_service.execute_workflow(request, &template_repo, &execution_repo).await
|
||||
let response = universal_service.execute_workflow(unified_request).await
|
||||
.map_err(|e| format!("执行工作流失败: {}", e))?;
|
||||
|
||||
// 转换响应格式
|
||||
let converted_response = crate::data::models::outfit_photo_generation::ExecuteWorkflowResponse {
|
||||
execution_id: response.execution_id,
|
||||
status: match response.status {
|
||||
crate::data::models::workflow_execution_record::ExecutionStatus::Running => "running".to_string(),
|
||||
crate::data::models::workflow_execution_record::ExecutionStatus::Completed => "completed".to_string(),
|
||||
crate::data::models::workflow_execution_record::ExecutionStatus::Failed => "failed".to_string(),
|
||||
crate::data::models::workflow_execution_record::ExecutionStatus::Cancelled => "cancelled".to_string(),
|
||||
crate::data::models::workflow_execution_record::ExecutionStatus::Pending => "pending".to_string(),
|
||||
crate::data::models::workflow_execution_record::ExecutionStatus::Timeout => "timeout".to_string(),
|
||||
},
|
||||
comfyui_prompt_id: response.comfyui_prompt_id,
|
||||
error_message: response.error_message,
|
||||
};
|
||||
|
||||
info!("工作流执行成功,执行记录ID: {}", response.execution_id);
|
||||
Ok(response)
|
||||
Ok(converted_response)
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +306,16 @@ pub async fn cancel_execution(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 执行历史分页响应
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ExecutionHistoryResponse {
|
||||
pub records: Vec<WorkflowExecutionRecord>,
|
||||
pub total_count: u32,
|
||||
pub page: u32,
|
||||
pub page_size: u32,
|
||||
pub total_pages: u32,
|
||||
}
|
||||
|
||||
/// 获取执行历史
|
||||
#[tauri::command]
|
||||
pub async fn get_execution_history(
|
||||
@@ -282,7 +323,7 @@ pub async fn get_execution_history(
|
||||
limit: Option<i32>,
|
||||
offset: Option<i32>,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<Vec<WorkflowExecutionRecord>, String> {
|
||||
) -> Result<ExecutionHistoryResponse, String> {
|
||||
info!("获取执行历史");
|
||||
|
||||
// 获取工作流执行记录仓库
|
||||
@@ -293,19 +334,35 @@ pub async fn get_execution_history(
|
||||
.ok_or_else(|| "工作流执行记录仓库未初始化".to_string())?;
|
||||
|
||||
// 查询执行历史
|
||||
let records = if let (Some(limit), Some(offset)) = (limit, offset) {
|
||||
let (records, total_count, page, page_size) = if let (Some(limit), Some(offset)) = (limit, offset) {
|
||||
let page = (offset / limit.max(1)) as u32;
|
||||
let page_size = limit as u32;
|
||||
let (records, _total) = repo.find_with_pagination(filter.as_ref(), page, page_size)
|
||||
let (records, total) = repo.find_with_pagination(filter.as_ref(), page, page_size)
|
||||
.map_err(|e| format!("分页查询执行历史失败: {}", e))?;
|
||||
records
|
||||
(records, total, page, page_size)
|
||||
} else {
|
||||
repo.find_all(filter.as_ref())
|
||||
.map_err(|e| format!("查询执行历史失败: {}", e))?
|
||||
// 如果没有分页参数,返回所有记录
|
||||
let records = repo.find_all(filter.as_ref())
|
||||
.map_err(|e| format!("查询执行历史失败: {}", e))?;
|
||||
let total = records.len() as u32;
|
||||
(records, total, 0, total)
|
||||
};
|
||||
|
||||
info!("成功获取 {} 条执行历史记录", records.len());
|
||||
Ok(records)
|
||||
let total_pages = if page_size > 0 {
|
||||
(total_count + page_size - 1) / page_size
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
info!("成功获取 {} 条执行历史记录,总数: {}", records.len(), total_count);
|
||||
|
||||
Ok(ExecutionHistoryResponse {
|
||||
records,
|
||||
total_count,
|
||||
page,
|
||||
page_size,
|
||||
total_pages,
|
||||
})
|
||||
}
|
||||
|
||||
/// 获取执行环境列表
|
||||
@@ -366,7 +423,7 @@ pub async fn update_execution_environment(
|
||||
request: UpdateExecutionEnvironmentRequest,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<WorkflowExecutionEnvironment, String> {
|
||||
info!("更新执行环境: {}", id);
|
||||
info!("更新执行环境: {}, 请求数据: {:?}", id, request);
|
||||
|
||||
// 获取工作流执行环境仓库
|
||||
let repo_guard = state.get_workflow_execution_environment_repository()
|
||||
@@ -375,6 +432,13 @@ pub async fn update_execution_environment(
|
||||
let repo = repo_guard.as_ref()
|
||||
.ok_or_else(|| "工作流执行环境仓库未初始化".to_string())?;
|
||||
|
||||
// 查询更新前的环境
|
||||
let old_environment = repo.find_by_id(id)
|
||||
.map_err(|e| format!("查询更新前的执行环境失败: {}", e))?
|
||||
.ok_or_else(|| format!("执行环境不存在,ID: {}", id))?;
|
||||
|
||||
info!("更新前的环境数据: {:?}", old_environment);
|
||||
|
||||
// 更新执行环境
|
||||
repo.update(id, &request)
|
||||
.map_err(|e| format!("更新执行环境失败: {}", e))?;
|
||||
@@ -384,7 +448,7 @@ pub async fn update_execution_environment(
|
||||
.map_err(|e| format!("查询更新后的执行环境失败: {}", e))?
|
||||
.ok_or_else(|| "更新后的执行环境未找到".to_string())?;
|
||||
|
||||
info!("成功更新执行环境,ID: {}", id);
|
||||
info!("成功更新执行环境,ID: {}, 更新后数据: {:?}", id, environment);
|
||||
Ok(environment)
|
||||
}
|
||||
|
||||
@@ -411,6 +475,43 @@ pub async fn delete_execution_environment(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 健康检查执行环境
|
||||
#[tauri::command]
|
||||
pub async fn health_check_execution_environment(
|
||||
id: i64,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<crate::data::models::workflow_execution_environment::HealthStatus, String> {
|
||||
info!("健康检查执行环境: {}", id);
|
||||
|
||||
// 获取工作流执行环境仓库并克隆以避免所有权问题
|
||||
let repo = {
|
||||
let repo_guard = state.get_workflow_execution_environment_repository()
|
||||
.map_err(|e| format!("获取工作流执行环境仓库失败: {}", e))?;
|
||||
|
||||
repo_guard.as_ref()
|
||||
.ok_or_else(|| "工作流执行环境仓库未初始化".to_string())?
|
||||
.clone()
|
||||
};
|
||||
|
||||
// 获取环境信息
|
||||
let _environment = repo.find_by_id(id)
|
||||
.map_err(|e| format!("查询执行环境失败: {}", e))?
|
||||
.ok_or_else(|| format!("执行环境不存在,ID: {}", id))?;
|
||||
|
||||
// 执行健康检查 - 使用公共方法
|
||||
let health_results = repo.health_check_all().await
|
||||
.map_err(|e| format!("执行健康检查失败: {}", e))?;
|
||||
|
||||
// 查找当前环境的健康状态
|
||||
let health_status = health_results.iter()
|
||||
.find(|(env_id, _)| *env_id == id)
|
||||
.map(|(_, status)| status.clone())
|
||||
.unwrap_or(crate::data::models::workflow_execution_environment::HealthStatus::Unknown);
|
||||
|
||||
info!("执行环境健康检查完成,ID: {}, 状态: {:?}", id, health_status);
|
||||
Ok(health_status)
|
||||
}
|
||||
|
||||
/// 导出工作流模板
|
||||
#[tauri::command]
|
||||
pub async fn export_workflow_template(
|
||||
@@ -634,6 +735,157 @@ pub async fn delete_execution_result_files(
|
||||
})
|
||||
}
|
||||
|
||||
/// 系统统计信息响应
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SystemStatistics {
|
||||
pub execution_stats: ExecutionStats,
|
||||
pub environment_stats: EnvironmentStats,
|
||||
pub system_resources: SystemResources,
|
||||
pub performance_metrics: PerformanceMetrics,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ExecutionStats {
|
||||
pub total_executions_today: u32,
|
||||
pub successful_executions_today: u32,
|
||||
pub failed_executions_today: u32,
|
||||
pub average_execution_time_seconds: f64,
|
||||
pub current_queue_size: u32,
|
||||
pub active_executions: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnvironmentStats {
|
||||
pub total_environments: u32,
|
||||
pub healthy_environments: u32,
|
||||
pub unhealthy_environments: u32,
|
||||
pub average_response_time_ms: f64,
|
||||
pub total_capacity: u32,
|
||||
pub used_capacity: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SystemResources {
|
||||
pub cpu_usage_percent: f64,
|
||||
pub memory_usage_percent: f64,
|
||||
pub disk_usage_percent: f64,
|
||||
pub network_status: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PerformanceMetrics {
|
||||
pub requests_per_minute: u32,
|
||||
pub average_response_time_ms: f64,
|
||||
pub error_rate_percent: f64,
|
||||
pub uptime_hours: f64,
|
||||
}
|
||||
|
||||
/// 获取系统统计信息
|
||||
#[tauri::command]
|
||||
pub async fn get_system_statistics(
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<SystemStatistics, String> {
|
||||
info!("获取系统统计信息");
|
||||
|
||||
// 获取工作流执行记录仓库
|
||||
let repo_guard = state.get_workflow_execution_record_repository()
|
||||
.map_err(|e| format!("获取工作流执行记录仓库失败: {}", e))?;
|
||||
|
||||
let repo = repo_guard.as_ref()
|
||||
.ok_or_else(|| "工作流执行记录仓库未初始化".to_string())?;
|
||||
|
||||
// 获取环境仓库
|
||||
let env_repo_guard = state.get_workflow_execution_environment_repository()
|
||||
.map_err(|e| format!("获取执行环境仓库失败: {}", e))?;
|
||||
|
||||
let env_repo = env_repo_guard.as_ref()
|
||||
.ok_or_else(|| "执行环境仓库未初始化".to_string())?;
|
||||
|
||||
// 获取今天的执行统计
|
||||
let today = chrono::Utc::now().date_naive();
|
||||
let today_filter = crate::data::models::workflow_execution_record::ExecutionRecordFilter {
|
||||
date_from: Some(today.and_hms_opt(0, 0, 0).unwrap().and_utc()),
|
||||
date_to: Some(today.and_hms_opt(23, 59, 59).unwrap().and_utc()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let execution_stats_result = repo.get_execution_statistics(Some(&today_filter))
|
||||
.map_err(|e| format!("获取执行统计失败: {}", e))?;
|
||||
|
||||
// 获取环境统计
|
||||
let environments = env_repo.find_all(None)
|
||||
.map_err(|e| format!("获取环境列表失败: {}", e))?;
|
||||
|
||||
let healthy_envs = environments.iter()
|
||||
.filter(|env| env.health_status == crate::data::models::workflow_execution_environment::HealthStatus::Healthy)
|
||||
.count() as u32;
|
||||
|
||||
let total_capacity: u32 = environments.iter()
|
||||
.map(|env| env.max_concurrent_jobs as u32)
|
||||
.sum();
|
||||
|
||||
// 获取当前活跃执行
|
||||
let active_filter = crate::data::models::workflow_execution_record::ExecutionRecordFilter {
|
||||
status: Some(crate::data::models::workflow_execution_record::ExecutionStatus::Running),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let active_executions = repo.find_all(Some(&active_filter))
|
||||
.map_err(|e| format!("获取活跃执行失败: {}", e))?;
|
||||
|
||||
// 获取队列中的执行
|
||||
let pending_filter = crate::data::models::workflow_execution_record::ExecutionRecordFilter {
|
||||
status: Some(crate::data::models::workflow_execution_record::ExecutionStatus::Pending),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let pending_executions = repo.find_all(Some(&pending_filter))
|
||||
.map_err(|e| format!("获取队列执行失败: {}", e))?;
|
||||
|
||||
// 计算系统资源使用情况(简化实现)
|
||||
let cpu_usage = get_cpu_usage().unwrap_or(0.0);
|
||||
let memory_usage = get_memory_usage().unwrap_or(0.0);
|
||||
let disk_usage = get_disk_usage().unwrap_or(0.0);
|
||||
|
||||
Ok(SystemStatistics {
|
||||
execution_stats: ExecutionStats {
|
||||
total_executions_today: execution_stats_result.total_executions,
|
||||
successful_executions_today: execution_stats_result.completed_executions,
|
||||
failed_executions_today: execution_stats_result.failed_executions,
|
||||
average_execution_time_seconds: execution_stats_result.average_duration_seconds.unwrap_or(0.0),
|
||||
current_queue_size: pending_executions.len() as u32,
|
||||
active_executions: active_executions.len() as u32,
|
||||
},
|
||||
environment_stats: EnvironmentStats {
|
||||
total_environments: environments.len() as u32,
|
||||
healthy_environments: healthy_envs,
|
||||
unhealthy_environments: environments.len() as u32 - healthy_envs,
|
||||
average_response_time_ms: environments.iter()
|
||||
.filter_map(|env| env.average_response_time_ms)
|
||||
.map(|t| t as f64)
|
||||
.sum::<f64>() / environments.len().max(1) as f64,
|
||||
total_capacity,
|
||||
used_capacity: active_executions.len() as u32,
|
||||
},
|
||||
system_resources: SystemResources {
|
||||
cpu_usage_percent: cpu_usage,
|
||||
memory_usage_percent: memory_usage,
|
||||
disk_usage_percent: disk_usage,
|
||||
network_status: "connected".to_string(),
|
||||
},
|
||||
performance_metrics: PerformanceMetrics {
|
||||
requests_per_minute: calculate_requests_per_minute(&execution_stats_result),
|
||||
average_response_time_ms: execution_stats_result.average_duration_seconds.unwrap_or(0.0) * 1000.0,
|
||||
error_rate_percent: if execution_stats_result.total_executions > 0 {
|
||||
(execution_stats_result.failed_executions as f64 / execution_stats_result.total_executions as f64) * 100.0
|
||||
} else {
|
||||
0.0
|
||||
},
|
||||
uptime_hours: get_uptime_hours(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// 获取存储统计信息
|
||||
#[tauri::command]
|
||||
pub async fn get_storage_statistics(
|
||||
@@ -685,3 +937,81 @@ pub async fn batch_cleanup_execution_results(
|
||||
errors: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
// 辅助函数:获取CPU使用率
|
||||
fn get_cpu_usage() -> Option<f64> {
|
||||
use sysinfo::System;
|
||||
|
||||
let mut system = System::new_all();
|
||||
system.refresh_cpu();
|
||||
|
||||
// 等待一小段时间以获得准确的CPU使用率
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
system.refresh_cpu();
|
||||
|
||||
let cpu_usage: f64 = system.cpus().iter()
|
||||
.map(|cpu| cpu.cpu_usage() as f64)
|
||||
.sum::<f64>() / system.cpus().len() as f64;
|
||||
|
||||
Some(cpu_usage)
|
||||
}
|
||||
|
||||
// 辅助函数:获取内存使用率
|
||||
fn get_memory_usage() -> Option<f64> {
|
||||
use sysinfo::System;
|
||||
|
||||
let mut system = System::new_all();
|
||||
system.refresh_memory();
|
||||
|
||||
let total_memory = system.total_memory();
|
||||
let used_memory = system.used_memory();
|
||||
|
||||
if total_memory > 0 {
|
||||
Some((used_memory as f64 / total_memory as f64) * 100.0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:获取磁盘使用率
|
||||
fn get_disk_usage() -> Option<f64> {
|
||||
use sysinfo::Disks;
|
||||
|
||||
let disks = Disks::new_with_refreshed_list();
|
||||
|
||||
// 获取主磁盘的使用率
|
||||
if let Some(disk) = disks.iter().next() {
|
||||
let total_space = disk.total_space();
|
||||
let available_space = disk.available_space();
|
||||
let used_space = total_space - available_space;
|
||||
|
||||
if total_space > 0 {
|
||||
Some((used_space as f64 / total_space as f64) * 100.0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:计算每分钟请求数
|
||||
fn calculate_requests_per_minute(stats: &crate::data::repositories::workflow_execution_record_repository::ExecutionStatistics) -> u32 {
|
||||
// 基于今天的总执行数估算每分钟请求数
|
||||
let total_today = stats.total_executions;
|
||||
let hours_passed = chrono::Utc::now().hour() + 1; // 至少1小时
|
||||
let minutes_passed = hours_passed * 60;
|
||||
|
||||
if minutes_passed > 0 {
|
||||
(total_today * 60) / minutes_passed
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:获取系统运行时间
|
||||
fn get_uptime_hours() -> f64 {
|
||||
use sysinfo::System;
|
||||
|
||||
System::uptime() as f64 / 3600.0 // 转换为小时
|
||||
}
|
||||
|
||||
@@ -146,6 +146,8 @@ export const EnvironmentConfigurator: React.FC<EnvironmentConfiguratorProps> = (
|
||||
// 初始化表单数据
|
||||
useEffect(() => {
|
||||
if (environment) {
|
||||
console.log('EnvironmentConfigurator 接收到环境数据:', environment);
|
||||
console.log('环境类型:', environment.environment_type, '类型:', typeof environment.environment_type);
|
||||
setFormData({
|
||||
name: environment.name,
|
||||
environment_type: environment.environment_type,
|
||||
@@ -159,6 +161,7 @@ export const EnvironmentConfigurator: React.FC<EnvironmentConfiguratorProps> = (
|
||||
max_execution_time_seconds: environment.max_execution_time_seconds,
|
||||
tags: environment.tags || []
|
||||
});
|
||||
console.log('设置的表单数据 environment_type:', environment.environment_type);
|
||||
} else {
|
||||
// 重置为默认值
|
||||
setFormData({
|
||||
|
||||
@@ -53,6 +53,15 @@ interface WorkflowExecutionRecord {
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// 执行历史分页响应接口
|
||||
interface ExecutionHistoryResponse {
|
||||
records: WorkflowExecutionRecord[];
|
||||
total_count: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
total_pages: number;
|
||||
}
|
||||
|
||||
// 筛选器接口
|
||||
interface ExecutionRecordFilter {
|
||||
workflow_template_id?: number;
|
||||
@@ -136,16 +145,14 @@ export const ExecutionHistoryList: React.FC<ExecutionHistoryListProps> = ({
|
||||
filterConditions.date_from = dateFrom.toISOString();
|
||||
}
|
||||
|
||||
const result = await invoke<WorkflowExecutionRecord[]>('get_execution_history', {
|
||||
const result = await invoke<ExecutionHistoryResponse>('get_execution_history', {
|
||||
filter: filterConditions,
|
||||
limit: pageSize,
|
||||
offset: (currentPage - 1) * pageSize
|
||||
});
|
||||
|
||||
setRecords(result);
|
||||
|
||||
// TODO: 获取总数来计算总页数
|
||||
setTotalPages(Math.ceil(result.length / pageSize));
|
||||
setRecords(result.records);
|
||||
setTotalPages(result.total_pages);
|
||||
|
||||
} catch (err) {
|
||||
console.error('加载执行历史失败:', err);
|
||||
|
||||
@@ -40,6 +40,15 @@ interface WorkflowExecutionRecord {
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// 执行历史分页响应接口
|
||||
interface ExecutionHistoryResponse {
|
||||
records: WorkflowExecutionRecord[];
|
||||
total_count: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
total_pages: number;
|
||||
}
|
||||
|
||||
// 系统统计信息接口
|
||||
interface SystemStatistics {
|
||||
execution_stats: {
|
||||
@@ -128,7 +137,7 @@ export const MonitoringDashboard: React.FC<MonitoringDashboardProps> = ({
|
||||
// 加载活跃执行
|
||||
const loadActiveExecutions = useCallback(async () => {
|
||||
try {
|
||||
const result = await invoke<WorkflowExecutionRecord[]>('get_execution_history', {
|
||||
const result = await invoke<ExecutionHistoryResponse>('get_execution_history', {
|
||||
filter: {
|
||||
status: 'running' // 只获取正在执行的
|
||||
},
|
||||
@@ -137,7 +146,7 @@ export const MonitoringDashboard: React.FC<MonitoringDashboardProps> = ({
|
||||
});
|
||||
|
||||
// 同时获取等待中的执行
|
||||
const pendingResult = await invoke<WorkflowExecutionRecord[]>('get_execution_history', {
|
||||
const pendingResult = await invoke<ExecutionHistoryResponse>('get_execution_history', {
|
||||
filter: {
|
||||
status: 'pending'
|
||||
},
|
||||
@@ -145,7 +154,7 @@ export const MonitoringDashboard: React.FC<MonitoringDashboardProps> = ({
|
||||
offset: 0
|
||||
});
|
||||
|
||||
setActiveExecutions([...result, ...pendingResult]);
|
||||
setActiveExecutions([...result.records, ...pendingResult.records]);
|
||||
} catch (err) {
|
||||
console.error('加载活跃执行失败:', err);
|
||||
// 使用模拟数据
|
||||
@@ -156,45 +165,44 @@ export const MonitoringDashboard: React.FC<MonitoringDashboardProps> = ({
|
||||
// 加载系统统计
|
||||
const loadSystemStats = useCallback(async () => {
|
||||
try {
|
||||
// TODO: 实现实际的系统统计API
|
||||
// const result = await invoke<SystemStatistics>('get_system_statistics');
|
||||
// setSystemStats(result);
|
||||
const result = await invoke<SystemStatistics>('get_system_statistics');
|
||||
setSystemStats(result);
|
||||
} catch (err) {
|
||||
console.error('加载系统统计失败:', err);
|
||||
|
||||
// 暂时使用模拟数据
|
||||
const mockStats: SystemStatistics = {
|
||||
// 如果API调用失败,使用基础的模拟数据作为后备
|
||||
const fallbackStats: SystemStatistics = {
|
||||
execution_stats: {
|
||||
total_executions_today: 156,
|
||||
successful_executions_today: 142,
|
||||
failed_executions_today: 14,
|
||||
average_execution_time_seconds: 45.6,
|
||||
total_executions_today: 0,
|
||||
successful_executions_today: 0,
|
||||
failed_executions_today: 0,
|
||||
average_execution_time_seconds: 0,
|
||||
current_queue_size: activeExecutions.filter(e => e.status === 'pending').length,
|
||||
active_executions: activeExecutions.filter(e => e.status === 'running').length
|
||||
},
|
||||
environment_stats: {
|
||||
total_environments: 3,
|
||||
healthy_environments: 2,
|
||||
unhealthy_environments: 1,
|
||||
average_response_time_ms: 1250,
|
||||
total_capacity: 16,
|
||||
total_environments: 0,
|
||||
healthy_environments: 0,
|
||||
unhealthy_environments: 0,
|
||||
average_response_time_ms: 0,
|
||||
total_capacity: 0,
|
||||
used_capacity: activeExecutions.filter(e => e.status === 'running').length
|
||||
},
|
||||
system_resources: {
|
||||
cpu_usage_percent: Math.random() * 30 + 20, // 20-50%
|
||||
memory_usage_percent: Math.random() * 20 + 40, // 40-60%
|
||||
disk_usage_percent: Math.random() * 10 + 65, // 65-75%
|
||||
network_status: 'connected'
|
||||
cpu_usage_percent: 0,
|
||||
memory_usage_percent: 0,
|
||||
disk_usage_percent: 0,
|
||||
network_status: 'disconnected'
|
||||
},
|
||||
performance_metrics: {
|
||||
requests_per_minute: 24,
|
||||
average_response_time_ms: 1250,
|
||||
error_rate_percent: 8.97,
|
||||
uptime_hours: 72.5
|
||||
requests_per_minute: 0,
|
||||
average_response_time_ms: 0,
|
||||
error_rate_percent: 0,
|
||||
uptime_hours: 0
|
||||
}
|
||||
};
|
||||
|
||||
setSystemStats(mockStats);
|
||||
} catch (err) {
|
||||
console.error('加载系统统计失败:', err);
|
||||
setSystemStats(fallbackStats);
|
||||
}
|
||||
}, [activeExecutions]);
|
||||
|
||||
|
||||
@@ -144,50 +144,108 @@ export const WorkflowPage: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleEditEnvironment = (env: WorkflowExecutionEnvironment) => {
|
||||
console.log('编辑环境,接收到的数据:', env);
|
||||
console.log('环境类型:', env.environment_type, '类型:', typeof env.environment_type);
|
||||
setSelectedEnvironment(env);
|
||||
setIsEnvironmentConfiguratorOpen(true);
|
||||
};
|
||||
|
||||
const handleDeleteEnvironment = async (envId: number) => {
|
||||
try {
|
||||
// TODO: 实现删除逻辑
|
||||
// 确认删除
|
||||
const confirmed = window.confirm('确定要删除这个执行环境吗?此操作不可撤销。');
|
||||
if (!confirmed) return;
|
||||
|
||||
console.log('删除执行环境:', envId);
|
||||
await invoke('delete_execution_environment', { id: envId });
|
||||
|
||||
console.log('环境删除成功');
|
||||
// 刷新页面以显示最新数据
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error('删除环境失败:', error);
|
||||
alert(`删除环境失败: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleHealthCheckEnvironment = async (envId: number) => {
|
||||
try {
|
||||
// TODO: 实现健康检查逻辑
|
||||
console.log('健康检查环境:', envId);
|
||||
// 调用健康检查命令
|
||||
const healthStatus = await invoke('health_check_execution_environment', { id: envId });
|
||||
console.log('健康检查完成,状态:', healthStatus);
|
||||
|
||||
// 刷新页面以显示最新的健康状态
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error('健康检查失败:', error);
|
||||
alert(`健康检查失败: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleEnvironmentActive = async (envId: number, isActive: boolean) => {
|
||||
try {
|
||||
// TODO: 实现激活状态切换逻辑
|
||||
console.log('切换环境激活状态:', envId, isActive);
|
||||
const updatedEnvironment = await invoke('update_execution_environment', {
|
||||
id: envId,
|
||||
request: {
|
||||
is_active: isActive
|
||||
}
|
||||
});
|
||||
console.log('激活状态切换成功:', updatedEnvironment);
|
||||
|
||||
// 刷新页面以显示最新状态
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error('切换激活状态失败:', error);
|
||||
alert(`切换激活状态失败: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveEnvironment = async (envData: CreateEnvironmentRequest) => {
|
||||
try {
|
||||
if (selectedEnvironment) {
|
||||
// TODO: 实现更新逻辑
|
||||
// 更新现有环境 - 简化逻辑,直接传递所有字段
|
||||
console.log('更新环境:', envData);
|
||||
const updateRequest = {
|
||||
name: envData.name,
|
||||
description: envData.description,
|
||||
base_url: envData.base_url,
|
||||
api_key: envData.api_key,
|
||||
connection_config_json: envData.connection_config_json,
|
||||
supported_workflow_types: envData.supported_workflow_types,
|
||||
max_concurrent_jobs: envData.max_concurrent_jobs,
|
||||
priority: envData.priority,
|
||||
max_memory_mb: envData.max_memory_mb,
|
||||
max_execution_time_seconds: envData.max_execution_time_seconds,
|
||||
metadata_json: envData.metadata_json,
|
||||
tags: envData.tags,
|
||||
};
|
||||
|
||||
console.log('发送更新请求:', updateRequest);
|
||||
const updatedEnvironment = await invoke('update_execution_environment', {
|
||||
id: selectedEnvironment.id,
|
||||
request: updateRequest
|
||||
});
|
||||
console.log('更新成功,返回数据:', updatedEnvironment);
|
||||
} else {
|
||||
// TODO: 实现创建逻辑
|
||||
// 创建新环境
|
||||
console.log('创建环境:', envData);
|
||||
await invoke('create_execution_environment', { request: envData });
|
||||
}
|
||||
|
||||
setIsEnvironmentConfiguratorOpen(false);
|
||||
setSelectedEnvironment(null);
|
||||
|
||||
// TODO: 添加成功提示
|
||||
console.log('环境保存成功');
|
||||
|
||||
// 刷新页面以显示最新数据(临时方案)
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error('保存环境失败:', error);
|
||||
// TODO: 添加错误提示UI
|
||||
alert(`保存环境失败: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -161,6 +161,15 @@ export interface WorkflowExecutionRecord {
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// 执行历史分页响应接口
|
||||
export interface ExecutionHistoryResponse {
|
||||
records: WorkflowExecutionRecord[];
|
||||
total_count: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
total_pages: number;
|
||||
}
|
||||
|
||||
// 执行环境接口
|
||||
export interface WorkflowExecutionEnvironment {
|
||||
id: number;
|
||||
|
||||
Reference in New Issue
Block a user