界面 SDK
所有 Nexus 应用共用的一套界面,外观与 shadcn/ui 一致、取值与 AIDC Console 同源。纯 HTML 应用引一个样式表就有全部组件;需要脚本的部分(主题、Toast、确认框、标签页、加载动效)在 aidc.js 的 ui 里。
<link rel="stylesheet" href="/developer/sdk/v1/ui.css" />
<script type="module">
import { ui } from "/developer/sdk/v1/aidc.js";
ui.toast("已保存", { variant: "success" });
</script>
页面
顶栏
appbar应用最上面一条:标识、应用名、右侧操作。吸顶、半透明毛玻璃。
<header class="aidc-appbar">
<span class="aidc-logo"><svg class="aidc-mark" viewBox="0 0 40 40" fill="currentColor" aria-hidden="true"><g transform="translate(20 20) skewX(-18)"><rect x="-9.6" y="-15" width="6.6" height="30"/><rect x="3" y="-15" width="6.6" height="30"/></g></svg><span>AIDC</span></span>
<span class="aidc-appbar__title">瑕疵检测</span>
<div class="aidc-appbar__actions">
<span class="aidc-badge aidc-badge--signal">测试版</span>
<button type="button" class="aidc-btn aidc-btn--ghost aidc-btn--sm">反馈</button>
</div>
</header>
版面
layout页面容器(最大宽度 + 留白)、竖排 / 横排间距、次要文字。不用 Tailwind 也能排版。
今日产线
数据每 30 秒同步一次。
<main class="aidc-page aidc-page--narrow">
<div class="aidc-stack">
<h1>今日产线</h1>
<p class="aidc-muted">数据每 30 秒同步一次。</p>
<div class="aidc-row">
<button type="button" class="aidc-btn">开始检测</button>
<button type="button" class="aidc-btn aidc-btn--outline">导出</button>
</div>
</div>
</main>
操作
按钮
button主按钮是实心黑(signal 主题下是信号橙);次要、描边、幽灵、危险、链接五种变体,三种尺寸与图标按钮。
<div class="aidc-row">
<button type="button" class="aidc-btn">发布</button>
<button type="button" class="aidc-btn aidc-btn--secondary">保存草稿</button>
<button type="button" class="aidc-btn aidc-btn--outline">预览</button>
<button type="button" class="aidc-btn aidc-btn--ghost">取消</button>
<button type="button" class="aidc-btn aidc-btn--destructive">删除</button>
<a class="aidc-btn aidc-btn--link" href="#">查看说明</a>
</div>
<div class="aidc-row">
<button type="button" class="aidc-btn aidc-btn--sm">小</button>
<button type="button" class="aidc-btn">默认</button>
<button type="button" class="aidc-btn aidc-btn--lg">大</button>
<button type="button" class="aidc-btn aidc-btn--outline aidc-btn--icon" aria-label="刷新"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-3-6.7L21 8"/><path d="M21 3v5h-5"/></svg></button>
<button type="button" class="aidc-btn" disabled><span class="aidc-loader" data-variant="dial" role="status" aria-label="Loading"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span>提交中</button>
</div>
标签页
tabs同一块区域里切换几组内容。标记写好后调 ui.tabs(容器) 接管点击与方向键。
<div class="aidc-tabs" id="orderTabs">
<div class="aidc-tabs__list" role="tablist" aria-label="订单">
<button type="button" class="aidc-tabs__trigger" role="tab" id="tab-open" aria-controls="panel-open" aria-selected="true">进行中</button>
<button type="button" class="aidc-tabs__trigger" role="tab" id="tab-done" aria-controls="panel-done" aria-selected="false">已完成</button>
</div>
<div class="aidc-tabs__panel" role="tabpanel" id="panel-open" aria-labelledby="tab-open">3 张工单进行中。</div>
<div class="aidc-tabs__panel" role="tabpanel" id="panel-done" aria-labelledby="tab-done" hidden>本周完成 18 张。</div>
</div>
ui.tabs("#orderTabs", { onChange: (panelId) => console.log(panelId) });
对话框
dialog原生 <dialog>。确认与输入用 ui.confirm / ui.prompt(代替 window.confirm / prompt),复杂内容自己写标记后 showModal()。
<div class="aidc-row">
<button type="button" class="aidc-btn aidc-btn--destructive" data-demo="confirm">删除工单</button>
<button type="button" class="aidc-btn aidc-btn--outline" data-demo="prompt">标记问题</button>
<button type="button" class="aidc-btn aidc-btn--outline" data-demo="custom-dialog">自定义对话框</button>
</div>
<dialog class="aidc-dialog" id="custom">
<form method="dialog" class="aidc-stack">
<div class="aidc-dialog__header">
<h2 class="aidc-dialog__title">发布到 Nexus</h2>
<p class="aidc-dialog__description">发布后全公司成员都能打开这个版本。</p>
</div>
<div class="aidc-dialog__footer">
<button type="submit" value="cancel" class="aidc-btn aidc-btn--outline">取消</button>
<button type="submit" value="confirm" class="aidc-btn">发布</button>
</div>
</form>
</dialog>
if (await ui.confirm({ title: "删除这张工单?", description: "删除后不能恢复。", confirmText: "删除", destructive: true })) { /* … */ }
const reason = await ui.prompt({ title: "标记问题", label: "问题描述", placeholder: "例如:布面污渍", required: true });
document.querySelector("#custom").showModal();
表单
输入框
input单行输入;手机上字号 16px(iOS 不会自动放大)。出错时加 aria-invalid="true"。
<input class="aidc-input" type="text" placeholder="批次号,例如 B-2026-0926" />
<input class="aidc-input" type="email" placeholder="错误示例" aria-invalid="true" value="not-an-email" />
<input class="aidc-input" type="file" />
多行输入
textarea多行文本,可纵向拉伸。
<textarea class="aidc-textarea" rows="3" placeholder="写下这次检查的备注…"></textarea>
下拉选择
select原生 <select>,弹出层由系统负责(手机上是系统选择器)。
<select class="aidc-select">
<option>一号产线</option>
<option>二号产线</option>
<option>三号产线</option>
</select>
复选框
checkbox原生 <input type="checkbox">,外观与 shadcn 一致。
<label class="aidc-label"><input type="checkbox" class="aidc-checkbox" checked /> 发布后通知全员</label>
单选框
radio原生 <input type="radio">。
<div class="aidc-stack" style="gap: 0.75rem">
<label class="aidc-label"><input type="radio" class="aidc-radio" name="shift" checked /> 白班</label>
<label class="aidc-label"><input type="radio" class="aidc-radio" name="shift" /> 夜班</label>
</div>
开关
switch原生复选框加 role="switch":开 / 关一项设置。
<label class="aidc-label"><input type="checkbox" role="switch" class="aidc-switch" checked /> 实时同步</label>
标签
label表单项的文字标签;包住复选框 / 单选框 / 开关时自动横排对齐。
<label class="aidc-label" for="qty">数量</label>
表单项
field标签 + 控件 + 说明 / 错误提示的一组。
印在料盒侧面,以 B- 开头。
批次号不能为空。
<div class="aidc-field">
<label class="aidc-label" for="batch">批次号</label>
<input class="aidc-input" id="batch" aria-invalid="true" aria-describedby="batch-error" />
<p class="aidc-field__description">印在料盒侧面,以 B- 开头。</p>
<p class="aidc-field__error" id="batch-error">批次号不能为空。</p>
</div>
展示
卡片
card一组相关内容的容器:标题、说明、右上角操作、正文、底部操作。
今日良率
一号产线 · 截至 14:30
+1.2%<div class="aidc-card" style="max-width: 24rem">
<div class="aidc-card__header">
<h3 class="aidc-card__title">今日良率</h3>
<p class="aidc-card__description">一号产线 · 截至 14:30</p>
<span class="aidc-card__action aidc-badge aidc-badge--success">+1.2%</span>
</div>
<div class="aidc-card__content"><strong style="font-size: 2rem">98.4%</strong></div>
<div class="aidc-card__footer">
<button type="button" class="aidc-btn aidc-btn--outline aidc-btn--sm">明细</button>
</div>
</div>
徽章
badge状态与标签。信号橙只用于需要注意的状态。
<div class="aidc-row">
<span class="aidc-badge">已发布</span>
<span class="aidc-badge aidc-badge--secondary">草稿</span>
<span class="aidc-badge aidc-badge--outline">v1.2.0</span>
<span class="aidc-badge aidc-badge--success">合格</span>
<span class="aidc-badge aidc-badge--signal">待复核</span>
<span class="aidc-badge aidc-badge--destructive">不合格</span>
</div>
表格
table数据表:外面包一层 .aidc-table-wrap 就能横向滚动;数字列加 .aidc-num 右对齐、等宽数字。
| 工单 | 产线 | 状态 | 数量 |
|---|---|---|---|
| WO-1041 | 一号 | 完成 | 1,200 |
| WO-1042 | 二号 | 待复核 | 860 |
| WO-1043 | 三号 | 排产 | 2,400 |
| 合计 | 4,460 | ||
<div class="aidc-table-wrap">
<table class="aidc-table">
<thead><tr><th>工单</th><th>产线</th><th>状态</th><th class="aidc-num">数量</th></tr></thead>
<tbody>
<tr><td>WO-1041</td><td>一号</td><td><span class="aidc-badge aidc-badge--success">完成</span></td><td class="aidc-num">1,200</td></tr>
<tr><td>WO-1042</td><td>二号</td><td><span class="aidc-badge aidc-badge--signal">待复核</span></td><td class="aidc-num">860</td></tr>
<tr><td>WO-1043</td><td>三号</td><td><span class="aidc-badge aidc-badge--secondary">排产</span></td><td class="aidc-num">2,400</td></tr>
</tbody>
<tfoot><tr><td colspan="3">合计</td><td class="aidc-num">4,460</td></tr></tfoot>
</table>
</div>
头像
avatar圆形头像;没有图片时放姓氏或缩写。
<div class="aidc-row"><span class="aidc-avatar">郭</span><span class="aidc-avatar">李</span><span class="aidc-avatar">AI</span></div>
按键
kbd快捷键提示。
<span class="aidc-muted">按 <kbd class="aidc-kbd">⌘</kbd> <kbd class="aidc-kbd">K</kbd> 搜索</span>
分隔线
separator横向用 <hr>;在横排里用竖向变体。
<div class="aidc-stack">
<span>上半部分</span>
<hr class="aidc-separator" />
<div class="aidc-row" style="height: 1.25rem">
<span>产线</span><span class="aidc-separator aidc-separator--vertical"></span><span>班次</span>
</div>
</div>
标识
logoAIDC 标识(棱角版双斜杠,logo 橙 #FF4D00)与字标。除了标识本身,界面里不要再用 // 做装饰。
<span class="aidc-logo" style="font-size: 1.5rem"><svg class="aidc-mark" viewBox="0 0 40 40" fill="currentColor" aria-hidden="true"><g transform="translate(20 20) skewX(-18)"><rect x="-9.6" y="-15" width="6.6" height="30"/><rect x="3" y="-15" width="6.6" height="30"/></g></svg><span>AIDC</span></span>
document.querySelector("header").prepend(ui.logo()); // ui.logo({ wordmark: false }) 只要标识
空状态
empty没有数据时告诉用户为什么、下一步做什么。
还没有工单
ERP 同步过来的工单会出现在这里。
<div class="aidc-empty">
<div class="aidc-empty__media"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7h18M3 12h18M3 17h18"/></svg></div>
<h3 class="aidc-empty__title">还没有工单</h3>
<p class="aidc-empty__description">ERP 同步过来的工单会出现在这里。</p>
<button type="button" class="aidc-btn aidc-btn--outline aidc-btn--sm">立即同步</button>
</div>
反馈
提示条
alert页面里的常驻提示;出错用 destructive。
<div class="aidc-alert" role="status">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
<div class="aidc-alert__title">数据源在线</div>
<div class="aidc-alert__description">ERP 发布端 2 分钟前心跳正常。</div>
</div>
<div class="aidc-alert aidc-alert--destructive" role="alert">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg>
<div class="aidc-alert__title">连不上数据源</div>
<div class="aidc-alert__description">发布端已 10 分钟没有心跳,页面上的数据可能不是最新的。</div>
</div>
Toast
toast操作结果的轻提示,几秒后自动消失(悬停暂停)。只用 ui.toast(),不用手写标记。
<div class="aidc-row">
<button type="button" class="aidc-btn aidc-btn--outline" data-demo="toast">已保存</button>
<button type="button" class="aidc-btn aidc-btn--outline" data-demo="toast-error">保存失败</button>
<button type="button" class="aidc-btn aidc-btn--outline" data-demo="toast-action">带撤销</button>
</div>
ui.toast("已保存", { variant: "success" });
ui.toast("保存失败", { variant: "error", description: "网络断开,稍后重试。" });
ui.toast("已删除 1 条记录", { action: { label: "撤销", onClick: undo } });
加载动效
loader八种等待态都以品牌斜杆 // 为母题(dial 刻度轮、cadence 节拍、sequence 递进、sweep 掠光、march 行进、pulse 韵律、breathe 呼吸、track 轨道),按场景选、同一界面不混用;大小跟字号,颜色跟 --signal。
<div class="aidc-row" style="gap: 1.5rem; font-size: 1.5rem">
<span class="aidc-loader" data-variant="dial" role="status" aria-label="Loading"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span>
<span class="aidc-loader" data-variant="cadence" role="status" aria-label="Loading"><i></i><i></i></span>
<span class="aidc-loader" data-variant="sequence" role="status" aria-label="Loading"><i></i><i></i></span>
<span class="aidc-loader" data-variant="sweep" role="status" aria-label="Loading"><i></i><i></i></span>
<span class="aidc-loader" data-variant="march" role="status" aria-label="Loading"><span data-slot="train"><i></i><i></i><i></i><i></i><i></i></span></span>
<span class="aidc-loader" data-variant="pulse" role="status" aria-label="Loading"><i></i><i></i></span>
<span class="aidc-loader" data-variant="breathe" role="status" aria-label="Loading"><i></i><i></i></span>
<span style="font-size: 1rem"><span class="aidc-loader" data-variant="track" role="status" aria-label="Loading"><span data-slot="lane"><span data-slot="runner"><i></i><i></i></span></span></span></span>
</div>
button.prepend(ui.loader("dial")); // 刻度轮
panel.append(ui.loader("cadence", { label: "加载订单" }));
骨架屏
skeleton内容加载前的占位形状。
<div class="aidc-row" style="gap: 0.75rem">
<div class="aidc-skeleton" style="width: 2.5rem; height: 2.5rem; border-radius: 9999px"></div>
<div class="aidc-stack" style="gap: 0.5rem">
<div class="aidc-skeleton" style="width: 12rem; height: 1rem"></div>
<div class="aidc-skeleton" style="width: 8rem; height: 1rem"></div>
</div>
</div>
进度条
progress原生 <progress>:有明确进度的等待。
<progress class="aidc-progress" value="62" max="100">62%</progress>