iter(g103): 区分表格两种空状态
This commit is contained in:
@@ -5,19 +5,21 @@ import {
|
||||
selectionPlugin,
|
||||
sortPlugin,
|
||||
} from '@ui-arch/table-core';
|
||||
import type { PageInfo, RowKey, TableInstance } from '@ui-arch/table-core';
|
||||
import type { RowKey } from '@ui-arch/table-core';
|
||||
import { computed, effect, h, renderList, signal } from '@ui-arch/frame';
|
||||
import { attachResize } from './columnResize.js';
|
||||
import { exportButton } from './csv.js';
|
||||
import { button } from './button.js';
|
||||
import { skeleton } from './skeleton.js';
|
||||
import { textField } from './textField.js';
|
||||
import type { DataTableProps } from './types.js';
|
||||
import { emptyRow } from './tableEmpty.js';
|
||||
import type { DataTableProps, TableApi } from './types.js';
|
||||
|
||||
/*** 数据表格:粘性表头 + 行选择 + 排序 + 筛选 + 分页 + 空状态;状态由 table-core 持有,信号只做桥接渲染 ***/
|
||||
export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): HTMLElement {
|
||||
// —— 状态集中声明 ——
|
||||
const selectable = props.selectable ?? false; // 行选择开关
|
||||
const keyword = signal(''); // 筛选框关键字:受控信号,空状态里的「清除筛选」靠它一键还原
|
||||
const table = createTable({
|
||||
data: props.data,
|
||||
columns: props.columns,
|
||||
@@ -25,10 +27,7 @@ export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): H
|
||||
plugins: [filterPlugin<T>(), sortPlugin<T>(), paginationPlugin<T>(), selectionPlugin<T>()],
|
||||
initialState: { pagination: { page: 1, pageSize: props.pageSize ?? 5 } },
|
||||
});
|
||||
const api = table as unknown as TableInstance<T> & {
|
||||
getPageInfo(): PageInfo;
|
||||
selectAllVisible(): void;
|
||||
};
|
||||
const api = table as unknown as TableApi<T>; // 用到的两个取数方法在类型别名里声明
|
||||
const version = signal(0); // 桥接信号:table-core 订阅通知 → 递增触发信号系统
|
||||
table.subscribe(() => version(version() + 1));
|
||||
|
||||
@@ -142,9 +141,7 @@ export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): H
|
||||
if (busy()) return skeletonRows(); // 加载态优先:不看数据,避免闪出旧行
|
||||
const sel = state().selection; // 读入依赖:选择变化即整表重绘(行数 = pageSize,代价可控)
|
||||
const rows = visible().rows;
|
||||
if (!rows.length) {
|
||||
return [h('tr', { class: 'ua-empty-row' }, h('td', { colspan }, '暂无匹配数据'))];
|
||||
}
|
||||
if (!rows.length) return [emptyRow(colspan, keyword, () => table.dispatch({ type: 'setFilter', key: filterKey, value: '' }))]; // 空状态:筛选词与内核筛选一起清
|
||||
return rows.map((row, i) => {
|
||||
const key = visible().keys[i];
|
||||
const selected = sel.includes(key);
|
||||
@@ -170,6 +167,7 @@ export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): H
|
||||
const filterInput = textField({
|
||||
placeholder: `筛选 ${filterKey}…`,
|
||||
prefix: '🔍',
|
||||
value: keyword, // 受控信号:空状态里的「清除筛选」能同时清掉输入框内容
|
||||
disabled: props.loading, // 加载中禁止筛选,避免与在途结果竞争
|
||||
onInput: (value) => {
|
||||
table.dispatch({ type: 'setFilter', key: filterKey, value });
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { h } from '@ui-arch/frame';
|
||||
import type { Signal } from '@ui-arch/frame';
|
||||
import { button } from './button.js';
|
||||
|
||||
/*** 表格空状态行:有筛选词说明是筛掉的并给一键清除,没有筛选词就是真没数据;两种语义不该混成一句话 ***/
|
||||
export function emptyRow(colspan: number, keyword: Signal<string>, onClear: () => void): HTMLElement {
|
||||
const q = keyword().trim(); // 读信号:筛选词变化时整表重绘会带上新文案
|
||||
return h(
|
||||
'tr',
|
||||
{ class: 'ua-empty-row' },
|
||||
h(
|
||||
'td',
|
||||
{ colspan },
|
||||
h('span', { class: 'ua-empty-tip' }, q ? `没有符合「${q}」的行` : '暂无数据'),
|
||||
q ? button({ label: '清除筛选', variant: 'ghost', onClick: () => { keyword(''); onClear(); } }) : null, // 清空信号与内核筛选
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ColumnDef, RowKey } from '@ui-arch/table-core';
|
||||
import type { ColumnDef, PageInfo, RowKey, TableInstance } from '@ui-arch/table-core';
|
||||
import type { Signal } from '@ui-arch/frame';
|
||||
|
||||
/*** 悬浮提示入参 ***/
|
||||
@@ -679,6 +679,9 @@ export interface SpaceProps {
|
||||
block?: boolean; // 是否占满父容器宽度;缺省按内容收缩
|
||||
}
|
||||
|
||||
/*** 表格扩展接口:table-core 实例 + 皮肤层用到的两个取数方法 ***/
|
||||
export type TableApi<T> = TableInstance<T> & { getPageInfo(): PageInfo; selectAllVisible(): void };
|
||||
|
||||
/*** 锚点导航项 ***/
|
||||
export interface AnchorItem {
|
||||
href: string; // 目标区块地址(#id);对应元素须存在于页面上
|
||||
|
||||
@@ -195,6 +195,10 @@ body.ua-col-resizing {
|
||||
color: var(--ua-color-text-muted);
|
||||
padding: 28px 12px;
|
||||
}
|
||||
.ua-empty-tip {
|
||||
display: inline-block;
|
||||
margin-right: var(--ua-space-2);
|
||||
}
|
||||
.ua-table-scroll {
|
||||
max-height: 420px;
|
||||
overflow: auto;
|
||||
|
||||
Reference in New Issue
Block a user