optimize ui loading and dashboard performance
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Alert, Badge, Button } from './ui.jsx';
|
||||
|
||||
const selectedBlue = '#2563EB';
|
||||
@@ -55,7 +56,7 @@ export function Panel({ title, aside, children, className = '' }) {
|
||||
|
||||
export function ApiNotice({ loading, error, onRetry }) {
|
||||
if (loading) {
|
||||
return <Alert title="正在读取真实 API">正在从 LisgloSIPS API 拉取页面数据。</Alert>;
|
||||
return null;
|
||||
}
|
||||
if (error) {
|
||||
return (
|
||||
@@ -68,6 +69,32 @@ export function ApiNotice({ loading, error, onRetry }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function PageLoadingDialog({ loading, message = '页面加载中,请稍候…', delay = 2000 }) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
setVisible(false);
|
||||
return undefined;
|
||||
}
|
||||
const timer = window.setTimeout(() => setVisible(true), delay);
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [delay, loading]);
|
||||
|
||||
if (!visible) return null;
|
||||
return (
|
||||
<div className="page-loading-backdrop" role="status" aria-live="polite" aria-label={message}>
|
||||
<div className="page-loading-dialog">
|
||||
<span className="page-loading-spinner" aria-hidden="true" />
|
||||
<div>
|
||||
<strong>{message}</strong>
|
||||
<span>正在读取真实业务数据,请不要重复刷新。</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function EmptyState({ title = '暂无数据', children = '当前筛选条件下没有可展示的数据。' }) {
|
||||
return (
|
||||
<div className="empty-state">
|
||||
@@ -139,10 +166,10 @@ export function StatusBadge({ children }) {
|
||||
return <Badge tone={toneForStatus(children)}>{children}</Badge>;
|
||||
}
|
||||
|
||||
export function SimpleTable({ columns, rows, onRowClick, selectedKey }) {
|
||||
export function SimpleTable({ columns, rows, onRowClick, selectedKey, loading = false, emptyTitle = '暂无数据', emptyDescription }) {
|
||||
return (
|
||||
<div className="table-shell">
|
||||
<table className="proto-table">
|
||||
<table className="proto-table" aria-busy={loading}>
|
||||
{columns.some((column) => column.width) ? (
|
||||
<colgroup>
|
||||
{columns.map((column) => <col key={column.key} style={column.width ? { width: column.width } : undefined} />)}
|
||||
@@ -154,10 +181,14 @@ export function SimpleTable({ columns, rows, onRowClick, selectedKey }) {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.length === 0 ? (
|
||||
{loading && rows.length === 0 ? Array.from({ length: 4 }, (_, rowIndex) => (
|
||||
<tr className="table-skeleton-row" key={`skeleton-${rowIndex}`} aria-hidden="true">
|
||||
{columns.map((column) => <td key={column.key}><span className="table-skeleton-cell" /></td>)}
|
||||
</tr>
|
||||
)) : rows.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={columns.length}>
|
||||
<EmptyState />
|
||||
<EmptyState title={emptyTitle}>{emptyDescription}</EmptyState>
|
||||
</td>
|
||||
</tr>
|
||||
) : rows.map((row, index) => (
|
||||
|
||||
Reference in New Issue
Block a user