/** * 能力演示卡片的定义结构 * - title: 卡片标题 * - desc: 能力说明 * - actions: 该卡片下的操作按钮列表 */ export interface DemoAction { /** 按钮文字 */ label: string; /** 是否使用次要样式(灰色按钮) */ secondary?: boolean; /** 点击后执行的处理函数,返回要展示的文本 */ run: (ctx: DemoContext) => Promise | string; } /** 卡片定义 */ export interface DemoCard { /** 卡片唯一 id,用于关联输出区域 */ id: string; /** 卡片标题 */ title: string; /** 卡片说明文字 */ desc: string; /** 是否需要一个文本输入框 */ input?: { placeholder: string; default?: string }; /** 操作按钮 */ actions: DemoAction[]; } /** 传递给操作函数的上下文,可读取输入框内容 */ export interface DemoContext { /** 获取当前卡片输入框的值(不存在时返回空字符串) */ getInput: () => string; } /** * 渲染单个能力卡片到指定容器 * @param container 卡片挂载的父节点 * @param card 卡片定义 * 注意事项:按钮点击时会自动捕获异常并以红色输出错误信息,避免未处理的 Promise 报错。 */ export function renderCard(container: HTMLElement, card: DemoCard): void { const el = document.createElement("section"); el.className = "card"; const inputHtml = card.input ? `
` : ""; el.innerHTML = `

${card.title}

${card.desc}

${inputHtml}
`; container.appendChild(el); const out = el.querySelector(`#out-${card.id}`)!; const actionsRow = el.querySelector(`#actions-${card.id}`)!; const ctx: DemoContext = { getInput: () => el.querySelector(`#input-${card.id}`)?.value ?? "", }; for (const action of card.actions) { const btn = document.createElement("button"); btn.textContent = action.label; if (action.secondary) btn.classList.add("secondary"); btn.addEventListener("click", async () => { out.className = "output"; out.textContent = "执行中…"; try { out.textContent = await action.run(ctx); out.classList.add("ok"); } catch (err) { out.textContent = `出错:${err instanceof Error ? err.message : String(err)}`; out.classList.add("err"); } }); actionsRow.appendChild(btn); } }