SNAPSHOT W7 已部署稳定态 — 凯迪ERP+OA一体化平台 (MET 73.3%)
恢复点(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>
This commit is contained in:
@@ -0,0 +1,592 @@
|
||||
# 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` |
|
||||
|
||||
应用入口只导入一次全局样式:
|
||||
|
||||
```ts
|
||||
import './styles/erp-ui.css'
|
||||
import './styles/modern.css'
|
||||
```
|
||||
|
||||
业务视图不要重复导入 Element Plus CSS,不要在页面内重新定义主题变量,也不要自建第二套视觉体系。
|
||||
|
||||
## 全局样式入口
|
||||
|
||||
`erp-ui.css` 是可复用 ERP 视觉系统入口,顺序为:
|
||||
|
||||
1. Element Plus 官方 CSS。
|
||||
2. `tokens.css`:颜色、字号、间距、圆角、阴影、边框等全局变量。
|
||||
3. `base.css`:基础页面和元素规则。
|
||||
4. `element-overrides.css`:Element Plus 变量映射和窄范围覆盖。
|
||||
5. `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` 等模式。
|
||||
|
||||
### 样式依赖规则
|
||||
|
||||
业务页只能走以下路径:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
生产页面采用:
|
||||
|
||||
```text
|
||||
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`:
|
||||
|
||||
```vue
|
||||
<ErpSearchForm
|
||||
:fields="formBlock.fields"
|
||||
:submit-action="formBlock.submitAction"
|
||||
:initial-values="routePayload"
|
||||
@submit="handleSubmit"
|
||||
@reset="handleReset"
|
||||
@update:model="mergePayload"
|
||||
/>
|
||||
```
|
||||
|
||||
新建、编辑、维护业务对象使用 `ErpEntityForm`:
|
||||
|
||||
```vue
|
||||
<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。
|
||||
|
||||
选择控件的三类数据契约:
|
||||
|
||||
```text
|
||||
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。实体选项调用:
|
||||
|
||||
```text
|
||||
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`:
|
||||
|
||||
```vue
|
||||
<ErpDataTable
|
||||
:columns="tableBlock.fields"
|
||||
:rows="tableBlock.rows"
|
||||
:data-source="tableBlock.dataSource"
|
||||
/>
|
||||
```
|
||||
|
||||
数据契约示例:
|
||||
|
||||
```ts
|
||||
{ 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`:
|
||||
|
||||
```vue
|
||||
<ErpActionBar
|
||||
:actions="page.actions"
|
||||
:payload="pagePayload"
|
||||
@executed="setActionResult"
|
||||
/>
|
||||
```
|
||||
|
||||
动作规则:
|
||||
|
||||
- 一个区域只保留一个 primary action;`ErpActionBar` 默认第一个可见动作是 primary。
|
||||
- 删除、取消、移除、拒绝、delete、cancel、remove、reject 等危险动作使用 danger,并在高风险时加 `el-popconfirm`。
|
||||
- 普通模式最多显示 4 个动作,compact 模式最多显示 2 个,其余进入 `更多`。
|
||||
- 表格行操作使用 link button,标签短而明确:查看、审计、编辑、打开。
|
||||
- 成功、失败、不可执行、需人工处理等结果要留在页面工作区或 `ErpPageRenderer` action receipt 中;`ElMessage` 只能作为补充。
|
||||
- 不要做长横向按钮带,不要在多个区域重复同一个 submit,不要在 API 或 OFBiz 返回结果不支持时宣称动作成功。
|
||||
|
||||
`ErpPageRenderer` 只在 `submitAction.apiExecutable` 为 true 且存在 `actionId` 时调用 `/api/v1/actions/:actionId`。其他 action contract 要在页面里显示原因和下一步。
|
||||
|
||||
## 菜单、面包屑和路由
|
||||
|
||||
`ErpAppShell` 拥有全局导航。业务页面不要重建侧栏、顶栏、全局命令、会话身份或支持链接。
|
||||
|
||||
模块导航来自:
|
||||
|
||||
```text
|
||||
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 页面仍保持紧凑、稳定、可扫描。
|
||||
|
||||
推荐结构:
|
||||
|
||||
1. `ErpPageHeader`:面包屑、短说明、有限头部动作。
|
||||
2. tabs:当页面有总览、数据、动作、流程、审计、权限等不同表面。
|
||||
3. 查询/命令/动作带:只在能帮助操作员时出现。
|
||||
4. 主工作区:form、table、action bar、domain workspace。
|
||||
5. 侧向上下文:文档摘要、流程、审计、权限、交接状态。
|
||||
|
||||
密度规则:
|
||||
|
||||
- 24px 用于页面 `h1`,18px 用于面板标题,14px 用于正文和主要控件,13px 用于菜单/面包屑/紧凑文本,12px 用于状态、标签和元数据。
|
||||
- 使用 4px spacing grid 和 `--erp-space-*`。
|
||||
- 圆角不超过 `--erp-radius-md` 8px。
|
||||
- 表格用 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 等验收线索。
|
||||
|
||||
路由和渲染流程:
|
||||
|
||||
```text
|
||||
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 不能丢:
|
||||
|
||||
```text
|
||||
/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、扩展、系统等模块。
|
||||
|
||||
1. 在 `moduleCatalog.ts` 维护模块身份和导航。
|
||||
2. 使用 `ErpDomainAdminView` 或领域 admin view。
|
||||
3. 顶部使用 `ErpPageHeader`。
|
||||
4. 指标用 `.metrics-grid` 和 `.erp-metric-card`。
|
||||
5. 主体展示队列、近期记录、风险、交接、治理信息。
|
||||
6. 记录列表使用 `ErpDataTable` 或领域 workspace 内表格。
|
||||
7. 原始诊断信息只放系统/诊断区域,不进第一屏。
|
||||
|
||||
### 查询和列表维护
|
||||
|
||||
1. `ErpPageHeader`
|
||||
2. `ErpSearchForm`
|
||||
3. `ErpActionBar`,当存在查询、导出、打印或批处理动作
|
||||
4. `ErpDataTable`
|
||||
5. 内置详情抽屉或 `ErpDrawer`
|
||||
6. 需要审计时使用 `ErpAuditTimeline`
|
||||
|
||||
### 新建和编辑
|
||||
|
||||
1. `ErpPageHeader`
|
||||
2. 权限、来源或后台契约 `el-alert`
|
||||
3. `ErpEntityForm`
|
||||
4. `ErpActionBar` 或 form submit action
|
||||
5. 既有记录的详情/审计侧栏
|
||||
|
||||
必填和身份字段前置,实体引用用 lookup,大表单拆成 tabs 或 sections。
|
||||
|
||||
### 流程、审批、履约
|
||||
|
||||
1. 当前对象摘要和状态标签
|
||||
2. 一个明确的 primary next action
|
||||
3. 主流程 workspace:行项目、数量、付款、发运、退货、凭证或审批数据
|
||||
4. 侧栏显示审计、权限、风险、交接
|
||||
5. 提交后保留 action receipt
|
||||
|
||||
流程页必须说明当前状态、下一步、阻塞原因和审计相关结果。
|
||||
|
||||
### 报表和导出
|
||||
|
||||
使用 `ErpReportWorkspace` 或 `ErpAdapterBlock` 的 report surface:
|
||||
|
||||
1. 参数表单
|
||||
2. 输出模式:页面预览、PDF、CSV、print、export
|
||||
3. 结果表格或不可用原因
|
||||
4. 导出状态或 action receipt
|
||||
|
||||
报表、PDF、CSV、print、export 要验证参数、权限、输出内容和文件行为。
|
||||
|
||||
### 系统、安全、运维
|
||||
|
||||
1. `ErpPageHeader`
|
||||
2. 服务、权限、缓存、job、安全状态 alert
|
||||
3. logs、jobs、services、users、groups、rules 使用密集表格
|
||||
4. 危险动作必须确认
|
||||
5. 只有代码、日志、配置值使用 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` 运行:
|
||||
|
||||
```bash
|
||||
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 改动可做轻量检查:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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 理由。
|
||||
- 没有把内部验证状态、覆盖率或适配状态说成最终产品目标。
|
||||
Reference in New Issue
Block a user