恢复点(restore point)。别人改崩后可 git reset --hard 回到此提交。 == 此快照内容 == - 后端 oa-backend: 734 控制器 / 711 实体 (Spring Boot 3.2.5 + SQLite, 端口8091) - 前端 modern-ui/app: Vue3+Vite, 约700页 (构建产物已在 oa-backend/src/main/resources/static) - 数据库 oa-backend/data/oa.db: 含全部演示数据 (强制入库, 6.6MB) - 交接文档 go.md + go-code-reference/endpoints/entities/database.md - 多代理建设脚本 .claude/wf-*.js == 状态 == - 对 凯迪科技ERP_20260507.xlsx 合规 MET ~73.3% (PARTIAL 75: 34可建+6种子/bug+35外部硬天花板) - 安全: 5轮红队+5轮复检, default-deny分级鉴权, 连续零可利用 - W3~W7 累计补完436缺口; W8末轮(40缺口)为半成品(源码树可编译但未集成) - 运行: cd oa-backend; java -jar build/libs/oa-backend-0.1.0.jar --server.port=8091; admin/123456 == 排除(gitignore, 可再生) == node_modules / oa-backend/build / .jdks / *.log / Backup-ERP-* / 弃用的OFBiz核心(只保留modern-ui) 完整文件夹备份见同目录 Backup-ERP-20260615-191517/ (含上述全部, 仅缺 node_modules) 时间戳: 20260615-191517 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 KiB
OFBiz Modern UI 使用手册
定位
plugins/modern-ui 是 OFBiz 现代管理端的生产 UI。目标界面是 /modern/app/ 下的管理员工作台、领域管理页、业务操作页和系统维护页,服务对象是每天处理订单、库存、财务、客户、内容、系统维护等任务的后台操作员。
本手册说明如何用 Vue 3、Element Plus 和 ERP wrapper 构建 OFBiz 管理端。原有 FreeMarker、widget XML、controller XML 和 service XML 是元数据来源、兼容路由和回退依据;生产页面要面向业务操作员,使用订单、商品、客户、财务、库存、履约、采购、人事、内容、POS、电商、系统维护等业务语言。
/Users/qiu/Desktop/ERP/element-plus-lab 可以作为样式试验来源,但不能作为 modern-ui 的产品目标。生产 UI 的入口、样式、组件调用和验收边界都以本目录代码为准。
代码入口
| 关注点 | 文件 |
|---|---|
| 应用启动、Element Plus 注册、全局图标注册、全局样式导入 | plugins/modern-ui/app/src/main.ts |
| Hash 路由、登录门禁、视图选择、业务页参数传递 | plugins/modern-ui/app/src/App.vue |
| 侧栏、顶栏、全局命令、快捷动作、会话身份 | plugins/modern-ui/app/src/components/erp/ErpAppShell.vue |
| 模块目录、模块路由、标签、图标、业务前缀、快捷页、工作流 | plugins/modern-ui/app/src/data/moduleCatalog.ts |
| 领域管理页模板 | plugins/modern-ui/app/src/components/erp/ErpDomainAdminView.vue |
生成业务页路由 #/pages/:pageId |
plugins/modern-ui/app/src/views/BusinessPageView.vue |
PageDefinition block 渲染、页面动作、回执 |
plugins/modern-ui/app/src/components/erp/ErpPageRenderer.vue |
| 非普通 form/table/action block 的适配与 workspace 分发 | plugins/modern-ui/app/src/components/erp/ErpAdapterBlock.vue |
| ERP wrapper 组件 | plugins/modern-ui/app/src/components/erp/*.vue |
| API、action、lookup、option、entity rows、fallback 数据 | plugins/modern-ui/app/src/services/api.ts, plugins/modern-ui/app/src/services/fallback.ts |
| 共享类型 | plugins/modern-ui/app/src/types/api.ts |
| 标签清洗和业务文案格式化 | plugins/modern-ui/app/src/utils/display.ts, plugins/modern-ui/app/src/utils/erpMetadata.ts |
| 样式入口 | plugins/modern-ui/app/src/styles/erp-ui.css, plugins/modern-ui/app/src/styles/modern.css |
| 设计变量、Element Plus 覆盖、ERP 可复用模式 | plugins/modern-ui/app/src/styles/tokens.css, plugins/modern-ui/app/src/styles/element-overrides.css, plugins/modern-ui/app/src/styles/erp-patterns.css |
| 生成页面 JSON | plugins/modern-ui/app/public/generated, plugins/modern-ui/webapp/modern/app/generated |
应用入口只导入一次全局样式:
import './styles/erp-ui.css'
import './styles/modern.css'
业务视图不要重复导入 Element Plus CSS,不要在页面内重新定义主题变量,也不要自建第二套视觉体系。
全局样式入口
erp-ui.css 是可复用 ERP 视觉系统入口,顺序为:
- Element Plus 官方 CSS。
tokens.css:颜色、字号、间距、圆角、阴影、边框等全局变量。base.css:基础页面和元素规则。element-overrides.css:Element Plus 变量映射和窄范围覆盖。erp-patterns.css:ERP 表单、表格、状态、上传、lookup、菜单、详情、分页、空状态等可复用类。
modern.css 负责管理端 shell、领域页、生成业务页和少量页面级布局。规则归属如下:
- 改颜色、字号、间距、圆角、阴影:优先改
tokens.css。 - 改 Element Plus 全局变量或基础组件密度:放在
element-overrides.css。 - 可复用 ERP 模式:放在
erp-patterns.css。 - 某个页面或某类业务页的布局:放在
modern.css,使用明确的页面或 block class。 - 组件私有且不可复用的小范围布局:留在组件
<style scoped>,但避免硬编码主题值。
不要在业务页面里散落一次性颜色、深层选择器、任意 padding、超出 8px 的圆角或装饰性阴影。页面章节应是工作区域,不要做卡片套卡片。
Token 和密度契约
生产样式以 tokens.css 为唯一变量来源:
| 维度 | Token / 规则 |
|---|---|
| 主色 | --erp-color-primary 用于全局导航、主按钮、选中态和可操作焦点 |
| 状态色 | success 表示完成/健康/已连接,warning 表示待处理/需复核/后台处理中,danger 表示错误/拒绝/取消/删除,info 表示中性元数据 |
| 字号 | 24px 页面标题,18px 大面板标题,14px 正文和主要控件,13px 紧凑文本,12px 标签和元数据 |
| 间距 | 全站使用 4px grid:--erp-space-1 到 --erp-space-8 |
| 控件高度 | 标准 32px,紧凑 28px,大控件 36px |
| 圆角 | 常规 4px / 6px,上限 8px |
| 阴影 | 后台工作区默认不用装饰阴影,只在浮层或确需层级时使用 |
| 表格 | 表头/行高 34px,cell 垂直 padding 5px,横向 padding 8px |
element-overrides.css 只把 Element Plus 变量映射到 ERP token,不承载业务页面布局。erp-patterns.css 承载可复用的 .erp-table、.erp-dense-pagination、.erp-status-tag、.erp-state-line、.erp-work-area、.erp-form--search、.erp-form--entity、.erp-action-stack 等模式。
样式依赖规则
业务页只能走以下路径:
Element Plus primitive -> ERP wrapper / ERP pattern -> 业务页面
- 表单、表格、动作、状态、lookup、上传、抽屉、审计优先调用 wrapper。
- 没有 wrapper 时,先复用
erp-patterns.css中的模式类;确实缺失时补窄 pattern,再让页面使用。 modern.css只放 shell、领域页和生成页的布局组合,不新增颜色体系、字号体系、阴影体系或按钮体系。<style scoped>只能处理组件私有排版,且必须引用 token;不能散写主题色、任意圆角、装饰阴影或深层覆盖 Element Plus。- 业务页面不得重复手写 form/table/action/status/lookup/upload/detail drawer/audit timeline 的样式组合。
按钮层级
- 每个工作区最多一个 primary action;其余为 default / link / text。
- 删除、取消、移除、拒绝等危险动作使用 danger,并在高风险动作前加确认。
- 普通动作区最多展示 4 个动作,紧凑动作区最多 2 个,其余进入
更多。 - 表格行操作使用 link button,短标签优先:查看、审计、编辑、打开。
- 成功、失败、不可执行、需人工处理等结果必须留在工作区内;toast 只能补充。
Element Plus 与 ERP Wrapper
生产页面采用:
Element Plus primitive -> ERP wrapper / ERP pattern -> OFBiz business page
直接使用 Element Plus 的场景:
el-tabs:同一业务对象的不同表面,如总览、数据、动作、流程、审计、权限。el-menu:页面内子导航或横向菜单。el-alert、el-empty、el-skeleton:loading、empty、permission、unavailable、error、success receipt。el-descriptions、el-timeline:只读事实和历史,但优先由 wrapper 承载。el-dialog、el-popconfirm:短确认、短阻塞表单、危险动作确认。el-button、el-tag:局部小控件,且没有对应业务 wrapper 时。
业务对象优先使用 wrapper:
| 业务需要 | 使用 |
|---|---|
| 管理端 shell、全局导航、会话 | ErpAppShell |
| 标题、说明、面包屑、头部动作 | ErpPageHeader |
| 查询、筛选、报表参数 | ErpSearchForm |
| 新建、编辑、维护表单 | ErpEntityForm |
| 业务列表、实体表、分页、排序、行详情 | ErpDataTable |
| 保存、提交、审批、取消、导出、打印等动作 | ErpActionBar |
| 业务状态、队列状态、回执状态 | ErpStatusTag |
| Party/Product/Order 等实体查找 | ErpLookup |
| 行详情、审计、附件、权限上下文侧检 | ErpDrawer |
| 审计历史 | ErpAuditTimeline |
| 附件、媒体、导入文件 | ErpUpload, ErpMediaWorkspace |
| 生成页面 block 渲染 | ErpPageRenderer |
| 非普通 form/table/action 的生成 block | ErpAdapterBlock |
| 领域流程工作台 | ErpOrderWorkspace, ErpFinanceWorkspace, ErpInventoryWorkspace, ErpProcurementWorkspace, ErpCatalogWorkspace, ErpPartyWorkspace, ErpContentWorkspace, ErpSystemWorkspace, ErpCommerceSurface, ErpPosWorkspace 等 |
如果一个业务视图重复手写 form、table、action bar、status tag、lookup、upload、detail drawer 或 audit timeline,应该改为调用 wrapper,或在 components/erp 新增窄 wrapper 后再复用。
当前覆盖事实
截至 2026-06-09 的审计口径:
- 1772 个 legacy view route 映射到 1767 个 unique
PageDefinition,有 5 个重复 route alias。 - 1767 个 split PageDefinition JSON 文件位于
plugins/modern-ui/webapp/modern/app/generated/pages。 ErpPageRenderer/ErpAdapterBlock结构支持 1767 个生成页,当前没有 unsupported block type。- 553 个 table block 都有 data-source contract,其中 505 个 entity-backed,48 个 derived/report/history。
- 1409 个 form block 都有 submit/read contract,其中 602 个 service-ready,146 个 event-ready,369 个 navigation-action,其余为 readonly、dynamic、local、navigation-target 或 preserved unmapped target。
- 当前 verification 截图目录有 112 张 PNG;这不是全量 1767 页浏览器截图。
- 当前 parity artifact 只有 4 个 Accounting 页面 runtime smoke 通过;它不能代表全域 E2E parity。
- 当前浏览器运行时验收使用本地 Google Chrome + CDP fallback;
browser-runtime-report.json对http://127.0.0.1:8080/modern/app/通过,截图为plugins/modern-ui/verification/browser-runtime-admin.png。 - Codex in-app browser /
iab当前不可用,根因为agent.browsers.get('iab') -> Browser is not available: iab。不要把iab不可用解释为 Modern UI 失败,也不要无限重试;按 Chrome/CDP 验证链路处理。 - 1721 个页面仍是 pending business E2E,876 个是 high-risk pending 页面。
这组事实只允许声明“结构覆盖/renderer 覆盖/contract 覆盖已建立”。不要在产品文案、PR、交付说明或验收报告里写“full parity complete”、“全量业务等价完成”或类似结论。
Wrapper 使用边界
生成页默认由 BusinessPageView -> ErpPageRenderer -> ErpAdapterBlock 承载。只有在以下情况才新增或扩展 dedicated Vue/workspace:
- 页面需要跨多个实体编排流程,而不是单个 form/table/action block。
- 需要真实业务状态机、步骤条、异常交接、审计、上传、导入、导出、PDF/CSV/print、POS/cart/payment、report output 等行为。
- legacy 页面依赖复杂 JavaScript、FreeMarker/Groovy 模板语义或多请求副作用,metadata renderer 只能保留结构。
- 同一领域已有 workspace 可复用,如
ErpFinanceWorkspace、ErpOrderWorkspace、ErpProcurementWorkspace、ErpContentWorkspace、ErpPosWorkspace、ErpBirtReportingWorkspace、ErpSystemWorkspace。
不要为了单个普通 legacy form/table 复制一套页面结构。先把元数据送进 wrapper;当 E2E 证明 metadata renderer 无法表达业务行为时,再把那段行为提升成窄 workspace 或 wrapper。
表单规则
查询、筛选、报表参数和生成 legacy form block 使用 ErpSearchForm:
<ErpSearchForm
:fields="formBlock.fields"
:submit-action="formBlock.submitAction"
:initial-values="routePayload"
@submit="handleSubmit"
@reset="handleReset"
@update:model="mergePayload"
/>
新建、编辑、维护业务对象使用 ErpEntityForm:
<ErpEntityForm
:fields="editBlock.fields"
:submit-action="editBlock.submitAction"
:initial-values="currentRecord"
@submit="handleSubmit"
@update:model="mergePayload"
/>
表单布局规则:
- 搜索表单使用四列密集网格,编辑表单使用两列;抽屉或窄面板内使用一列。
- 身份字段优先:party、product、order、invoice、payment、facility、content、work effort、employee 等。
- 只读事实用
el-descriptions或.erp-detail-descriptions,不要用 disabled form 假装详情。 ErpSearchForm当前最多展示 16 个可见字段,ErpEntityForm当前最多展示 24 个可见字段。需要更多字段时分组、分 tab 或高级区,不要绕过 wrapper。- hidden、ignored、submit widget 不作为普通输入控件显示。
- disabled、readonly、requires-login、contract-only、backend-only 等状态必须可见并有业务含义,不要直接隐藏整块表单。
Select、Radio、Lookup 与 Option
来自 OFBiz widget XML 的 drop-down、select、radio 必须继续使用生成元数据,不要在业务页面手写 <el-select> options。
选择控件的三类数据契约:
field.options: 静态 <option key="" description=""> 值
field.optionSources[type=entity-options]: 动态 <entity-options> 来源
field.optionSources[type=list-options]: 旧 list-options 上下文,等待页面数据注入
ErpSearchForm 和 ErpEntityForm 通过 fieldOptions.ts 合并静态选项和远程 entity options。实体选项调用:
GET /api/v1/options/:entityName
?keyFieldName=geoId
&description=${geoName} [${geoId}]
&constraint=geoTypeId:STATE
&pageSize=60
lookup 规则:
- Party、Product、OrderHeader 或可推断实体引用使用
ErpLookup。 - 描述性文本可以用普通 input;实体身份字段不要用自由文本代替 lookup。
- lookup 数据通过
services/api.ts#getLookup获取。 - lookup 弹层、autocomplete、选中值展示不要在业务页重复手写。
上传规则:
- 普通字段上传由表单 wrapper 的 file widget 或
ErpUpload承载。 - 媒体资产、内容关联、审核工作流使用
ErpMediaWorkspace。 - 上传、导入、PDF、CSV、print、export 都属于业务验收敏感路径,不能只验证页面可渲染。
表格和列表
业务列表使用 ErpDataTable:
<ErpDataTable
:columns="tableBlock.fields"
:rows="tableBlock.rows"
:data-source="tableBlock.dataSource"
/>
数据契约示例:
{ type: 'entity', entityName: 'Party', endpoint: '/api/v1/entities/Party' }
{ type: 'derived', derivedType: 'report-list', reason: '需要进入对应业务流程后加载数据' }
ErpDataTable 负责:
- provided rows 和 remote entity rows。
- 搜索、刷新、服务端排序、分页。
- 默认 page size 20,可选 10 / 20 / 50 / 100。
- 默认最多 12 个可见列。
- hidden、ignored、submit widget 不显示为列。
amount、total、price等金额列右对齐。status类列用ErpStatusTag。- 固定右侧操作列,短动作如
查看、审计。 - 420px 详情抽屉,显示
el-descriptions和审计时间线。 - loading、empty、unavailable、error、derived/fallback 状态。
当用户需要扫描、排序、比较、分页或执行行级动作时,不要用装饰卡片替代表格。空数据必须解释业务状态:当前条件无匹配记录、权限不足、会话缺失、服务不可用、或数据需要进入业务流程后加载。
动作和按钮
页面动作使用 ErpActionBar:
<ErpActionBar
:actions="page.actions"
:payload="pagePayload"
@executed="setActionResult"
/>
动作规则:
- 一个区域只保留一个 primary action;
ErpActionBar默认第一个可见动作是 primary。 - 删除、取消、移除、拒绝、delete、cancel、remove、reject 等危险动作使用 danger,并在高风险时加
el-popconfirm。 - 普通模式最多显示 4 个动作,compact 模式最多显示 2 个,其余进入
更多。 - 表格行操作使用 link button,标签短而明确:查看、审计、编辑、打开。
- 成功、失败、不可执行、需人工处理等结果要留在页面工作区或
ErpPageRendereraction receipt 中;ElMessage只能作为补充。 - 不要做长横向按钮带,不要在多个区域重复同一个 submit,不要在 API 或 OFBiz 返回结果不支持时宣称动作成功。
ErpPageRenderer 只在 submitAction.apiExecutable 为 true 且存在 actionId 时调用 /api/v1/actions/:actionId。其他 action contract 要在页面里显示原因和下一步。
菜单、面包屑和路由
ErpAppShell 拥有全局导航。业务页面不要重建侧栏、顶栏、全局命令、会话身份或支持链接。
模块导航来自:
plugins/modern-ui/app/src/data/moduleCatalog.ts
新增或调整模块时先维护 id、navLabel、landingPath、title、eyebrow、description、icon、tone、prefixes、legacyIncludes、quickPages、workflows。App.vue、ErpAppShell.vue、DashboardView.vue、ModuleWorkspaceView.vue 都依赖该目录。
导航规则:
- 侧栏:全局模块和系统入口。
- 顶栏快捷动作:高频跨模块跳转,标签保持短。
el-tabs:同一业务对象的多个表面。- 横向
el-menu:页内路由或锚点,active state 是 1px 下划线,不是圆角 pill。 - 面包屑:通过
ErpPageHeader的crumbs,使用业务层级,如OFBiz 管理 / 订单履约 / 订单查询,不要暴露组件路径、JSON 文件名或生成来源。 - legacy GET 路由进入现代页时必须保留 query 参数,如
partyId、orderId、productId。
抽屉、弹窗和状态
抽屉用于非阻塞业务检查:
- 行详情
- 审计历史
- 附件和媒体审查
- 权限上下文
- side-by-side 数据检查
- 低频编辑
弹窗只用于确认和短阻塞表单。不要把完整业务流程、大表、多 tab、长审计或复杂上传塞进 dialog。popover 和 tooltip 只放轻量上下文,不能承载关键错误或多步工作。
状态规则:
| 状态 | 表达 |
|---|---|
| Loading | 工作区内保留骨架或 loading 文案 |
| Empty | 说明业务含义和下一步 |
| Unavailable | 说明权限、会话、服务、数据源或流程依赖 |
| Error | 页面内保留错误原因,不只 toast |
| Success | 页面内回执或结果区,toast 只补充 |
| Disabled | 尽量显示为何不能操作 |
状态是文字第一、颜色第二。蓝色用于主导航和主动作,绿色用于完成/健康/已连接,黄色用于待处理/需复核/后台处理,红色用于错误/拒绝/取消/删除,灰色用于中性元数据和不可用说明。
页面排版
后台页面是桌面优先的密集工作台,当前宽度目标约 1180px。POS 和 commerce 可以更适合触控,但 back-office 页面仍保持紧凑、稳定、可扫描。
推荐结构:
ErpPageHeader:面包屑、短说明、有限头部动作。- tabs:当页面有总览、数据、动作、流程、审计、权限等不同表面。
- 查询/命令/动作带:只在能帮助操作员时出现。
- 主工作区:form、table、action bar、domain workspace。
- 侧向上下文:文档摘要、流程、审计、权限、交接状态。
密度规则:
- 24px 用于页面
h1,18px 用于面板标题,14px 用于正文和主要控件,13px 用于菜单/面包屑/紧凑文本,12px 用于状态、标签和元数据。 - 使用 4px spacing grid 和
--erp-space-*。 - 圆角不超过
--erp-radius-md8px。 - 表格用 1px soft border、紧凑 cell、稳定分页。
- cards 只用于重复项、摘要指标、队列行和真正 framed tools;不要卡片套卡片。
- 不做营销 hero,不用大段解释挡住主工作区,第一屏要看到真实业务工作。
PageDefinition 业务页
PageDefinition 是业务操作页的主要元数据契约,包含:
pageId、title、component、domain、layout。blocks: form、table、actions、menu、links、permission、section、workspace、report、adapter 等PageBlock[]。actions: 字符串 action 或ActionDefinition[]。permissions: OFBiz 继承权限。legacy: 旧 source path 和 widget traceability。acceptance: renderability、mapping、risk、checklist、scenario 等验收线索。
路由和渲染流程:
controller.xml + widget XML + service XML
-> plugins/modern-api/generated/ui-inventory.json
-> plugins/modern-ui/app/public/generated/ui-inventory.json
-> /modern/app/generated/ui-inventory.json
-> GET /api/v1/pages/:pageId 或 generated page JSON fallback
-> BusinessPageView
-> ErpPageRenderer
-> Element Plus ERP wrappers
BusinessPageView 接收 pageId 和 hash query,解析 PageDefinition,保留 route payload,并传给 ErpPageRenderer。ErpPageRenderer 负责页面动作状态、ErpActionBar、上传处理、动作回执、domain workspace 选择和 block 渲染。
不要在自定义 view 中按 route id 手工重建生成业务页。优先修 PageDefinition 元数据、renderer 映射或 workspace 映射,让同类页面一起受益。
legacy query 不能丢:
/accounting/control/EditBillingAccount?partyId=DemoCustomer
-> /modern/app/#/pages/accounting__EditBillingAccount?partyId=DemoCustomer
这些参数要进入 initialPayload,并预填匹配的 ErpSearchForm / ErpEntityForm 字段。
Block 和 Workspace 选择
常见 block 映射:
| Block 类型 | 使用 |
|---|---|
form |
ErpSearchForm;编辑语义明确时用 ErpEntityForm |
table |
ErpDataTable |
actions |
ErpActionBar |
menu |
Element Plus el-menu 或业务链接组 |
links |
Element Plus button/link group |
permission |
el-descriptions / el-alert 展示业务权限含义 |
section |
业务摘要或只读事实 |
report |
ErpReportWorkspace 或 report adapter |
search-workspace |
查询表单 + 结果表格 |
entity-editor |
ErpEntityForm + 校验/审计上下文 |
domain-workspace |
摘要、tabs、line tables、领域动作 |
tree-workspace |
树导航 + 详情面板 |
calendar |
el-calendar + .erp-calendar |
lookup-workspace |
lookup 搜索 + 可选结果 |
commerce-surface |
ErpCommerceSurface |
pos-workspace |
ErpPosWorkspace |
client-behavior |
dependent selects、多选、前端校验说明 |
route-workspace |
没有 widget block 的旧路由工作区 |
template-adapter, html-template, legacy-screen |
临时结构承载;业务签收前必须确认行为或替换成领域实现 |
领域流程优先使用 dedicated workspace,例如:
- 订单、购物车、发运、履约:
ErpOrderWorkspace,ErpFulfillmentWorkspace,ErpReturnWorkspace。 - 财务、手工分录、对账:
ErpFinanceWorkspace,ErpFinanceOperationsWorkspace。 - 库存、采购、制造:
ErpInventoryWorkspace,ErpProcurementWorkspace,ErpManufacturingWorkspace。 - 商品、目录、促销、媒体:
ErpCatalogWorkspace,ErpMediaWorkspace。 - 客户、关系、沟通:
ErpPartyWorkspace。 - 内容、报表、BI、系统、扩展、网关、门户:对应
Erp*Workspace。
Dedicated workspace 仍然要消费 PageBlock、PageDefinition、actions、fields、items、capabilities 和 dataSource,不要把业务规则写成孤立静态布局。
页面配方
领域管理页
适用于订单、客户、商品、财务、库存、生产、人事、采购、内容、营销、电商、POS、扩展、系统等模块。
- 在
moduleCatalog.ts维护模块身份和导航。 - 使用
ErpDomainAdminView或领域 admin view。 - 顶部使用
ErpPageHeader。 - 指标用
.metrics-grid和.erp-metric-card。 - 主体展示队列、近期记录、风险、交接、治理信息。
- 记录列表使用
ErpDataTable或领域 workspace 内表格。 - 原始诊断信息只放系统/诊断区域,不进第一屏。
查询和列表维护
ErpPageHeaderErpSearchFormErpActionBar,当存在查询、导出、打印或批处理动作ErpDataTable- 内置详情抽屉或
ErpDrawer - 需要审计时使用
ErpAuditTimeline
新建和编辑
ErpPageHeader- 权限、来源或后台契约
el-alert ErpEntityFormErpActionBar或 form submit action- 既有记录的详情/审计侧栏
必填和身份字段前置,实体引用用 lookup,大表单拆成 tabs 或 sections。
流程、审批、履约
- 当前对象摘要和状态标签
- 一个明确的 primary next action
- 主流程 workspace:行项目、数量、付款、发运、退货、凭证或审批数据
- 侧栏显示审计、权限、风险、交接
- 提交后保留 action receipt
流程页必须说明当前状态、下一步、阻塞原因和审计相关结果。
报表和导出
使用 ErpReportWorkspace 或 ErpAdapterBlock 的 report surface:
- 参数表单
- 输出模式:页面预览、PDF、CSV、print、export
- 结果表格或不可用原因
- 导出状态或 action receipt
报表、PDF、CSV、print、export 要验证参数、权限、输出内容和文件行为。
系统、安全、运维
ErpPageHeader- 服务、权限、缓存、job、安全状态 alert
- logs、jobs、services、users、groups、rules 使用密集表格
- 危险动作必须确认
- 只有代码、日志、配置值使用 monospace
文案规则
使用短、具体、可操作的中文业务文案。
推荐:
- 当前单据
- 业务数据
- 提交动作
- 权限上下文
- 待处理队列
- 异常交接
- 处理回执
- 业务流转
- 审计记录
生产页面避免使用内部工程叙事作为主文案。操作员可见区域必须围绕业务对象、业务状态、下一步动作、权限原因和处理回执;生成来源、适配状态、覆盖率、签收阶段、路由映射和工程报告只放内部验证、开发诊断或交付说明。
文档和交付说明可以客观描述从原有 OFBiz 页面到现代管理端的迁移策略,但必须以生产管理站点为中心:哪些业务对象可操作、哪些动作可执行、哪些流程仍需业务签收、哪些验证命令证明了什么。
验收边界
可以声明“结构已覆盖”的条件:
- 有 route manifest entry 和
PageDefinition。 - 能进入 Vue + Element Plus renderer。
- block 映射到 form、table、action、adapter 或 workspace。
- 表单控件有明确 read/submit contract。
- action 有
ActionDefinition或明确不可执行状态。 - 代表性 runtime 检查无 console/runtime 错误。
不能把结构覆盖等同于业务完成。业务签收需要旧流程和现代流程在以下行为上匹配:
- query 参数和表单预填
- 查询结果、分页和排序
- lookup 和 option loading
- create/edit/submit/action side effects
- service/event 返回、错误和跳转
- upload、media、import、export、PDF、print、report output
- permission、login、session、validation
- 状态流转、审计相关影响、导航目标
template-adapter、html-template、legacy-screen、derived dataSource、local submit contract 等都只能说明页面有结构承载;涉及业务副作用时必须做 old-vs-new E2E 或改成 dedicated Vue/workspace。
内部验证
代码或 UI 行为改动后,从 plugins/modern-ui/app 运行:
npm run build
npm run verify:browser-runtime
npm run verify:coverage
npm run verify:preview
npm run verify:parity
命令含义:
| 命令 | 能证明 | 不能证明 |
|---|---|---|
npm run build |
TypeScript 和 Vite 构建成功 | 业务行为正确 |
npm run verify:browser-runtime |
/modern/app/ 管理端在浏览器渲染,收集 console/runtime 健康 |
全路由和业务等价 |
npm run verify:coverage |
route/page/action/form/table/API contract 的结构覆盖 | old-vs-new 功能等价 |
npm run verify:preview |
代表性页面渲染、交互、生成资源和场景覆盖 | 所有业务页已签收 |
npm run verify:parity |
rewrite gate 和 parity accounting 报告 | 所有业务副作用已匹配 |
文档-only 改动可做轻量检查:
git status --short -- plugins/modern-ui/UI.md plugins/modern-ui/DESIGN.md plugins/modern-ui/app/src/styles
rg -n "Token 和密度契约|样式依赖规则|按钮层级|表单规则|表格和列表|验收边界|内部验证" plugins/modern-ui/UI.md
rg -n "<本次任务禁用的三组中文主导词>" plugins/modern-ui/UI.md plugins/modern-ui/DESIGN.md plugins/modern-ui/app/src/styles
最后一条把占位内容替换成审查清单中的禁用主导词后应无结果。
当前 Codex in-app browser / iab 不可用时,浏览器验收命令仍应走本地 Chrome/CDP fallback:
CHROME_BIN="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" npm run verify:browser-runtime
验收报告路径是 plugins/modern-ui/verification/browser-runtime-report.json,截图路径是 plugins/modern-ui/verification/browser-runtime-admin.png。如果该命令失败,优先检查 /modern/app/ 是否可达、CHROME_BIN 是否存在、CDP 是否能启动;不要改用无限 iab 重试作为替代。
Review Checklist
审核 modern-ui 页面或组件改动时确认:
- 页面使用合适的
ErpPageHeader、ErpSearchForm、ErpEntityForm、ErpDataTable、ErpActionBar、ErpStatusTag、ErpLookup、ErpUpload、ErpDrawer、ErpPageRenderer或ErpAdapterBlock。 - 颜色、字号、间距、圆角、边框、阴影来自 tokens 和 ERP pattern。
- 表格密集、可分页、状态真实,不发明业务记录。
- 动作有 primary、secondary、danger、overflow 层级。
- loading、empty、unavailable、permission、error、success、disabled 都在页面内有表达。
- 面包屑和文案使用业务语言,不把生成来源、组件路径或内部验证状态暴露为主 UI。
PageDefinition页面保持 renderer-driven,除非有明确领域 workspace 理由。- 没有把内部验证状态、覆盖率或适配状态说成最终产品目标。