fix: 修复配置页面无法输入 + 添加关机按钮
This commit is contained in:
16
src/api.rs
16
src/api.rs
@@ -20,8 +20,8 @@ pub struct ApiResponse<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ProxmoxClient {
|
impl ProxmoxClient {
|
||||||
pub fn new(host: &str, token_id: &str, token_secret: &str) -> Self {
|
pub fn new(host: &str, port: u16, token_id: &str, token_secret: &str) -> Self {
|
||||||
let base_url = format!("https://{}:8006/api2/json", host);
|
let base_url = format!("https://{}:{}/api2/json", host, port);
|
||||||
Self {
|
Self {
|
||||||
client: reqwest::Client::builder()
|
client: reqwest::Client::builder()
|
||||||
.danger_accept_invalid_certs(true)
|
.danger_accept_invalid_certs(true)
|
||||||
@@ -77,4 +77,16 @@ impl ProxmoxClient {
|
|||||||
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
|
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
|
||||||
self.start_vm(node, vm_id).await
|
self.start_vm(node, vm_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn shutdown_node(&self, node: &str) -> Result<(), String> {
|
||||||
|
let url = format!("{}/nodes/{}/status", self.base_url, node);
|
||||||
|
self.client
|
||||||
|
.post(&url)
|
||||||
|
.header("Authorization", self.auth_header())
|
||||||
|
.json(&serde_json::json!({"command": "shutdown"}))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
52
src/gui.rs
52
src/gui.rs
@@ -103,7 +103,7 @@ impl AppState {
|
|||||||
let config = Config::load();
|
let config = Config::load();
|
||||||
|
|
||||||
let client = if !config.host.is_empty() && !config.token_id.is_empty() && !config.token_secret.is_empty() {
|
let client = if !config.host.is_empty() && !config.token_id.is_empty() && !config.token_secret.is_empty() {
|
||||||
let c = ProxmoxClient::new(&config.host, &config.token_id, &config.token_secret);
|
let c = ProxmoxClient::new(&config.host, config.port, &config.token_id, &config.token_secret);
|
||||||
Arc::new(Mutex::new(Some(c)))
|
Arc::new(Mutex::new(Some(c)))
|
||||||
} else {
|
} else {
|
||||||
Arc::new(Mutex::new(None))
|
Arc::new(Mutex::new(None))
|
||||||
@@ -240,9 +240,10 @@ impl eframe::App for App {
|
|||||||
|
|
||||||
// 控制按钮
|
// 控制按钮
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let btn_start = ui.add(egui::Button::new("▶ 启动").min_size(Vec2::new(80.0, 32.0)));
|
let btn_start = ui.add(egui::Button::new("▶ 启动").min_size(Vec2::new(70.0, 32.0)));
|
||||||
let btn_stop = ui.add(egui::Button::new("■ 停止").min_size(Vec2::new(80.0, 32.0)));
|
let btn_stop = ui.add(egui::Button::new("■ 停止").min_size(Vec2::new(70.0, 32.0)));
|
||||||
let btn_refresh = ui.add(egui::Button::new("↻ 刷新").min_size(Vec2::new(80.0, 32.0)));
|
let btn_refresh = ui.add(egui::Button::new("↻ 刷新").min_size(Vec2::new(70.0, 32.0)));
|
||||||
|
let btn_shutdown = ui.add(egui::Button::new("🔴 关机").min_size(Vec2::new(70.0, 32.0)));
|
||||||
|
|
||||||
let vm_id_start = st.vm_id;
|
let vm_id_start = st.vm_id;
|
||||||
let node_start = st.node.clone();
|
let node_start = st.node.clone();
|
||||||
@@ -256,6 +257,10 @@ impl eframe::App for App {
|
|||||||
let node_refresh = st.node.clone();
|
let node_refresh = st.node.clone();
|
||||||
let client_refresh = st.client.clone();
|
let client_refresh = st.client.clone();
|
||||||
|
|
||||||
|
let client_shutdown = st.client.clone();
|
||||||
|
let node_shutdown = st.node.clone();
|
||||||
|
let state_shutdown = state.clone();
|
||||||
|
|
||||||
if btn_start.clicked() {
|
if btn_start.clicked() {
|
||||||
let client = client_start.clone();
|
let client = client_start.clone();
|
||||||
let node = node_start.clone();
|
let node = node_start.clone();
|
||||||
@@ -330,6 +335,29 @@ impl eframe::App for App {
|
|||||||
state.write().unwrap().add_log(&msg);
|
state.write().unwrap().add_log(&msg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if btn_shutdown.clicked() {
|
||||||
|
let client = client_shutdown.clone();
|
||||||
|
let node = node_shutdown.clone();
|
||||||
|
let state = state_shutdown.clone();
|
||||||
|
st.add_log("正在执行关机流程...");
|
||||||
|
st.add_log("1. 停止所有虚拟机...");
|
||||||
|
ctx.request_repaint();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
// 先停止所有运行的虚拟机
|
||||||
|
let _ = rt.block_on(async {
|
||||||
|
// 获取节点上所有虚拟机
|
||||||
|
let client = client.lock().unwrap();
|
||||||
|
if let Some(c) = client.as_ref() {
|
||||||
|
// 发送关闭节点命令
|
||||||
|
c.shutdown_node(&node).await.ok();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state.write().unwrap().add_log("2. 正在关闭 Proxmox 主机...");
|
||||||
|
state.write().unwrap().add_log("关机命令已发送");
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
@@ -352,8 +380,8 @@ impl eframe::App for App {
|
|||||||
let show_settings = st.show_settings;
|
let show_settings = st.show_settings;
|
||||||
let mut host = st.host.clone();
|
let mut host = st.host.clone();
|
||||||
let mut port = st.port;
|
let mut port = st.port;
|
||||||
|
let mut token_id = st.token_id.clone();
|
||||||
let mut token_secret = st.token_secret.clone();
|
let mut token_secret = st.token_secret.clone();
|
||||||
let token_id = st.token_id.clone();
|
|
||||||
let state_clone = state.clone();
|
let state_clone = state.clone();
|
||||||
|
|
||||||
drop(st);
|
drop(st);
|
||||||
@@ -362,7 +390,7 @@ impl eframe::App for App {
|
|||||||
egui::Window::new("设置")
|
egui::Window::new("设置")
|
||||||
.collapsible(false)
|
.collapsible(false)
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.min_size(Vec2::new(350.0, 300.0))
|
.min_size(Vec2::new(350.0, 320.0))
|
||||||
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
|
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
ui.set_width(320.0);
|
ui.set_width(320.0);
|
||||||
@@ -389,15 +417,15 @@ impl eframe::App for App {
|
|||||||
ui.add(egui::DragValue::new(&mut port).range(1..=65535).speed(1));
|
ui.add(egui::DragValue::new(&mut port).range(1..=65535).speed(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Token ID 输入
|
// 令牌ID 输入
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Token ID:");
|
ui.label("令牌ID:");
|
||||||
ui.text_edit_singleline(&mut token_id.clone());
|
ui.text_edit_singleline(&mut token_id);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Token Secret 输入(密码框)
|
// 密钥 输入(密码框)
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Token Secret:");
|
ui.label("密钥:");
|
||||||
ui.add(egui::TextEdit::singleline(&mut token_secret).password(true));
|
ui.add(egui::TextEdit::singleline(&mut token_secret).password(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -415,7 +443,7 @@ impl eframe::App for App {
|
|||||||
state.token_id = tid.clone();
|
state.token_id = tid.clone();
|
||||||
state.token_secret = ts.clone();
|
state.token_secret = ts.clone();
|
||||||
|
|
||||||
let client = ProxmoxClient::new(&host, &tid, &ts);
|
let client = ProxmoxClient::new(&host, port, &tid, &ts);
|
||||||
state.client = Arc::new(Mutex::new(Some(client)));
|
state.client = Arc::new(Mutex::new(Some(client)));
|
||||||
state.is_connected = true;
|
state.is_connected = true;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user