REAL SHOWCASE SOURCEcontext-menu-patient-row
1 个文件 · 110 行 · TypeScript
// ===== showcase/src/examples/components/context_menu.ts ===== import { ContextMenuManager, RenderBorder, RenderButton, RenderPageHeader, RenderStackPanel, RenderText, RenderWrapPanel, type ContextMenuEntry,} from 'ds-ui'import type { ShowcaseExample } from '../../showcase_example' export function createContextMenuExample(): ShowcaseExample { const contextMenu = new ContextMenuManager() const status = new RenderText('选择患者后打开“更多操作”,观察分组、禁用、危险项与子菜单。', { role: 'secondary' }) let recordLocked = true let moreButton!: RenderButton const entries = (): ContextMenuEntry[] => [ { key: 'open', label: '打开患者档案', icon: 'folder-open', shortcut: 'Enter' }, { key: 'copy-id', label: '复制门诊号', icon: 'copy', shortcut: 'Ctrl+C' }, { separator: true }, { key: 'status', label: '设置就诊状态', items: [ { key: 'waiting', label: '候诊中' }, { key: 'consulting', label: '接诊中' }, { key: 'completed', label: '已完成' }, ], }, { key: 'assign', label: '转交科室', items: [ { key: 'cardiology', label: '心内科' }, { key: 'respiratory', label: '呼吸内科' }, { key: 'emergency', label: '急诊医学科' }, ], }, { separator: true }, { key: 'archive', label: '归档病历', disabled: recordLocked }, { key: 'delete', label: '删除草稿', danger: true }, ] const labels: Record<string, string> = { open: '已打开患者档案', 'copy-id': '门诊号已复制', waiting: '就诊状态已更新为候诊中', consulting: '就诊状态已更新为接诊中', completed: '就诊状态已更新为已完成', cardiology: '已转交心内科', respiratory: '已转交呼吸内科', emergency: '已转交急诊医学科', archive: '病历已归档', delete: '草稿删除操作已触发', } const openMenu = () => { const offset = moreButton.globalOffset contextMenu.show(entries(), { x: offset.x, y: offset.y + moreButton.size.height + 4 }, key => { status.text = labels[key] ?? `已执行:${key}` }) status.text = `菜单已打开 · ${entries().filter(entry => !('separator' in entry)).length} 个顶层操作` } moreButton = new RenderButton({ label: '更多操作', variant: 'primary', onClick: openMenu, }) const actions = new RenderWrapPanel({ spacing: 10, runSpacing: 10 }) actions.addChild(moreButton) actions.addChild(new RenderButton({ label: '切换病历锁定', onClick: () => { recordLocked = !recordLocked status.text = recordLocked ? '病历已锁定,“归档病历”将保持禁用。' : '病历已解锁,可以执行归档。' }, })) actions.addChild(new RenderButton({ label: '关闭菜单', onClick: () => { contextMenu.hide() status.text = '上下文菜单已关闭。' }, })) const row = new RenderStackPanel({ orientation: 'vertical', spacing: 6, crossAxisAlignment: 'stretch' }) row.addChild(new RenderText('李安然 · OP-20260717-018', { role: 'title', weight: 'semibold' })) row.addChild(new RenderText('心内科 · 09:30 · 复诊', { role: 'secondary' })) row.addChild(actions) const panel = new RenderStackPanel({ orientation: 'vertical', spacing: 18, crossAxisAlignment: 'stretch' }) panel.addChild(new RenderPageHeader({ title: 'ContextMenu 患者操作菜单', description: '同一数据结构表达图标、快捷键提示、禁用、危险操作和多级子菜单。', })) panel.addChild(new RenderBorder({ background: 'muted', padding: 16, child: row })) panel.addChild(status) panel.addChild(new RenderText('菜单打开后可用方向键导航;ArrowRight 进入子菜单,ArrowLeft 返回,Enter 执行,Escape 或 Tab 关闭。', { role: 'secondary' })) panel.padding = 24 return { content: panel, afterMount: openMenu, }}