refactor(sql-console): SqlConsoleTab 改用 SqlResultTable 组件

删除调用方对 Vec<Vec<Value>> → Vec<Vec<String>> 的预处理(保留类型
信息),结果表格段替换为 <SqlResultTable>,空结果集分支保留。
This commit is contained in:
xfy 2026-07-06 11:10:16 +08:00
parent 59edc7c4e4
commit 1db641bca9
2 changed files with 9 additions and 49 deletions

View File

@ -10,7 +10,7 @@ use dioxus::prelude::*;
use crate::api::database::sql_console::SqlResult; use crate::api::database::sql_console::SqlResult;
use crate::components::ui::ADMIN_TABLE_CLASS; use crate::components::ui::ADMIN_TABLE_CLASS;
/// 一行展开详情区中 `<pre>` 的最大高度(超出纵向滚动,避免大 jsonb 撑爆页面)。 /// 一行展开详情区容器的最大高度(超出纵向滚动,避免大 jsonb 撑爆页面)。
const EXPAND_MAX_HEIGHT_CLASS: &str = "max-h-80"; const EXPAND_MAX_HEIGHT_CLASS: &str = "max-h-80";
/// 文本单元格的列宽上限Tailwind 任意值,约束长文本不无限拉伸)。 /// 文本单元格的列宽上限Tailwind 任意值,约束长文本不无限拉伸)。
const TEXT_CELL_MAX_WIDTH_CLASS: &str = "max-w-[24rem]"; const TEXT_CELL_MAX_WIDTH_CLASS: &str = "max-w-[24rem]";

View File

@ -682,6 +682,7 @@ fn SqlConsoleTab() -> Element {
use crate::api::database::sql_console::{execute_sql, ExecuteSqlOpts}; use crate::api::database::sql_console::{execute_sql, ExecuteSqlOpts};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use crate::api::database::schema::get_db_schema; use crate::api::database::schema::get_db_schema;
use crate::components::sql_result_table::SqlResultTable;
use crate::components::ui::ADMIN_TABLE_CLASS; use crate::components::ui::ADMIN_TABLE_CLASS;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use crate::codemirror_bridge; use crate::codemirror_bridge;
@ -874,28 +875,6 @@ fn SqlConsoleTab() -> Element {
.map(|r| r.statement_type.clone()) .map(|r| r.statement_type.clone())
.unwrap_or_default(); .unwrap_or_default();
let truncated = current_result.as_ref().map(|r| r.truncated).unwrap_or(false); let truncated = current_result.as_ref().map(|r| r.truncated).unwrap_or(false);
// 结果行预格式化(避免在 rsx for 循环体内格式化)
let result_rows: Vec<Vec<String>> = current_result
.as_ref()
.map(|r| {
r.rows
.iter()
.map(|row| {
row.iter()
.map(|cell| match cell {
serde_json::Value::Null => "NULL".to_string(),
serde_json::Value::String(s) => s.clone(),
other => other.to_string(),
})
.collect()
})
.collect()
})
.unwrap_or_default();
let result_columns: Vec<String> = current_result
.as_ref()
.map(|r| r.columns.clone())
.unwrap_or_default();
let explain = current_result.as_ref().and_then(|r| r.explain.clone()); let explain = current_result.as_ref().and_then(|r| r.explain.clone());
rsx! { rsx! {
@ -989,34 +968,15 @@ fn SqlConsoleTab() -> Element {
} }
// 结果表格 // 结果表格
if !result_rows.is_empty() { if let Some(res) = &current_result {
div { class: "{ADMIN_TABLE_CLASS}", if !res.rows.is_empty() {
div { class: "overflow-x-auto", SqlResultTable { result: res.clone() }
table { class: "w-full text-sm", } else if res.statement_type.to_uppercase().contains("SELECT") {
thead { // 有结果但无行SELECT 返回空集的友好提示
tr { class: "border-b border-paper-border text-left text-paper-secondary", div { class: "{ADMIN_TABLE_CLASS} px-4 py-8 text-center text-sm text-[var(--color-paper-tertiary)]",
for col in result_columns.iter() { "查询成功,无返回行"
th { class: "px-4 py-2 font-medium whitespace-nowrap", "{col}" }
}
}
}
tbody {
for row in result_rows.iter() {
tr { class: "border-b border-paper-border last:border-0 hover:bg-paper-entry transition-colors",
for cell in row.iter() {
td { class: "px-4 py-2 font-mono text-xs text-paper-secondary", "{cell}" }
}
}
}
}
}
} }
} }
} else if current_result.is_some() && stmt_type.to_uppercase().contains("SELECT") {
// 有结果但无行SELECT 返回空集的友好提示
div { class: "{ADMIN_TABLE_CLASS} px-4 py-8 text-center text-sm text-[var(--color-paper-tertiary)]",
"查询成功,无返回行"
}
} }
// EXPLAIN 输出 // EXPLAIN 输出