# 模块引擎配置参考

## 核心归属

| 配置 | 归属 |
|---|---|
| 表与字段元数据 | `diy_table`、`diy_field` |
| 菜单、列表列、按钮、打开方式、ViewSchema | `sys_menu` |
| 接口替换业务逻辑 | `sys_apiengine` |
| 左右树配置 | `diy_LeftJoinRightView` |
| MicroService 运行时/页面 | `sys_microiservice`、`sys_microiservice_page` |

## 查询与显示

| 逻辑配置 | sys_menu 侧含义 |
|---|---|
| `TableDiyFieldIds` | 当前模块可用字段全集 |
| `SelectFields` | 列表查询字段 |
| `SearchFieldIds` | 可搜索字段 |
| `SortFieldIds` | 可排序字段 |
| `NotShowFields` | 查询但不直接显示的字段 |
| `StatisticsFields` | 汇总字段 |
| `MobileListFields` | 移动端列表字段 |
| `CardTitleTagFields` | 卡片标题/标签字段 |
| `CardBottomTagFields` | 卡片底部字段 |
| `DefaultOrderBy` | 默认排序 |
| `MenuBadgeEnabled` | 左侧菜单统计角标开关 |
| `MenuBadgeApiEngineKey` | 菜单统计接口引擎 Key，返回 `Data.Value` |

默认隐藏 Id、外键、系统字段、布局字段、上传、富文本、地图和子表等重字段。
默认搜索优先名称、标题、编号、状态、类型、分类、负责人和时间；统计优先金额、
数量、价格、积分和余额。用户明确配置优先。

## 打开方式细节

### Diy

默认 `/diy/diy-table-rowlist`，绑定 `DiyTableId` 后自动具备列表、搜索、新增、
编辑、删除、导入和导出。

### Component

用于主前端源码已注册的组件。组件路径必须存在并经过目标前端构建验证。

### Iframe

仅允许受控 URL。地址接口引擎可返回动态 URL，但：

- 密钥只在后端使用；
- 外部 Token 短时缓存并按 `OsClient + 用户 + 目标系统` 隔离；
- URL 参数使用一次性交换码，不使用当前后台 JWT；
- 限制跳转域名并防 SSRF/开放重定向。

### SecondMenu

只承载子菜单，不绑定业务表；`HasChild` 与真实子菜单一致。

### Report

使用报表引擎虚拟表。读取 `report-engine/SKILL.md`。

### MicroService

必须同时绑定：

- `MicroServiceId`
- `MicroServicePageId`
- `MicroServiceRoutePath`
- `MicroServiceKey`
- `ComponentPath=/micro-app/host`

路由优先 `/micro-app/{MsKey}/{RoutePath}`，并兼容历史 Id 路由。

## 跨端 ViewSchema

专用物理字段：

| 字段 | 说明 |
|---|---|
| `EnableViewSchema` | 1 启用 Detail/Edit 自定义表单视图；不控制 List/Card |
| `ViewSchemaVersion` | 可选；为空默认 `1.0` |
| `ViewConfigVersion` | 可选；为空默认 `1`，后续发布递增并驱动缓存失效 |
| `ViewSchema` | Detail/Edit/List/Card JSON |

顶层 PC 列表不依赖 `EnableViewSchema` 才采用新样式：平台始终显示紧凑模块标题；ViewSchema 中有效的 List-PC 与 Card-Mobile 配置也不受该开关限制。模块表单中的 `DiyModulePresentationDesigner` 负责可视化编辑这些展示配置，以独立 JSON 编辑 Detail/Edit，并通过高级 JSON 保留角色视图及未知字段。

视图项常用字段：`Key`、`Scene`、`Device`、`RoleIds`、`Priority`、`Layout`。
标准区块包括 `EntityHero`、`MetricStrip`、`ActionGrid`、
`ResponsiveSection`。声明式动作包括：

`ApiEngine`、`OpenDetail`、`OpenList`、`OpenForm`、`Navigate`、
`Dial`、`Scan`、`Map`、`Refresh`、`Back`、`Copy`。

`ParamMap` 可使用经过白名单处理的 `$form.Field`、`$user.Field`、
`$menu.Field`。小程序端不下载/执行任意 V8Code。

### List / Card 展示协议

| 配置路径 | 用途 | 核心字段 |
|---|---|---|
| `Layout.Hero` | 模块眉题、标题、说明、统计条 | `Eyebrow/Title/Description/Metrics` |
| `Hero.Metrics[]` | 内置、字段或接口引擎指标 | `Key/Label/Source/Field/ApiEngineKey/ValuePath/Prefix/Suffix/Icon/Tone/Color/RefreshSeconds` |
| `Layout.List.Columns[]` | PC 复合列 | `Field/Lines/TrailingFields/RequiredFields/Align/MinWidth` |
| `Layout.Card` | 移动端业务卡片 | `AvatarTextField/TitleField/TopFields/SubtitleFields/RightFields/Fields/MetaFields/BottomFields` |

字段引用对象支持 `Name/AsName/Label/ShowLabel/Icon/Tone/Color/Prefix/Suffix/
FontWeight/DisplayStyle`。运行时会把引用字段并入 `_SelectFields`；查询接口替换也必须
返回这些字段。多字段模板沿用对应 `diy_field.V8TmpEngineTable`，不在 ViewSchema 内保存
可执行脚本。

Hero 必须在 PageTabs 上方渲染。PC 无指标/含指标头部分别为 `44px / 62px`，连同间距的
总纵向占用约 `50px / 68px`。有指标时标题说明区占约 25%~30%，指标区弹性占满其余空间，
两区只用弱化渐变分隔；指标容器不加外框，单指标使用轻量语义色背景和图标色块，禁止
“外层框 + 指标条框 + 指标卡框”的多层线框。无指标时标题说明自动铺满。每个指标必须
显式配置 `Icon`，同一 Hero 内使用不同 `Tone` 或 `Color` 与不同图标，不能只靠数字区分。
只允许一次性入场与一次性轻量光效，禁止持续循环动画；
`prefers-reduced-motion: reduce` 下关闭动画和过渡。

`Hero.Metrics[].Source` 可直接配置 `DataCount`（当前筛选总记录数）或 `PageCount`（本页
加载数），两者复用列表结果且不请求接口。字段汇总使用 `Field`。动态指标接口按
`ApiEngineKey` 分组调用，参数包含 `MetricKeys`、当前模块/表、租户和筛选上下文；同一接口
应一次返回多个指标。`ValuePath` 例：`Data.UnpaidAmount`。

## 动态按钮位置

| 字段 | 位置 |
|---|---|
| `MoreBtns` | 行操作 |
| `FormBtns` | 表单底部 |
| `BatchSelectMoreBtns` | 批量勾选后 |
| `PageTabs` | 页面顶部 Tab，固定在模块 Hero 下方 |
| `PageBtns` | 页面级 |
| `ExportMoreBtns` | 导出扩展 |

按钮对象必须有稳定唯一 Id、Sort、Name、显隐逻辑和动作。后台任务按钮还要配置
ApiEngineKey、Workload、幂等字段、并发 Key、业务状态/任务 Id/进度/ETA 字段。

`PageTabs` 与五类按钮共用统计字段：`BadgeEnabled`、`BadgeApiEngineKey`、`BadgeValuePath`、`BadgeField`、
`BadgeTone`、`BadgeColor`、`BadgeMax`、`BadgeShowZero`、`BadgeRefreshSeconds`。接口一次接收当前页 `Ids` 与
`ButtonKeys`，推荐返回：

```json
{
  "Code": 1,
  "Data": {
    "Buttons": { "button-id": 12 },
    "Rows": { "row-id": { "button-id": 2 } }
  }
}
```

行按钮的 `BadgeField` 直接读取当前行已有字段；PageTabs/页面按钮的 `BadgeField` 读取模块 `StatisticsFields` 页面汇总值，必须同时配置“统计列”。字段模式不调用接口；其它行统计必须批量聚合，禁止 N+1。

## 接口替换

可替换查询、新增、更新、删除、导入、导入进度和导出接口。替换后仍要保持平台
返回契约、权限、分页、统计、错误码和租户隔离。

- 查询：返回 `Code/Data/DataCount`，不可丢失菜单权限。
- 导入：读取文件、校验、分片写入、真实进度、幂等恢复。
- 导出：大数据使用后台任务/流式文件，不在请求内无界物化。
- 所有路径变量只能使用平台明确支持的占位符，不拼接 Token。

## PageTabs 两种模式

- 无目标菜单：在当前模块执行 V8，通常 `V8.SearchSet(...)`。
- 有 `TargetSysMenuId`：加载目标模块。目标菜单即使隐藏导航，也必须给角色权限。

PageTabs 可以通过 `BadgeApiEngineKey` 显示数字角标。接口按 `ButtonKeys` 一次返回所有 Tab 数量到 `Data.Buttons`，`BadgeValuePath` 可显式指定 `Data.Buttons.{TabId}`；失败只隐藏角标，不能阻断页签切换。

PageTabs 只表达当前模块的数据类别/状态，不能取代模块 Hero，也不能渲染到 Hero 上方。

跨表 Tab 应让每个目标菜单配置同一组 PageTabs，不在前端按菜单名写死。

## URL 参数

兼容参数包括 `ShowClassicTop`、`ShowClassicLeft`、`FormDataId`。它们只控制
界面/默认打开记录，不建立授权；记录仍须通过当前菜单和数据权限校验。
