feat(sql-console): 表头 sticky + 数据行截断 + 点击展开详情
This commit is contained in:
parent
b0833eebf7
commit
59edc7c4e4
@ -62,8 +62,8 @@ fn render_cell(value: &serde_json::Value) -> Element {
|
|||||||
|
|
||||||
/// 渲染展开详情区中的「列名: 完整值」单行。
|
/// 渲染展开详情区中的「列名: 完整值」单行。
|
||||||
///
|
///
|
||||||
/// 与 `render_cell` 不同:值不做截断,长文本由外层 `<pre>` 的
|
/// 与 `render_cell` 不同:值不做截断,长文本换行由外层展开区容器
|
||||||
/// `whitespace-pre-wrap break-all` + `max-h-80 overflow-y-auto` 承载。
|
/// (`whitespace-pre-wrap break-all` + `max-h-80 overflow-y-auto`)承载。
|
||||||
fn render_expanded_value(col: &str, value: &serde_json::Value) -> Element {
|
fn render_expanded_value(col: &str, value: &serde_json::Value) -> Element {
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
let display = match value {
|
let display = match value {
|
||||||
@ -101,12 +101,64 @@ pub struct SqlResultTableProps {
|
|||||||
#[cfg_attr(not(target_arch = "wasm32"), allow(unused_mut))]
|
#[cfg_attr(not(target_arch = "wasm32"), allow(unused_mut))]
|
||||||
pub fn SqlResultTable(props: SqlResultTableProps) -> Element {
|
pub fn SqlResultTable(props: SqlResultTableProps) -> Element {
|
||||||
let mut expanded_row: Signal<Option<usize>> = use_signal(|| None);
|
let mut expanded_row: Signal<Option<usize>> = use_signal(|| None);
|
||||||
|
let cols_len = props.result.columns.len();
|
||||||
|
// colspan = 列数 + 行头箭头列
|
||||||
|
let expand_colspan = cols_len + 1;
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "{ADMIN_TABLE_CLASS}",
|
div { class: "{ADMIN_TABLE_CLASS}",
|
||||||
div { class: "overflow-auto max-h-[70vh]",
|
div { class: "overflow-auto max-h-[70vh]",
|
||||||
table { class: "w-full text-sm border-collapse",
|
table { class: "w-full text-sm border-collapse",
|
||||||
// 占位:后续 task 填充 thead / tbody
|
thead {
|
||||||
|
tr { class: "border-b border-[var(--color-paper-border)] sticky top-0 bg-[var(--color-paper-entry)] z-10",
|
||||||
|
th { class: "w-8 px-2 py-2", "" }
|
||||||
|
for col in props.result.columns.iter() {
|
||||||
|
th {
|
||||||
|
class: "px-4 py-2 text-left font-medium whitespace-nowrap text-[var(--color-paper-secondary)]",
|
||||||
|
"{col}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tbody {
|
||||||
|
for (row_idx, row) in props.result.rows.iter().enumerate() {
|
||||||
|
// 数据行:点击切换展开
|
||||||
|
tr {
|
||||||
|
class: "border-b border-[var(--color-paper-border)] last:border-0 hover:bg-[var(--color-paper-accent-soft)] transition-colors cursor-pointer",
|
||||||
|
onclick: move |_| {
|
||||||
|
let cur = expanded_row();
|
||||||
|
if cur == Some(row_idx) {
|
||||||
|
expanded_row.set(None);
|
||||||
|
} else {
|
||||||
|
expanded_row.set(Some(row_idx));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
td { class: "px-2 py-2 text-center text-[var(--color-paper-tertiary)] text-xs select-none",
|
||||||
|
if expanded_row() == Some(row_idx) { "▾" } else { "▸" }
|
||||||
|
}
|
||||||
|
for cell in row.iter() {
|
||||||
|
td {
|
||||||
|
class: "px-4 py-2 align-top",
|
||||||
|
{render_cell(cell)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 展开详情行(跨列)
|
||||||
|
if expanded_row() == Some(row_idx) {
|
||||||
|
tr {
|
||||||
|
td { colspan: "{expand_colspan}",
|
||||||
|
class: "px-4 py-3 bg-[var(--color-paper-theme)]",
|
||||||
|
div {
|
||||||
|
class: "{EXPAND_MAX_HEIGHT_CLASS} overflow-y-auto space-y-0.5 whitespace-pre-wrap break-all",
|
||||||
|
for (ci, col) in props.result.columns.iter().enumerate() {
|
||||||
|
{render_expanded_value(col, row.get(ci).unwrap_or(&serde_json::Value::Null))}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user