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', } })}