# 模块引擎配置参考

## 核心归属

| 配置 | 归属 |
|---|---|
| 表与字段元数据 | `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` |
| `MenuBadgeTooltip` | 鼠标移入菜单数字角标时显示的统计口径说明；应写清对象、用户范围及待办/未读/总数等含义 |

默认隐藏 Id、外键、系统字段、布局字段、上传、富文本、地图和子表等重字段。
默认搜索优先名称、标题、编号、状态、类型、分类、负责人和时间；统计优先金额、
数量、价格、积分和余额。用户明确配置优先。

每个可见且绑定表的 Diy 模块还必须有 List/Card 展示设计：所有普通列给合理
`TableWidth`，至少一个 PC 复合列给 `MinWidth`，Hero 有业务标题、副标题和 2~4 个
真实指标，移动卡片覆盖可用的标题/副标题/顶部/状态/右侧/正文/Meta/底部区域。
复合列一般只用一个主字段加一个 `Lines` 次要字段，形成紧凑双行；可以配置多个各自双行
的复合列，但不要在同一列堆两个 `Lines` 形成三行。复合列和卡片区域使用过的字段不得
继续机械显示为普通列或在多个区域重复。

菜单角标只用于少量待办、未读、逾期、预警等重要入口；PageTabs 与按钮角标按业务价值
选择。相同页面的一组指标/角标使用一个批量接口，不逐指标、逐按钮、逐行请求。
配置菜单角标时应同时配置 `MenuBadgeTooltip`；历史菜单缺少该字段时，客户端回退显示菜单名
和原始数字，不得因提示文案缺失影响角标本身。
自动默认值只保证旧库和漏配模块不出现空白标题，不替代业务设计；严禁用随机数或静态演示
数字伪造统计。没有可推断业务指标时只使用真实 `DataCount/PageCount` 兜底。

## 打开方式细节

### 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 路由。

完整系统 Manifest 使用可移植引用：模块写 `openType=MicroService`、`microServiceKey`、`microServiceRoutePath`，不把某个租户的 `MicroServiceId/MicroServicePageId` 固化进发行包。`microi_generate_system` 会在首个写操作前回读运行元数据并补齐两个 Id；解析失败必须停止整次生成。直接调用 `microi_create_module` 时仍须一次提供全部四个绑定字段。

## 跨端 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 保留角色视图及未知字段。

设计器固定提供“模块标题与统计 / PC 复合列 / 移动端卡片 / 自定义表单 / 高级 JSON”五个
Tab；开关标签是“启用自定义表单视图”，只影响第四个 Tab 中的 Detail/Edit。

视图项常用字段：`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 内保存
可执行脚本。

PC 复合列的常规高度上限是两行：`Field` 占主行，`Lines` 通常只放 1 项。多个信息组拆成
多个两行复合列；只有确有层级价值且完成桌面截图验收后，才允许在同一列放第 2 个
`Lines`。`TrailingFields` 位于右侧，不应被误用成增加纵向信息层级。

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`：在当前 `diy-table` 实例内加载目标模块的菜单、表、字段和列表数据。目标菜单即使隐藏导航，也必须给角色权限。

PageTabs 可以通过 `BadgeApiEngineKey` 显示数字角标。接口按 `ButtonKeys` 一次返回所有 Tab 数量到 `Data.Buttons`，`BadgeValuePath` 可显式指定 `Data.Buttons.{TabId}`；失败只隐藏角标，不能阻断页签切换。

PageTabs 只表达当前模块的数据类别/状态，不能取代模块 Hero，也不能渲染到 Hero 上方。

跨表 Tab 由入口模块统一配置一组 PageTabs，目标菜单只保留各自的模块设计、表绑定和角色权限，不复制 PageTabs。隐藏目标菜单统一设置 `ParentId=入口菜单Id、Display=0、AppDisplay=0、HasChild=0、PageTabs=[]`，入口菜单继续保持 `HasChild=0` 作为可直接点击的业务入口。模块设计器用【关联模块】可搜索菜单树展示名称、保存 `TargetSysMenuId`。切换只更新当前 URL 的 `Tab` 查询参数；路由、面包屑、顶部访问标签和入口模块 Hero 保持稳定，表格上下文在原实例中切换。实现时必须取消旧请求、丢弃迟到响应并在失败时回滚，禁止按菜单名或业务表名写死。

首屏和跨模块切换应为 Hero 标题/统计、PageTabs、工具栏和列表提供与最终几何尺寸一致的主题化骨架屏；根据模块元数据判断是否预留指标区和 PageTabs，并支持 `prefers-reduced-motion: reduce`。

## URL 参数

兼容参数包括 `ShowClassicTop`、`ShowClassicLeft`、`FormDataId`。它们只控制
界面/默认打开记录，不建立授权；记录仍须通过当前菜单和数据权限校验。
