REAL SHOWCASE SOURCEdata-grid-columns
2 个文件 · 150 行 · TypeScript
// ===== showcase/src/examples/data_grid/columns.ts ===== import { createGridExample } from './shared' export function createColumnsGridExample() { return createGridExample({ title: '列固定、重排与宽度', description: '左侧业务主键保持固定,其余列可以重排、缩放并按内容自动适配。', rowCount: 10000, statusText: '编号和项目名称固定在左侧 · 拖动表头重排列 · 拖动边界调整宽度', })} // ===== showcase/src/examples/data_grid/shared.ts ===== import { RenderButton, RenderDataGrid, RenderPageHeader, RenderSearchBox, RenderStackPanel, RenderText, type GridColumnDef,} from 'ds-ui' export interface DemoRow { id: number project: string owner: string department: string status: 'active' | 'review' | 'paused' progress: number budget: number updatedAt: string} const owners = ['林乔', '周鸣', '陈溪', '顾宁', '唐远', '许安']const departments = ['医疗产品', '数据平台', '企业应用', '基础架构']const statusOptions = [ { value: 'active', label: '进行中' }, { value: 'review', label: '待验收' }, { value: 'paused', label: '已暂停' },] export function createRows(count: number): DemoRow[] { return Array.from({ length: count }, (_, index) => ({ id: index + 1, project: `业务项目 ${String(index + 1).padStart(5, '0')}`, owner: owners[index % owners.length]!, department: departments[index % departments.length]!, status: (['active', 'review', 'paused'] as const)[index % 3]!, progress: (index * 13) % 101, budget: 80000 + (index % 48) * 12500, updatedAt: `2026-${String((index % 12) + 1).padStart(2, '0')}-${String((index % 28) + 1).padStart(2, '0')}`, }))} export const standardColumns: GridColumnDef<DemoRow>[] = [ { type: 'number', key: 'id', title: '编号', width: 76, pinned: 'left', align: 'center', sortable: true }, { type: 'text', key: 'project', title: '项目名称', width: 220, pinned: 'left', editable: true, filterable: true, sortable: true }, { type: 'text', key: 'owner', title: '负责人', width: 110, editable: true, filterable: true, sortable: true }, { type: 'text', key: 'department', title: '所属部门', width: 140, filterable: true, sortable: true }, { type: 'select', key: 'status', title: '状态', width: 110, editable: true, options: statusOptions, filterable: true, sortable: true }, { type: 'number', key: 'progress', title: '进度 %', width: 100, editable: true, min: 0, max: 100, align: 'right', filterable: true, sortable: true }, { type: 'number', key: 'budget', title: '预算', width: 130, editable: true, min: 0, align: 'right', filterable: true, sortable: true }, { type: 'date', key: 'updatedAt', title: '最近更新', width: 132, editable: true, filterable: true, sortable: true },] interface GridExampleOptions { title: string description: string rowCount: number editable?: boolean grouped?: boolean validationActions?: boolean statusText: string} export function createGridExample(options: GridExampleOptions): RenderStackPanel { const status = new RenderText(options.statusText) const grid = new RenderDataGrid<DemoRow>({ rowKey: 'id', columns: standardColumns, rows: createRows(options.rowCount), editable: options.editable ?? false, sortable: true, reorderableColumns: true, resizableColumns: true, autoFitColumns: true, selectionMode: 'range', summary: [ { key: 'id', aggregate: 'count', label: '项目数' }, { key: 'budget', aggregate: 'sum', label: '总预算' }, { key: 'progress', aggregate: 'avg', label: '平均进度' }, ], validateCell: ({ key, value }) => { if (key === 'project' && !String(value ?? '').trim()) return '项目名称不能为空' if (key === 'progress' && (Number(value) < 0 || Number(value) > 100)) return '进度应在 0 到 100 之间' return true }, validateRow: ({ row }) => { if (row.status === 'active' && row.progress === 0) { return { progress: '进行中项目的进度必须大于 0' } } return undefined }, onSelectionChange: event => { status.text = `${event.state.selectedRows.length || 1} 条已选择 · 可继续拖动扩展范围` }, onCellChange: (_row, key) => { status.text = `已保存 ${String(key)} 字段 · 仅刷新当前单元格` }, }) if (options.grouped) grid.groupBy = [{ key: 'status', order: 'asc' }] const search = new RenderSearchBox({ placeholder: '搜索项目、负责人或部门…', onChange: value => grid.setQuickFilter(value), onSearch: value => grid.setQuickFilter(value), }) const content = new RenderStackPanel({ orientation: 'vertical', spacing: 10, crossAxisAlignment: 'stretch' }) content.addChild(new RenderPageHeader({ title: options.title, description: options.description })) content.addChild(search) if (options.validationActions) { const actions = new RenderStackPanel({ orientation: 'horizontal', spacing: 8 }) actions.addChild(new RenderButton({ label: '校验全部数据', variant: 'primary', onClick: () => { const result = grid.validate() if (!result.valid) grid.focusFirstError() status.text = result.valid ? '全部数据校验通过' : `发现 ${result.errors.length} 个输入错误,已定位到第一个可见错误` }, })) actions.addChild(new RenderButton({ label: '清除校验结果', onClick: () => { grid.clearCellErrors() status.text = options.statusText }, })) content.addChild(actions) } content.addChild(grid, 1) content.addChild(status) content.padding = 16 return content}