REAL SHOWCASE SOURCEitems-control-patient-queue

1 个文件 · 130 行 · TypeScript

// ===== showcase/src/examples/components/items_control.ts ===== import {  RenderBadge,  RenderButton,  RenderItemsControl,  RenderPageHeader,  RenderStackPanel,  RenderText,  RenderWrapPanel,  type ItemContainerState,} from 'ds-ui' interface PatientQueueItem {  id: string  name: string  bed: string  department: string  diagnosis: string  waitMinutes: number  status: 'primary' | 'success' | 'warning' | 'danger'} export function createItemsControlExample(): RenderStackPanel {  const patients = createPatientQueue(2400)  const status = new RenderText('共 2,400 位患者;当前只创建视口附近的项容器。', { role: 'secondary' })  let list!: RenderItemsControl<PatientQueueItem>   list = new RenderItemsControl<PatientQueueItem>({    items: patients,    getKey: patient => patient.id,    height: 440,    spacing: 6,    itemMinHeight: 56,    itemAppearance: 'row',    defaultSelectedItem: patients[0],    virtualization: {      enabled: true,      estimatedItemMainSize: 62,      overscan: 4,    },    itemTemplate: (patient, state) => createPatientRow(patient, state),    onSelectionChange: change => {      const debug = list.debugState()      status.text = `已选择 ${change.item.bed} ${change.item.name};当前物化 ${debug.materializedKeys.length} 项。`    },    onActivate: patient => {      status.text = `已打开 ${patient.name} 的 ${patient.department} 候诊详情。`    },  })   const actions = new RenderWrapPanel({ spacing: 8, runSpacing: 8 })  actions.addChild(new RenderButton({    label: '定位第 500 位',    onClick: () => {      list.scrollToIndex(499, 'center')      status.text = '已定位到第 500 位患者,虚拟项按新的视口范围复用。'    },  }))  actions.addChild(new RenderButton({    label: '定位急诊 1800',    onClick: () => {      list.scrollToKey('patient-1800', 'center')      status.text = '已通过稳定 key 定位到 patient-1800。'    },  }))  actions.addChild(new RenderButton({    label: '回到队首',    onClick: () => {      list.scrollToIndex(0, 'start')      status.text = '已回到队首。'    },  }))   const panel = new RenderStackPanel({ orientation: 'vertical', spacing: 14, crossAxisAlignment: 'stretch' })  panel.addChild(new RenderPageHeader({    title: 'ItemsControl 患者候诊队列',    description: '2,400 条医疗业务卡片使用统一模板、单选、激活与可变高度虚拟化。',  }))  panel.addChild(actions)  panel.addChild(list)  panel.addChild(status)  panel.padding = 24  return panel} function createPatientRow(patient: PatientQueueItem, state: ItemContainerState): RenderStackPanel {  const row = new RenderStackPanel({ orientation: 'horizontal', spacing: 10, crossAxisAlignment: 'center' })  row.addChild(new RenderBadge({    value: patient.bed,    status: state.selected ? 'primary' : patient.status,    compact: true,  }))   const detail = new RenderStackPanel({ orientation: 'vertical', spacing: 3 })  detail.addChild(new RenderText(`${patient.name} · ${patient.diagnosis}`, {    role: state.selected ? 'accent' : 'title',    weight: 'semibold',    overflow: 'ellipsis',  }))  detail.addChild(new RenderText(`${patient.department} · 编号 ${patient.id}`, {    role: 'secondary',    size: 'small',    overflow: 'ellipsis',  }))  row.addChild(detail, 1)  row.addChild(new RenderText(`等待 ${patient.waitMinutes} 分钟`, {    role: patient.waitMinutes >= 45 ? 'accent' : 'secondary',    size: 'small',  }))  return row} function createPatientQueue(count: number): PatientQueueItem[] {  const departments = ['心内科', '呼吸内科', '神经内科', '急诊医学科']  const diagnoses = ['胸闷待查', '肺部感染复诊', '头晕待查', '术后换药']  return Array.from({ length: count }, (_, index) => {    const ordinal = index + 1    const waitMinutes = 6 + (index * 7) % 72    return {      id: `patient-${String(ordinal).padStart(4, '0')}`,      name: `患者 ${String(ordinal).padStart(4, '0')}`,      bed: `${(ordinal % 48) + 1} 号`,      department: departments[index % departments.length]!,      diagnosis: diagnoses[index % diagnoses.length]!,      waitMinutes,      status: waitMinutes >= 60 ? 'danger' : waitMinutes >= 40 ? 'warning' : index % 3 === 0 ? 'success' : 'primary',    }  })}