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