data-table.md
模式 · PATTERN

数据表格 DataTable

同名但用途不同的数据先用一排小键分区,再进表格。浅灰 mono 表头、可排序列、细线分行;窄屏只横向滚动,不折行。

来源提炼自 AdmDesign 样张 · ui 为源DataTable.jsxextracted.css机读patterns/data-table.md
分区 + 排序点表头排序;再点一次反向
M9PD6RZ4KX1B邀请人丙新学员 C已使用¥200
T2WQ8LN5VJ3C邀请人乙新学员 B可用¥0
G7KM4Q2HP9RX邀请人甲新学员 A已使用¥100
import { useMemo, useState } from 'react'
import { DataTable } from './extracted/DataTable.jsx'
import { StatusPill } from './extracted/Tag.jsx'
import { Btn } from './components/v4/Button.jsx'

const ROWS = [
  { code: 'G7KM4Q2HP9RX', from: '邀请人甲', to: '新学员 A', used: true, reward: 100 },
  { code: 'T2WQ8LN5VJ3C', from: '邀请人乙', to: '新学员 B', used: false, reward: 0 },
  { code: 'M9PD6RZ4KX1B', from: '邀请人丙', to: '新学员 C', used: true, reward: 200 },
]

const COLUMNS = [
  { key: 'code', label: '邀请码', fr: 1.2, mono: true },
  { key: 'from', label: '邀请人', fr: 1.1 },
  { key: 'to', label: '被邀请人', fr: 1.1 },
  { key: 'used', label: '状态', fr: 0.7, render: (r) => <StatusPill tone={r.used ? 'neutral' : 'ok'}>{r.used ? '已使用' : '可用'}</StatusPill> },
  { key: 'reward', label: '奖励', fr: 0.6, mono: true, accent: true, render: (r) => `¥${r.reward}` },
]

export default function DataTableDemo() {
  const [scope, setScope] = useState('register')
  const [sort, setSort] = useState({ key: 'from', dir: 'asc' })
  const rows = useMemo(() => {
    const out = [...ROWS].sort((a, b) => (a[sort.key] > b[sort.key] ? 1 : a[sort.key] < b[sort.key] ? -1 : 0))
    return sort.dir === 'desc' ? out.reverse() : out
  }, [sort])
  const onSort = (key) => setSort((s) => ({ key, dir: s.key === key && s.dir === 'asc' ? 'desc' : 'asc' }))
  return (
    <div style={{ width: '100%', display: 'grid', gap: 12 }}>
      <div style={{ display: 'flex', gap: 8 }}>
        <Btn size="sm" variant={scope === 'register' ? 'primary' : 'paper'} onClick={() => setScope('register')}>注册激活码</Btn>
        <Btn size="sm" variant={scope === 'course' ? 'primary' : 'paper'} onClick={() => setScope('course')}>课程 / 会员激活码</Btn>
      </div>
      <DataTable columns={COLUMNS} rows={rows} sort={sort} onSort={onSort} rowKey={(r) => r.code} />
    </div>
  )
}
静态标记
邀请码邀请人状态奖励
G7KM4Q2HP9RX邀请人甲已使用¥100
import { DataTable } from './extracted/DataTable.jsx'
import { StatusPill } from './extracted/Tag.jsx'

export function Static() {
  return (
    <DataTable
      columns={[
        { key: 'code', label: '邀请码', fr: 1.2, mono: true },
        { key: 'from', label: '邀请人', fr: 1.1 },
        { key: 'state', label: '状态', fr: 0.7, render: (r) => <StatusPill>{r.state}</StatusPill> },
        { key: 'reward', label: '奖励', fr: 0.6, mono: true, accent: true },
      ]}
      rows={[{ code: 'G7KM4Q2HP9RX', from: '邀请人甲', state: '已使用', reward: '¥100' }]}
      minWidth={560}
    />
  )
}

属性

属性取值默认说明
columns[{ key, label, fr?, mono?, accent?, render?, sortable? }][]fr 为列宽份额;mono 用等宽字;accent 用朱色(金额)
rowsobject[][]数据行
sort{ key, dir: 'asc' · 'desc' }当前排序(受控)
onSort(key) => void传了才显示排序键
minWidthnumber680内容最小宽度,窄屏靠横向滚动
rowKey(row, i) => key下标行的 key

规格

表头:内距 10 × 18 · 底 #FAFAF8 · mono 10 · 字距 1 · #A2A29C · 下方 .07 细线。数据行:内距 11 × 18 · 12px · 行间 .07 细线。容器:.09 描边 · 圆角 16。分区键:当前用 sm 墨键,其余 sm 纸键。