mirror of
https://github.com/mztlive/dx-admin-template.git
synced 2025-12-22 21:59:59 +00:00
FIX STYLE
This commit is contained in:
@@ -78,6 +78,12 @@
|
||||
transform 0.2s ease;
|
||||
}
|
||||
|
||||
.ui-button-content {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.ui-button[data-size="sm"] {
|
||||
height: 2rem;
|
||||
padding: 0 0.75rem;
|
||||
@@ -1402,6 +1408,89 @@
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
/* Data Table - Interactive Table */
|
||||
.ui-data-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ui-data-table-toolbar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 0.75rem 0;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.ui-data-table-columns {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ui-data-table-columns-trigger svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ui-data-table-columns-popover {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.5rem);
|
||||
right: 0;
|
||||
min-width: 200px;
|
||||
padding: 0.5rem;
|
||||
background-color: hsl(var(--popover));
|
||||
border: 1px solid hsl(var(--border));
|
||||
border-radius: calc(var(--radius));
|
||||
box-shadow: var(--shadow-lg);
|
||||
z-index: 50;
|
||||
animation: fadeIn 0.15s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-0.5rem);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-data-table-columns-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.625rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
color: hsl(var(--foreground));
|
||||
cursor: pointer;
|
||||
border-radius: calc(var(--radius) - 4px);
|
||||
transition: background-color 0.15s ease;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ui-data-table-columns-option:hover {
|
||||
background-color: hsl(var(--muted) / 0.5);
|
||||
}
|
||||
|
||||
.ui-data-table-columns-option span {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ui-data-table-empty {
|
||||
padding: 3rem 1rem;
|
||||
text-align: center;
|
||||
color: hsl(var(--muted-foreground));
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.ui-data-table-checkbox-cell {
|
||||
width: 48px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.ui-table-row.is-selected {
|
||||
background-color: hsl(var(--muted) / 0.5);
|
||||
}
|
||||
|
||||
.ui-calendar {
|
||||
border: 1px solid hsl(var(--border));
|
||||
border-radius: calc(var(--radius) - 2px);
|
||||
|
||||
@@ -4,9 +4,9 @@ use std::{
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use super::{utils::merge_class, Button, ButtonSize, ButtonVariant};
|
||||
use crate::components::ui::Checkbox;
|
||||
use dioxus::prelude::*;
|
||||
use super::utils::merge_class;
|
||||
#[component]
|
||||
pub fn Table(#[props(into, default)] class: Option<String>, children: Element) -> Element {
|
||||
let classes = merge_class("ui-table", class);
|
||||
@@ -249,30 +249,53 @@ pub fn InteractiveTable(
|
||||
rsx! {
|
||||
div {
|
||||
class: wrapper_class,
|
||||
onclick: {
|
||||
let mut open = columns_menu_open.clone();
|
||||
move |_| {
|
||||
if open() {
|
||||
open.set(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
div {
|
||||
class: "ui-data-table-toolbar",
|
||||
if !toggleable_columns.is_empty() {
|
||||
div {
|
||||
class: "ui-data-table-columns",
|
||||
onfocusout: {
|
||||
let mut open = columns_menu_open.clone();
|
||||
move |_| open.set(false)
|
||||
},
|
||||
button {
|
||||
Button {
|
||||
variant: ButtonVariant::Outline,
|
||||
size: ButtonSize::Sm,
|
||||
class: "ui-data-table-columns-trigger",
|
||||
"data-open": if columns_menu_open() { "true" } else { "false" },
|
||||
onclick: {
|
||||
on_click: {
|
||||
let mut open = columns_menu_open.clone();
|
||||
move |_| {
|
||||
move |evt: MouseEvent| {
|
||||
evt.stop_propagation();
|
||||
let next = !open();
|
||||
open.set(next);
|
||||
}
|
||||
},
|
||||
"列显隐"
|
||||
svg {
|
||||
width: "16",
|
||||
height: "16",
|
||||
view_box: "0 0 24 24",
|
||||
fill: "none",
|
||||
stroke: "currentColor",
|
||||
stroke_width: "2",
|
||||
stroke_linecap: "round",
|
||||
stroke_linejoin: "round",
|
||||
rect { x: "3", y: "3", width: "7", height: "7" }
|
||||
rect { x: "14", y: "3", width: "7", height: "7" }
|
||||
rect { x: "14", y: "14", width: "7", height: "7" }
|
||||
rect { x: "3", y: "14", width: "7", height: "7" }
|
||||
}
|
||||
"列控制"
|
||||
}
|
||||
if columns_menu_open() {
|
||||
div {
|
||||
class: "ui-data-table-columns-popover",
|
||||
onclick: move |evt| {
|
||||
evt.stop_propagation();
|
||||
},
|
||||
for column in toggleable_columns.iter() {
|
||||
{
|
||||
let column_id = column.id.clone();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::components::ui::{
|
||||
Avatar, Badge, BadgeVariant, Button, ButtonSize, ButtonVariant, Card, CardContent,
|
||||
CardDescription, CardFooter, CardHeader, CardTitle, CheckboxChipGroup, CheckboxChipOption,
|
||||
DateRange, DateRangePicker, Input, Label, Pagination, Popover, Select, SelectOption, Slider,
|
||||
Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, ToggleGroup,
|
||||
ToggleGroupItem, ToggleGroupMode,
|
||||
DateRange, DateRangePicker, Input, InteractiveTable, Label, Pagination, Popover, Select,
|
||||
SelectOption, Slider, Table, TableBody, TableCaption, TableCell, TableColumnConfig,
|
||||
TableFooter, TableHead, TableHeader, TableRow, TableRowData,
|
||||
};
|
||||
use chrono::NaiveDate;
|
||||
use dioxus::prelude::*;
|
||||
@@ -948,6 +948,134 @@ pub fn Orders() -> Element {
|
||||
span { class: "orders-metric-sub", "调整筛选条件或清除限制重新查看。" }
|
||||
}
|
||||
} else {
|
||||
// 示例1:基础表格
|
||||
h3 { style: "margin-top: 1rem;", "1. 基础表格 (Table)" }
|
||||
Table {
|
||||
TableCaption { "订单数据表格" }
|
||||
TableHeader {
|
||||
TableRow {
|
||||
TableHead { "订单号" }
|
||||
TableHead { "客户" }
|
||||
TableHead { "状态" }
|
||||
TableHead { "金额" }
|
||||
}
|
||||
}
|
||||
TableBody {
|
||||
for order in paginated_orders.iter().take(3).cloned() {
|
||||
TableRow {
|
||||
TableCell { "{order.number}" }
|
||||
TableCell { "{order.customer_name}" }
|
||||
TableCell {
|
||||
Badge { variant: order.status.badge(), "{order.status.label()}" }
|
||||
}
|
||||
TableCell { {format!("¥{:.2}", order.total)} }
|
||||
}
|
||||
}
|
||||
}
|
||||
TableFooter {
|
||||
TableRow {
|
||||
TableCell { "总计 (前3项)" }
|
||||
TableCell { }
|
||||
TableCell { }
|
||||
TableCell {
|
||||
{
|
||||
let total: f32 = paginated_orders.iter().take(3).map(|o| o.total).sum();
|
||||
format!("¥{:.2}", total)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 示例2:InteractiveTable with 行选择 + 列可见性控制
|
||||
h3 { style: "margin-top: 2rem;", "2. 高级数据表格 (InteractiveTable) - 行选择 + 列切换" }
|
||||
{
|
||||
let mut selected_rows = use_signal(|| std::collections::HashSet::<String>::new());
|
||||
let selected_count = selected_rows().len();
|
||||
|
||||
let columns = vec![
|
||||
TableColumnConfig {
|
||||
id: "number".to_string(),
|
||||
label: "订单号".to_string(),
|
||||
toggleable: false,
|
||||
visible_by_default: true,
|
||||
},
|
||||
TableColumnConfig {
|
||||
id: "customer".to_string(),
|
||||
label: "客户".to_string(),
|
||||
toggleable: true,
|
||||
visible_by_default: true,
|
||||
},
|
||||
TableColumnConfig {
|
||||
id: "date".to_string(),
|
||||
label: "日期".to_string(),
|
||||
toggleable: true,
|
||||
visible_by_default: true,
|
||||
},
|
||||
TableColumnConfig {
|
||||
id: "status".to_string(),
|
||||
label: "状态".to_string(),
|
||||
toggleable: true,
|
||||
visible_by_default: true,
|
||||
},
|
||||
TableColumnConfig {
|
||||
id: "payment".to_string(),
|
||||
label: "支付".to_string(),
|
||||
toggleable: true,
|
||||
visible_by_default: true,
|
||||
},
|
||||
TableColumnConfig {
|
||||
id: "channel".to_string(),
|
||||
label: "渠道".to_string(),
|
||||
toggleable: true,
|
||||
visible_by_default: false,
|
||||
},
|
||||
TableColumnConfig {
|
||||
id: "total".to_string(),
|
||||
label: "金额".to_string(),
|
||||
toggleable: true,
|
||||
visible_by_default: true,
|
||||
},
|
||||
];
|
||||
|
||||
let rows: Vec<TableRowData> = paginated_orders
|
||||
.iter()
|
||||
.map(|order| {
|
||||
let mut cells = std::collections::HashMap::new();
|
||||
cells.insert("number".to_string(), order.number.clone());
|
||||
cells.insert("customer".to_string(), format!("{} ({})", order.customer_name, order.customer_email));
|
||||
cells.insert("date".to_string(), order.placed_on.format("%Y-%m-%d").to_string());
|
||||
cells.insert("status".to_string(), order.status.label().to_string());
|
||||
cells.insert("payment".to_string(), order.payment_status.label().to_string());
|
||||
cells.insert("channel".to_string(), order.channel.label().to_string());
|
||||
cells.insert("total".to_string(), format!("¥{:.2}", order.total));
|
||||
TableRowData {
|
||||
id: order.number.clone(),
|
||||
cells,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
rsx! {
|
||||
div { style: "margin-bottom: 0.5rem;",
|
||||
span { style: "font-size: 0.875rem; color: var(--muted-foreground);",
|
||||
"已选择 {selected_count} 行"
|
||||
}
|
||||
}
|
||||
InteractiveTable {
|
||||
columns: columns,
|
||||
rows: rows,
|
||||
default_selected: Some(vec![]),
|
||||
empty_state: Some("没有数据".to_string()),
|
||||
on_selection_change: move |_selected: Vec<String>| {
|
||||
// 选中的订单回调
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 示例3:完整功能表格 (原始设计)
|
||||
h3 { style: "margin-top: 2rem;", "3. 完整功能表格" }
|
||||
Table {
|
||||
TableHeader {
|
||||
TableRow {
|
||||
|
||||
Reference in New Issue
Block a user