为需求而生,为通用立命,让组件变成任何你想要的样子~
📌 先说清楚:Ones 万能组件是 E10 表单组件,不是 EB 页面组件。
它从表单设计器的组件管理创建,拖入的是表单设计器,不是 e-builder 页面设计器。因为它运行在表单页面里,所以能拿到表单上下文,才能读写当前表单的字段。
界面


为什么做这个组件
做过泛微 E10 表单二开的人大概都遇到过这种需求:
- 表单里要一张「Safe / Positive vs Unsafe / Negative」的双卡片选择器;
- 要一个指标卡、时间轴、步骤面板、特殊的联动说明块;
- 要一段完全自定义的 HTML 布局,但必须读写当前表单字段;
- 每个需求都写一次 ecode、发一次版,周期长、复用低;
- 直接写 EB 页面组件,又拿不到表单字段上下文,或者把表单页面搞得很重。
平台的标准表单组件很稳,但形态是固定的;自定义 HTML 的自由和表单字段的契约,一直是两件事。
Ones 万能组件想做的,是把这两件事合起来:管理员只配一个单文件 HTML,字段读写、只读、必填、初始值、明细、错误兜底由组件桥接层负责。
它长什么样
配置面板只有 4 项:
- 组件代码(单文件 HTML):可以写
<div>...</div><style>...</style><script>...</script>,也可以粘完整 HTML 文档; - 运行 JS:关闭后只渲染 HTML/CSS,不执行脚本;
- 调试模式:显示脚本错误和字段解析提示;
- AI 生成(高级):默认折叠;展开后填需求 + 字段清单,一键生成并复制提示词。
AI 闭环:
写需求 → 生成并复制提示词 → 粘给任意 AI → AI 返回一个 HTML 代码块 → 粘回「组件代码」→ 保存 → 预览提示词由组件内置模板生成,包含运行环境约束、字段规则、ctx API、data-ufc-*、输出格式和自检清单。AI 不需要知道 WeFormSDK、formStore 的差异。
核心设计:一个代码框 + 一层薄契约
1. 单文件 HTML,Shadow DOM 渲染
组件把 HTML 归一化后放进 Shadow DOM,CSS 天然隔离,不污染表单页面;脚本只执行一次,字段变化只更新绑定,不重跑整段代码。
- 设计态:只静态渲染 HTML/CSS,不执行脚本;
- 运行态:执行脚本,通过
ctx读写字段; - 打印态:不执行脚本,保留静态骨架和绑定值;
- 只读态:
ctx.set被拦截。
2. ctx 字段桥接
AI 代码只面向这一层:
ctx.get('字段') // 原值ctx.text('字段') // 显示文本(人员/选项自动取名称)ctx.set('字段', '值') // 写值ctx.attr('字段') // { readOnly, required, hidden, editable }ctx.on('字段', fn) // 字段值变化ctx.onAttr('字段', fn) // 只读/必填/隐藏变化ctx.onBeforeSave(fn) // 保存前校验ctx.rows('明细表') // 明细行ctx.request(...) // 平台统一请求底层优先取 window.WeFormSDK.getWeFormInstance(),不可用时降级 props.formStore。AI 只写 ctx,兼容性由组件负责。
3. 声明式绑定 data-ufc-*
常见展示/输入不写 JS:
<span data-ufc-text="客户名称" data-ufc-empty="—"></span><input data-ufc-input="备注" /><button data-ufc-if-edit="客户名称">同步</button><span data-ufc-if-required="客户名称">*</span>字段值变化、属性变化、联动/钻取后,绑定自动刷新。
4. 字段状态与初始值
- 只读:输入禁用、
data-ufc-if-edit隐藏、ctx.set拒绝; - 必填:
data-ufc-if-required显示*,ctx.onBeforeSave兜底; - 隐藏:相关 UI 不渲染;
- 关联/浏览/选项字段:用
text()显示名称,空值时显示占位; - 初始值只从运行数据读取,不写死示例;等表单就绪后刷新,联动/钻取后自动更新。
5. 明细字段必须带 rowId
这是实测踩出来的坑:主表字段 mark 是 field{fieldId},明细字段是 field{fieldId}_{rowId}。明细字段不带 rowId 写值,会把所有行写成同一个值。
桥接层现在强制要求 rowId,缺失直接抛错;ctx.rows('明细表') 负责拿行数据。
6. 固定选项:显示名与写值
固定选项的 getFieldObj().specialObj[].name 可能是空的,显示名要从字段 options 按 selectionId/valueKey 映射。
写值也有坑:有些字段认 valueKey(比如 0/1/2),有些认 selectionId;写错时 store 变了但原生下拉不刷新。组件内部提示词和文档都要求:写值前用 ctx.obj / 字段配置确认可识别值,写入后检查原生控件是否显示。
一个真实示例:Observation Type
V1 仓库里带了一个示例 examples/observation-type.html:
- 绑定字段:
Observation Type,数据 keyobstyp; Positive (0)/Negative (1);- 点击整张卡片写入并同步勾选;
- 只读/隐藏/打印态不响应;
- 样式保持原稿:双列卡片、彩色头部、圆形图标、勾选状态、底部双语提示,无外边框;
- 为了 Shadow DOM 只做了必要映射:
:root→:host,body→.ufc-root。
效果就是一张「Safe / Positive vs Unsafe / Negative」的选择卡片,选中项显示绿色/红色勾选,另一侧是灰色空心圆。
V1 实测结果
已在 E10 目标环境验证:
- Shadow DOM 渲染、
data-ufc-*; - 字段读写、只读拦截;
- 固定选项显示名与
valueKey写值; - 明细
ctx.rows、明细字段带rowId写入; - 缺
rowId抛错; - 保存前校验阻断 + 正常保存放行;
- 配置保存/重开;
- hook 去重(保存/字段/属性/动作);
- AI 提示词生成。
未完成:打印模板场景、整表单只读、真实移动端 H5、超大配置体积、多实例压力。
安全边界
组件会执行管理员配置的 JS,信任边界等同平台「页面源码 / 表单 ecode」。不要把它开放给不可信的低权限编辑者;正式发布前按你们的 ecode-security-review 流程确认直出/沙箱策略。
字段值、用户输入、接口返回永远不要拼进 HTML 字符串或 eval;用 textContent / ctx.text。
源码与版本
- GitHub:https://github.com/OnesZhang/e10-ones-ufc
- Release:https://github.com/OnesZhang/e10-ones-ufc/releases/tag/v1.0.0
- 示例:
examples/observation-type.html - 文档:
docs/architecture.md、docs/ai-prompt.md、docs/test-report.md
v1.0.0(2026-10-21):首个版本。
为需求而生,为通用立命,让组件变成任何你想要的样子~
—— Ones