@microi.net/cli 5.2.1 → 5.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/assets/build-meta.json +5 -5
- package/cordis.patch.yml +1 -1
- package/package.json +1 -1
- package/scripts/mcp-server.js +1 -1
- package/scripts/microi-codex-broker.js +12 -2
- package/scripts/microi-skills.meta.json +199 -199
- package/skills/.microi-skills-version.json +2 -2
- package/skills/app-store/SKILL.md +63 -11
- package/skills/microi-client-frontend/SKILL.md +15 -1
- package/skills/microi-form-engine/SKILL.md +106 -84
- package/skills/microi-form-engine/references/component-catalog.md +74 -3
- package/skills/microi-form-layout/SKILL.md +16 -7
- package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +4 -0
- package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +4 -0
- package/skills/microi-system-delivery/SKILL.md +13 -13
- package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +53 -53
- package/skills/microi-uniapp-frontend/SKILL.md +9 -1
- package/skills/module-engine/SKILL.md +8 -8
- package/skills/module-engine/references/module-config.md +204 -204
- package/skills/v8-api-config/SKILL.md +167 -154
- package/skills/v8-cache-pattern/SKILL.md +114 -114
- package/skills/v8-file-upload/SKILL.md +28 -3
- package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +1 -1
- package/skills/workspace-conventions/SKILL.md +11 -0
|
@@ -20,7 +20,17 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
20
20
|
- 表、字段、Tab、菜单、权限、接口引擎、事件、数据源、页面、打印、工作流、任务和可幂等种子数据都应通过应用包升级;不得为这些资源在 `Microi.Server/Microi.Upgrade/` 新增租户定制 .NET 代码。
|
|
21
21
|
- 有官方 MCP 权限时,固定使用 `microi_itdos`(`https://api.itdos.com`、`OsClient=iTdos`)更新官方母版、制作并发布对应应用,按内容哈希/包版本回读后,再由目标租户 MCP 安装或更新。无官方权限时只通过当前用户自己的 MCP/Manifest 更新其数据库并回读,不得假借通用升级器越权发布官方应用。
|
|
22
22
|
- `Microi.Upgrade` 只保留应用商城/安装器启动前必需的核心物理兼容或协议迁移,并要求持久化版本门、共享租约、幂等、失败不推进版本。禁止每次启动对每个租户重跑不断增长的历史迁移清单。
|
|
23
|
-
- 平台通用缺陷的交付证据必须分开记录:源码修复、官方母版资源、商城包发布后回读、目标租户后台安装任务、目标租户资源回读和真实 UI/接口验收;其中任一步未完成都不能笼统称为“已发布并安装”。
|
|
23
|
+
- 平台通用缺陷的交付证据必须分开记录:源码修复、官方母版资源、商城包发布后回读、目标租户后台安装任务、目标租户资源回读和真实 UI/接口验收;其中任一步未完成都不能笼统称为“已发布并安装”。
|
|
24
|
+
- 任何计划让全部吾码租户通过“安装/更新官方应用”获得的标准字段、布局、菜单、页面或种子数据,必须先在官方 `microi_itdos` 主租户创建并回读,再从该主租户按精确菜单/表资源导出新版 `AppPakcet`、单调递增应用版本并发布。禁止先只在客户/子租户补字段,再用本地手工 JSON 冒充官方母版;客户验证应发生在官方包发布之后。
|
|
25
|
+
- 同一标准能力若同时属于基础 SaaS 空库包和独立官方应用(例如系统设置、系统账号),两条交付链都要更新:基础包保证新租户初始化完整,独立应用保证存量租户可增量安装。发布后分别核对 `PackageInfo.Version`、物理列、`diy_field` 布局节点和商城行 `AppVersion/AppPakcet`,不能用其中一条替代另一条。
|
|
26
|
+
|
|
27
|
+
## 吾码创建人开发时的强制发布闭环
|
|
28
|
+
|
|
29
|
+
- 每次任务先检查工作区根的 `Microi.Server/Microi.net/`。只有目录存在且 `rg --files Microi.Server/Microi.net` 能找到至少一个真实源码文件时,才确认当前是吾码创建人在官方完整源码工作区开发;空目录不算,且不要求本次修改位于该目录。确认后,对任意目录中的平台基础能力执行修改、构建或交付时,官方应用数据包都不是“以后再补”的附加产物,而是本次实现的组成部分。目录缺失或为空时按普通用户工作区处理;纯审查、解释或诊断仍保持只读。
|
|
30
|
+
- 触发资源包括系统设置、表、字段、Tab、菜单、权限、接口引擎、事件、数据源、页面、打印、工作流、任务、平台内置微服务和可幂等种子数据。开始修改时就确定资源归属:系统设置、登录身份、个人中心等通常归 `app.microi.saas-engine`;表单引擎归 `app.microi.form-engine`;模块引擎归 `app.microi.module-engine`;应用商城归 `app.microi.store`。同一能力跨多个包时逐包更新,禁止只挑一个包。
|
|
31
|
+
- 强制闭环依次包含:①源码和定向测试;②通过绑定 `https://api.itdos.com + OsClient=iTdos` 的 `microi_itdos` 更新并回读官方母版资源;③从母版导出或按受审计发布契约生成本地应用包,单调提升包版本并核对资源数量、版本和 SHA-256;④发布对应官方 Platform 应用;⑤重新读取商城行和完整 `AppPakcet`,核对 `Published/IsApprove`、`AppVersion`、`PackageInfo.Version`、资源正文和内容哈希;⑥立即做一次同输入幂等重跑,确认无重复升版或漂移。任务还指定目标租户时,再安装/更新并等待后台任务 `Succeeded` 后回读真实资源。
|
|
32
|
+
- 本地包文件、生成器成功、单元测试通过、返回 TaskId 或 HTTP 200 都不能代替官方主数据库与商城回读。`.resource-sync-base` 只能在官网发布后逐项哈希一致时由同步器推进,不得与本地候选一起手工修改。若官方身份、MCP 登录或发布门禁失效,必须保留准确的未发布边界并修复链路;不得把本地 JSON 宣称为“其它吾码用户已经可以安装”。
|
|
33
|
+
- 应用包不得携带真实地图 Key、Token、连接串或其它租户秘密。浏览器供应商 Key 等配置只交付字段/设置模板和安全读取能力,实际值由每个目标租户在安装后自行填写。
|
|
24
34
|
|
|
25
35
|
## 包内容
|
|
26
36
|
|
|
@@ -33,10 +43,10 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
33
43
|
## 接口引擎资源所有权(强制)
|
|
34
44
|
|
|
35
45
|
- 新发布包必须声明 `ResourcePolicies.ApiEngines`,不得再依赖“同 Key 直接覆盖”。官方不可随租户修改的核心使用 `{ Ownership:'Application', UpgradePolicy:'Managed' }`;提供给租户改业务的 Hook 使用 `{ Ownership:'Tenant', UpgradePolicy:'CreateIfMissing' }`。
|
|
36
|
-
- 发布器从上一版 `AppPakcet.SysApiEngines` 计算 `BaseHash`;导入成功后把本版摘要写入 `sys_microistoreversion.InstallResult.ResourceState.ApiEngines`。普通/社区应用仍按 Base/Local/Incoming 三方保护:`Local == Base` 才更新,`Local != Base && Local != Incoming` 必须冲突回滚。唯一覆盖例外是从固定 `https://api.itdos.com + iTdos` 实时回读并校验为官方 `ApplicationType=Platform` 的应用:其中 `Ownership=Application + UpgradePolicy=Managed` 属于平台发行物,安装/更新按包覆盖本地差异;离线包、自报官方、非 Platform 来源都不能获得该权限。
|
|
46
|
+
- 发布器从上一版 `AppPakcet.SysApiEngines` 计算 `BaseHash`;导入成功后把本版摘要写入 `sys_microistoreversion.InstallResult.ResourceState.ApiEngines`。普通/社区应用仍按 Base/Local/Incoming 三方保护:`Local == Base` 才更新,`Local != Base && Local != Incoming` 必须冲突回滚。唯一覆盖例外是从固定 `https://api.itdos.com + iTdos` 实时回读并校验为官方 `ApplicationType=Platform` 的应用:其中 `Ownership=Application + UpgradePolicy=Managed` 属于平台发行物,安装/更新按包覆盖本地差异;离线包、自报官方、非 Platform 来源都不能获得该权限。
|
|
37
47
|
- `CreateIfMissing` 只在目标 Key 不存在时创建,存在时不得对齐 Id、源码、启用状态或其它字段。扩展模板发布后即归租户维护;后续版本禁止把同一 Key 改回 `Managed` 接管,确需新的官方核心时发布新 Key 并显式迁移。
|
|
38
|
-
- 官方功能采用“Managed 核心 + CreateIfMissing Hook”。核心只提供稳定协议和默认行为,并在可信官方 Platform 包更新时覆盖升级;客户日志、写表、通知和业务动作放 Hook,并以稳定 `EventId`、唯一约束或 outbox 幂等。`CreateIfMissing` 一旦交给租户维护,即使后续官方包误改为 Managed 也必须冲突回滚。
|
|
39
|
-
- 历史包未声明策略时只能按旧兼容流程安装;重新发布时发布器必须生成策略。验收至少覆盖首次安装、可信官方 Managed 本地有差异仍覆盖、普通应用核心差异冲突回滚、Hook 被改后保持原样、重复安装、两节点竞态,以及官方发布数据库连 `ValidateOnly` 也禁止执行安装器。
|
|
48
|
+
- 官方功能采用“Managed 核心 + CreateIfMissing Hook”。核心只提供稳定协议和默认行为,并在可信官方 Platform 包更新时覆盖升级;客户日志、写表、通知和业务动作放 Hook,并以稳定 `EventId`、唯一约束或 outbox 幂等。`CreateIfMissing` 一旦交给租户维护,即使后续官方包误改为 Managed 也必须冲突回滚。
|
|
49
|
+
- 历史包未声明策略时只能按旧兼容流程安装;重新发布时发布器必须生成策略。验收至少覆盖首次安装、可信官方 Managed 本地有差异仍覆盖、普通应用核心差异冲突回滚、Hook 被改后保持原样、重复安装、两节点竞态,以及官方发布数据库连 `ValidateOnly` 也禁止执行安装器。
|
|
40
50
|
|
|
41
51
|
## 安装流程
|
|
42
52
|
|
|
@@ -58,10 +68,10 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
58
68
|
- 官方平台是应用发布源,连安装器的 `ValidateOnly` 也必须拒绝,避免通过“只验证”绕过发布源隔离。发布源只做包正文、版本和资产 Hash 回读;真实安装、更新及预检必须切换到非官方目标租户或本地非发布源环境。
|
|
59
69
|
- 所有资源按目标 `OsClient` 写入;包内不能携带源租户 `OsClient`、数据库、Redis、对象存储、MQ/MQTT、AI 或第三方密钥。
|
|
60
70
|
- 按钮调用后台安装接口时,前端只传应用/版本/安装 Id;目标租户和管理员身份由 Token 确定。
|
|
61
|
-
- 每次安装、更新、重新安装生成稳定 `OperationId`。官方计数服务用共享数据库事件表唯一约束去重,并在同一事务内登记事件和递增 `InstallCount`;重试、跨节点和响应丢失不得重复计数。
|
|
62
|
-
- 安装次数回传属于非阻塞幂等遥测,不是应用导入事务的成功条件。来源节点返回旧格式 `True`、空响应、非 JSON、业务失败或请求异常时,只能写入带 `OperationId`/`InstallationKey` 的 warning 诊断,不得用 `_error_` 标记或回滚已经成功导入的应用;重试仍须复用同一幂等键。
|
|
63
|
-
- “全部安装/更新”固定只处理 `ApplicationType=Platform` 的官方平台应用中未安装与存在新版本的项目,不得把 UniApp、Web、MicroService 或其它社区/AI 应用整库安装;已是最新版的应用不重新安装。批量计划、子项状态、checkpoint 和进度必须持久化到共享数据库/后台任务,支持多节点抢占、失败重试和重启恢复,不能依赖进程内集合或浏览器状态。
|
|
64
|
-
- 主租户批量维护全部子租户时,前端入口和接口引擎都必须校验主租户上下文及 `Level >= 9999`,再由可信控制面为每个启用子租户创建独立持久后台任务;父任务必须按子任务真实百分比聚合进度,等全部子任务终态后才成功或失败,并在通知中心保留每个租户、阶段和原始失败原因。所有子任务可立即创建,但固定商城工作器必须通过配置租户 Redis 的集群并发租约跨租户串行执行,避免共享物理库并发 DDL
|
|
71
|
+
- 每次安装、更新、重新安装生成稳定 `OperationId`。官方计数服务用共享数据库事件表唯一约束去重,并在同一事务内登记事件和递增 `InstallCount`;重试、跨节点和响应丢失不得重复计数。
|
|
72
|
+
- 安装次数回传属于非阻塞幂等遥测,不是应用导入事务的成功条件。来源节点返回旧格式 `True`、空响应、非 JSON、业务失败或请求异常时,只能写入带 `OperationId`/`InstallationKey` 的 warning 诊断,不得用 `_error_` 标记或回滚已经成功导入的应用;重试仍须复用同一幂等键。
|
|
73
|
+
- “全部安装/更新”固定只处理 `ApplicationType=Platform` 的官方平台应用中未安装与存在新版本的项目,不得把 UniApp、Web、MicroService 或其它社区/AI 应用整库安装;已是最新版的应用不重新安装。批量计划、子项状态、checkpoint 和进度必须持久化到共享数据库/后台任务,支持多节点抢占、失败重试和重启恢复,不能依赖进程内集合或浏览器状态。
|
|
74
|
+
- 主租户批量维护全部子租户时,前端入口和接口引擎都必须校验主租户上下文及 `Level >= 9999`,再由可信控制面为每个启用子租户创建独立持久后台任务;父任务必须按子任务真实百分比聚合进度,等全部子任务终态后才成功或失败,并在通知中心保留每个租户、阶段和原始失败原因。所有子任务可立即创建,但固定商城工作器必须通过配置租户 Redis 的集群并发租约跨租户串行执行,避免共享物理库并发 DDL/元数据写入死锁;分片幂等任务使用足以覆盖短时死锁和滚动重启的有界重试预算,禁止无限重试。`MaxAttempts` 表示连续失败预算:任一分片成功写入 checkpoint 后必须把 `AttemptCount` 与陈旧 `LastError` 清零,不能让数百个成功分片之间偶发的网络错误按任务生命周期累计并误终结。分片重新入队后必须按 `COALESCE(NextRunTime, CreateTime)` 选取最早就绪任务,禁止只按 `CreateTime` 让最早长任务重复抢占全部分片。商城包属于只读权威数据,可对空响应做有界退避重试,并优先用完整响应的 `Content`、`RawBytes`、HTTP 状态和传输错误诊断;不得把该规则扩展到安装写入请求。目标租户固定商城工作器只允许从受信任官方谱系向更高版本刷新;同版本不同源码、目标端更新版或未知谱系必须失败关闭。历史空库缺少生成实体所需物理列时,导入器须在首次 FormEngine 调用前幂等补齐并回读,不能再把真实表结构错误包装成 `Value cannot be null (source)`。
|
|
65
75
|
- 必须随所有后端版本自动落地的平台基础能力,仍要封装成受信任的官方 Platform 应用包,再由升级器调用统一 `import-microi-store-package` 幂等导入;禁止把表、字段、页面或微服务复制成定制 C# 迁移。身份验证、登录方式、个人中心与租户系统设置使用 `app.microi.saas-engine.json`:携带 `mci_system_setting`、`mci_user_external_identity`、默认设置和平台内置微服务。默认行必须使用 `InsertIfMissing + ConfigKey`,只补缺失,不覆盖 `ValueSource=Tenant` 的租户值或租户后来明确关闭的功能。小型平台启动微服务应以 `Source=NotIncluded + Build=DatabaseOnly + StorageMode=db` 随程序集交付并接受 256 文件/5MB、逐文件哈希和无源码门禁,使新租户在 HDFS 故障时仍能打开商城与恢复入口;普通应用安装、源码编辑和文件能力继续失败关闭,不得伪装成全平台健康。
|
|
66
76
|
- 批量任务已经以“一个应用”为外层持久化恢复单元。规模可控的小型官方包应在一个事务中完成,避免对同一包体按 8 个字段反复下载、解析和重新排队;超过字段、表、DDL、流程、随包数据或资产安全阈值的大包继续使用内部 checkpoint 分片。热更新发现旧版批量计划不含 `ApplicationType` 时,必须丢弃旧计划并重新盘点,不能继续安装历史计划中的社区应用。
|
|
67
77
|
- MySQL 宽表触发 65,535 字节行内上限时,只允许把不参与索引的 `varchar` 配置列无损提升为 `mediumtext`,并把类型覆盖持久化到后台任务 checkpoint;索引列和非行宽错误必须失败关闭。发布包对长连接串、密钥、回调地址、域名/白名单等字段应直接使用 `mediumtext`,同时更新 `DiyFields` 与建表 DDL,不能长期依赖安装时猜测。
|
|
@@ -74,7 +84,7 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
74
84
|
- 后端来源代理必须固定已保存的 `ApiBase + OsClient`,拒绝过期 Token、访问密钥会话、非超级管理员、非 HTTPS 外网地址、重定向漂移和超限响应;Token 不得返回浏览器、日志、审计或应用包。退出登录同步删除服务端密文。
|
|
75
85
|
- 商城主页面统一承载应用市场、已安装、我发布的应用、安装离线包和来源管理,不能再通过独立菜单或路由割裂上下文。来源增删改启停逐项自动保存;来源管理、详情和复杂配置使用平台统一 `80%` 可拖动大圆角 Dialog,遮罩服从正向开关 `sys_config.FormMaskBlur`,缺失或 `0/false` 默认关闭毛玻璃。
|
|
76
86
|
- 每张应用卡必须显示预览图、公开范围、分类、最新版本、当前租户已安装版本及状态色。来源卡必须显示其公开数和当前授权可访问总数;平台官方发布节点只显示“平台官方应用源”身份标记,不显示安装、更新或重新安装操作。
|
|
77
|
-
- 安装可明确选择 `sys_microistore` 当前版本或 `mic_data_version`
|
|
87
|
+
- 安装可明确选择 `sys_microistore` 当前版本或 `mic_data_version` 中仍含完整包正文的历史快照;后台任务在首次取包时必须把计划中的 `AppVersion` 解析为匹配且包含完整包正文的不可变 `StoreVersionId`,写入 checkpoint,并在全部后续分片一直传到详情取包。发布方中途升版时继续完成已锁定快照,新版留给下一轮盘点;快照缺失、版本不匹配、身份变化或快照 Id 漂移必须失败关闭,禁止退回易变当前行。实际安装版本写回 `sys_microistoreversion`。回退旧版属于重新安装,不得静默换成最新版。
|
|
78
88
|
- 应用详情的版本选择必须服务端分页和搜索,默认每页不超过 20 条;当前版本固定置顶,历史版本只返回仍包含完整包正文的可安装状态。禁止用 `_PageSize:500` 或一次加载全部版本后在浏览器过滤。翻页、搜索与页大小切换都必须保持已选版本语义并显示总数。
|
|
79
89
|
- 商城详情、来源管理等 Teleport 弹层必须使用宿主级固定遮罩,毛玻璃覆盖完整可视区域;标题栏拖动按弹层真实尺寸限制四边,窗口缩放后重新限制,不能依赖固定像素最大位移或允许内容越出视口。
|
|
80
90
|
- “我发布的应用”只读取当前登录用户拥有的记录,可以包含草稿和构建失败项;普通商城列表只读取已发布项。两者必须在服务端按 Owner 和发布状态过滤,不能依赖浏览器过滤后再分页。
|
|
@@ -182,10 +192,52 @@ description: Microi 应用商城开发、打包、安装和升级规范。用于
|
|
|
182
192
|
- 通用规则:当包要求 `NOT NULL`、目标列仍可空且存在历史 `NULL` 时,必须先用包内明确声明的默认值参数化回填,再执行列约束变更;包未声明默认值时失败关闭并报告影响行数,禁止猜测业务值。该步骤必须可重复执行,并允许多节点并发重试后得到同一结果。
|
|
183
193
|
- 自动化检查:构造可空旧列及多条 `NULL` 行,断言导入器按“统计 NULL → 参数化回填 → `MODIFY ... NOT NULL`”顺序执行;覆盖字符串、整数、零行、缺失默认值、重复执行,以及商城包中全部发布协议状态字段。
|
|
184
194
|
|
|
185
|
-
## 复盘:应用新增菜单未自动授予系统管理员完整权限
|
|
195
|
+
## 复盘:应用新增菜单未自动授予系统管理员完整权限
|
|
186
196
|
|
|
187
197
|
- 触发场景:应用首次安装或版本更新新增了 `sys_menu`,菜单数据已经存在,但系统管理员看不到入口或只能执行部分按钮;再次人工到角色管理中勾选后才恢复。
|
|
188
198
|
- 根因:安装器只导入菜单,没有在同一事务内写入 `sys_rolelimit`;历史补丁又把单个管理员角色 Id 和五项旧权限硬编码,只能修复某个菜单,遗漏 `Read`、自定义按钮及其它 `Level >= 9999` 管理员角色。
|
|
189
199
|
- 通用规则:安装器只对本次真正新增或从删除状态重新引入的菜单自动授权,不扩大既有菜单的客户权限策略。目标角色必须从当前租户实时读取全部有效 `sys_role.Level >= 9999` 记录;基础权限固定为 `Read/Add/Edit/Del/Export/Import`,并合并菜单 `MoreBtns/ExportMoreBtns/BatchSelectMoreBtns/PageBtns/PageTabs/FormBtns` 中每个按钮的 `Id + Name`,不得加入 `NoDetail/NoSearch` 这类限制权限。
|
|
190
200
|
- 幂等与失败边界:已有 `sys_rolelimit` 只能合并、不得删除历史自定义权限;新增行使用“租户 + 角色 + 菜单”的确定性 Id,并在并发主键冲突后重新回读合并。找不到系统管理员、查询失败或任一权限写入失败必须让整个安装事务回滚,不能出现“菜单成功但管理员无权”的半成品。通过 FormEngine 写入以触发共享授权缓存失效。
|
|
191
|
-
- 自动化检查:覆盖多个系统管理员、已有部分权限、自定义按钮既有 JSON 字符串也有数组、删除菜单恢复、重复安装零新增、两个节点同时插入后合并,以及既有菜单更新不自动扩权;发布门同时校验独立导入器与商城包内嵌副本都包含该能力。
|
|
201
|
+
- 自动化检查:覆盖多个系统管理员、已有部分权限、自定义按钮既有 JSON 字符串也有数组、删除菜单恢复、重复安装零新增、两个节点同时插入后合并,以及既有菜单更新不自动扩权;发布门同时校验独立导入器与商城包内嵌副本都包含该能力。
|
|
202
|
+
|
|
203
|
+
## 复盘:商城发布升版打断所有后台分片安装
|
|
204
|
+
|
|
205
|
+
- 触发场景:主租户为大量子租户执行“安装/更新全部平台应用”时,某个平台包从 v7.5.17 发布到 v7.5.18;正在执行的任务在下一分片报“检查点版本与当前版本发生变化”,大量子租户同时失败。
|
|
206
|
+
- 根因:版本保护正确阻止两个包混装,但批量计划只持久化 `StoreId + AppVersion`,每个分片仍从 `sys_microistore` 易变当前行重新取包,没有使用已经存在的 `mic_data_version` 完整快照,也没有把 `StoreVersionId` 写进 checkpoint。
|
|
207
|
+
- 通用规则:后台安装首次取包必须按计划 `AppVersion` 锁定匹配的完整历史快照,并在每个分片复用同一 `StoreVersionId`;应用商城自身必须排在平台批量计划首位,先自举最新版导入器。发布中途升版不能改变既有任务的包体,也不能让既有任务自动追新;下一次批量盘点再安装新版本。
|
|
208
|
+
- 自动化检查:构造计划版本 v1.0.0、商城当前版本在分片间升到 v1.0.1,断言首次选择 v1.0.0 快照 Id,恢复分片仍请求同一 Id且成功;覆盖快照尚未生成、显式 Id 与期望版本不符、身份不符均失败关闭,并断言批量计划第一项为 `app.microi.store`。
|
|
209
|
+
|
|
210
|
+
## 复盘:父任务 Monitor 重复自举误判同版本工作器
|
|
211
|
+
|
|
212
|
+
- 触发场景:全部子租户安装任务已经创建并持续执行,父任务在 Monitor 分片中再次调用租户发现/工作器自举;子租户刚从应用包写入的商城工作器与主租户版本相同,仅 BOM 或 CRLF/LF 不同,却被判为“同版本源码不同、疑似租户定制”,父任务失败,而子任务仍在后台运行。
|
|
213
|
+
- 根因:父编排器在解析 checkpoint 阶段前无条件读取租户目录,导致 Monitor 也重复执行只应发生在 Queue 的有副作用自举;服务端源码比较又直接使用 Ordinal 原文比较,没有先消除跨平台文本格式差异。
|
|
214
|
+
- 通用规则:租户发现与商城工作器自举只允许在 Queue 阶段执行;Monitor 必须只汇总 checkpoint 中已经持久化的 `ChildTasks`。同版本源码比较只可规范化 UTF-8 BOM、CRLF/LF 和文件末尾空白;任何其它字符差异仍按租户定制失败关闭,禁止用去注释、压缩空白或模糊标记绕过保护。
|
|
215
|
+
- 自动化检查:覆盖同版本 LF/CRLF/BOM 等价且不刷新、同版本真实代码差异继续拒绝、旧版官方谱系允许升级、新版目标保留;接口引擎资源断言 Monitor 检查点标记存在且 `GetChildTenantPlatformAppMaintenanceTargets` 只位于 Queue 分支。
|
|
216
|
+
|
|
217
|
+
## 复盘:资源数量小但工作量重的应用被合并为单事务
|
|
218
|
+
|
|
219
|
+
- 触发场景:子租户批量安装进度停在“系统设置”或“系统帐号”十多分钟,心跳和 CPU 仍活跃但没有新检查点;重启后同一现象只会转移到下一个租户。
|
|
220
|
+
- 根因:批量工作器请求 `BulkAdaptiveSingleSlice`,导入器仅按表、字段、菜单和数据行数量判断“小包”,没有计入 DDL、实体生成、权限回填和历史数据迁移的真实成本,因而关闭了内部后台分片。
|
|
221
|
+
- 通用规则:后台商城安装必须始终保留有界分片和持久化检查点;旧工作器仍传单片参数时,新导入器必须安全忽略。已排队的跨租户任务在真正运行目标 V8 前,应按进程缓存执行一次官方安装器自愈,使平台修复能从原检查点接管。
|
|
222
|
+
- 自动化检查:断言批量工作器显式关闭单片参数、导入器不存在 `backgroundChunkingEnabled=false` 路径、旧单片参数只记录忽略诊断;后台执行器在子租户工作器运行前调用受信自举,并继续保留同版本真实源码差异的失败关闭保护。
|
|
223
|
+
|
|
224
|
+
## 复盘:旧租户前置物理列逐列重建耗尽首片超时
|
|
225
|
+
|
|
226
|
+
- 触发场景:已启用后台分片后,旧租户首次更新“系统设置”仍长时间没有 `ChildCheckpoint`;心跳与 CPU 正常,接近单片超时后才推进。实时 Schema 回读显示 `sys_apiengine` 与 `diy_table` 同时缺少多项生成实体固定列。
|
|
227
|
+
- 根因:导入器为兼容历史空库,在第一次 FormEngine 调用前逐列执行 `ALTER TABLE ADD`。MySQL 每个语句都可能重新准备或重建同一张元数据表,多个固定列的累计耗时发生在首个可持久化检查点之前。
|
|
228
|
+
- 通用规则:MySQL 同一张表缺少多个受信固定前置列时,必须先完整盘点,再用单条 `ALTER TABLE ... ADD ..., ADD ...` 原子补齐并回读;可信后台任务每个分片最多修改一张前置元数据表,提交 `Prerequisites` 检查点后再继续下一张。没有缺列的现代租户直接进入原 DDL 阶段,不制造空分片。并发节点已完整补齐时按幂等成功,否则保留真实表名、未补齐列和数据库错误并失败关闭。SQL Server 与 Oracle 使用各自已验证语法,不得直接套用 MySQL 批量语句。
|
|
229
|
+
- 自动化检查:独立导入器和商城包内嵌副本都必须携带批量前置列及检查点标记;断言 MySQL 路径先收集 `pendingDefinitions`、每表只拼接一次批量 ALTER、后台每片写表上限为一,且失败后逐项回读所有待补列。真实旧租户验收需证明前置列分片已提交、随后不可变 `StoreVersionId` 与字段阶段检查点继续推进。
|
|
230
|
+
|
|
231
|
+
## 复盘:父级监控遇到数据库死锁被误判为业务失败
|
|
232
|
+
|
|
233
|
+
- 触发场景:父级 Monitor 已持久化全部子任务 Id,子任务仍在正常执行且 checkpoint 中没有业务失败;父任务汇总进度时偶发数据库死锁,却因调用方配置 `MaxAttempts=1` 立即进入 `Failed`,通知中心因此把仍可成功收敛的整批任务标红。
|
|
234
|
+
- 根因:后台任务把数据库死锁、锁等待超时等基础设施瞬态竞争与接口返回失败共用同一业务重试预算。低业务重试次数无法覆盖工作器自身的领取、心跳、检查点或结果持久化竞争,也没有保留父子任务的真实运行语义。
|
|
235
|
+
- 通用规则:后台任务存储层只对已知数据库死锁、锁等待超时、序列化竞争等稳定特征启用独立的有界基础设施重试;即使业务 `MaxAttempts=1`,也允许最多三次基础设施执行机会。重试必须保留原 TaskId、父子关系、checkpoint 和已产生的副作用,不得重新创建子任务;成功后清除瞬态错误,第三次仍竞争才按原业务规则终止。普通业务错误、数据冲突和 `Value cannot be null` 等非竞争错误不得借用该预算。
|
|
236
|
+
- 自动化检查:覆盖嵌套 ProviderException 与外层包装异常、MySQL/SQL Server/PostgreSQL/Oracle 的稳定错误码或消息;断言第一次和第二次竞争回到可领取状态且不消耗业务 AttemptCount,第三次进入原终态,非竞争异常仍按 `MaxAttempts` 立即失败。真实验收必须等待原 8 个子任务全部收敛,再以 `MaxAttempts=1` 连续执行一轮完整汇总和一轮立即无操作重跑,父任务均应得到 `SucceededCount=8、FailedCount=0`。
|
|
237
|
+
|
|
238
|
+
## 复盘:字段分片完成后后台安装卡在缓存失效广播
|
|
239
|
+
|
|
240
|
+
- 触发场景:字段分片的数据库写入和 Schema 回读已经精确完成,但 `ChildCheckpoint` 长时间停在同一字段索引;任务取消也无法及时结束,进程内存、线程数和 CPU 持续增长。
|
|
241
|
+
- 根因证据:两次托管转储的调用链都停在 `V8.ApiEngine.Run -> GetApiEngineModelInternal -> MicroiTwoLevelCache.SetAsync -> PublishInvalidateAsync -> PublishWithRetryAsync`。权威 Redis 写入已经成功,随后用于通知其它节点清理一级缓存的 Pub/Sub 广播没有完成时限,因而把业务调用永久挂住;与此同时,单字段元数据更新即使只变更 Label、Remark、布局或 V8,也会重复执行物理列 DDL,放大旧租户升级成本。
|
|
242
|
+
- 通用规则:Redis 权威值写入成功后,跨节点一级缓存失效广播只能是有界、尽力而为的附属动作。队列等待和实际发布都必须有独立短超时,超时后观察迟到异常并开启短暂熔断冷却,防止悬挂发布任务无界堆积;不得因此回滚已经成功的权威写入。`UptDiyField` 只有列名或物理类型变化时才允许调用 `ChangeColumn`,显示名称、说明、布局和事件代码等纯元数据变化禁止触发 DDL。
|
|
243
|
+
- 自动化与真实验收:缓存测试必须覆盖发布永久不返回时的有界退出、迟到异常观察和冷却期抑制;字段测试必须断言只有 Name/Type 变化才进入物理 DDL。应用商城资源契约测试、后台任务与 SaaS 回归测试通过后,还必须在真实主租户完成 8/8 子租户收敛并立即执行一轮 8/8 无操作重跑。验收期间若官方应用发布了新版本,应以新的不可变 `StoreVersionId` 启动独立追赶批次,禁止混入已经开始的旧版本分片。
|
|
@@ -130,7 +130,21 @@ description: Microi.Client 源码架构指南。用于修改 Microi.Client Vue
|
|
|
130
130
|
|
|
131
131
|
标准前端 V8 会挂载 `FormEngine`、`ApiEngine`、`DataSourceEngine`、`Http`、`Base64` 等能力;虽然 `DiyCommon.ModuleEngine` 有底层实现,标准全局 V8 当前并未挂载 `V8.ModuleEngine`,文档和编辑器提示不得把它当作可用 API。
|
|
132
132
|
|
|
133
|
-
`V8.SysConfig` 是面向浏览器的脱敏公开配置投影,不得依赖其中出现数据库连接串、对象存储密钥、短信/邮件密码或其它 SaaS 私密字段。
|
|
133
|
+
`V8.SysConfig` 是面向浏览器的脱敏公开配置投影,不得依赖其中出现数据库连接串、对象存储密钥、短信/邮件密码或其它 SaaS 私密字段。
|
|
134
|
+
|
|
135
|
+
### 框架来源标识与水印(强制)
|
|
136
|
+
|
|
137
|
+
- 微服务和定制组件的来源标识必须由 Microi.Client 宿主统一渲染,子应用不得各自实现。来源标识是框架内置的常驻可发现能力,不得再创建 `RenderSourceBadgeMode`、自动收起、全局关闭等租户配置。
|
|
138
|
+
- `V8.OpenAppDialog` / Drawer 等标准弹层的来源标识放在标题文字之后,始终显示且不提供关闭按钮;菜单/整页微服务由 `micro-app/host.vue` 在内容区右上角直接渲染,必须提供只作用于当前页面实例的手动关闭按钮,切换实例后恢复显示。不得依赖外围路由组件猜测菜单微服务,避免动态路由元数据不同步导致漏标。
|
|
139
|
+
- 来源标识必须使用可点击的 `button` 语义与 `cursor:pointer`。点击后用可拖动、居中、亮/暗色适配的大圆角 Element Plus 弹层展示 AppKey、PageKey、应用内/框架路由、版本、源码定位、运行入口、发布/挂载状态和租户坐标,并生成可复制的 MCP 修改指令;公开详情不得包含 DiyToken、访问密钥、私有配置或用户敏感字段。
|
|
140
|
+
- 框架水印覆盖 `100vw × 100vh` 且固定 `pointer-events:none`。开启后内容空值默认 `$SysTitle$ - $UserName$`(用户名为空回退账号)、方向默认 `DiagonalUp`、密度默认 `Comfortable`、字号空值/0 默认 14,透明度空值/0 默认 30;亮色、深色、弹层、键盘和减少动态效果模式都要验收。
|
|
141
|
+
|
|
142
|
+
### 用户级界面偏好(强制)
|
|
143
|
+
|
|
144
|
+
- 主题色、浅色/深色、菜单子级展开方式等需要“换设备仍生效”的选择必须保存到当前 DiyToken 用户的 `sys_user` 白名单字段;`localStorage` 只作为未安装新字段租户和匿名启动阶段的兼容回退,不能作为跨设备事实源。
|
|
145
|
+
- 已安装用户偏好字段时优先级固定为“当前用户显式值 → 租户 `sys_config` → 平台安全默认”;个人菜单值 `System` 表示继承租户配置。不得让上一位用户的浏览器本地主题覆盖下一位已登录用户。
|
|
146
|
+
- 自助保存优先使用官方 `Managed` 接口引擎,由 `V8.CurrentUser.Id` 与 `V8.OsClient` 推导用户和租户,并在服务端构造固定白名单更新对象;接口参数禁止决定目标 Id/OsClient,也禁止写入 Account、Phone、Tenant、Dept、Role、Level、State、Pwd、认证因子和登录审计字段。只有缺少可复用可信原子能力时才新增 C# DTO/端点。保存成功后调用 `V8.Method.RefreshLoginUser` 刷新登录缓存,并让微服务宿主重新同步 `CurrentUser`。
|
|
147
|
+
- 右上角即时切换可以乐观应用并短防抖保存;远端保存失败时保留当前设备效果并明确提示。个人中心和右上角必须调用同一个应用包交付的白名单接口引擎(当前为 `platform-user-update-preferences`),不能分别形成两套字段、枚举或优先级。
|
|
134
148
|
|
|
135
149
|
---
|
|
136
150
|
|
|
@@ -12,7 +12,7 @@ description: Microi 表单引擎设计与控件配置指南。用于创建或修
|
|
|
12
12
|
Config/Data、菜单查询列与缓存保持一致。
|
|
13
13
|
|
|
14
14
|
平台创建 DIY 表时会自动加入 `DiyCommon.FixedDiyField` 定义的 Id、创建/更新时间、
|
|
15
|
-
创建人、租户等固定字段。业务 Manifest 不重复声明这些字段;读取实时 Schema 或离线快照时也不能
|
|
15
|
+
创建人、租户等固定字段。业务 Manifest 不重复声明这些字段;读取实时 Schema 或离线快照时也不能
|
|
16
16
|
因为 `_Fields` 只列出可配置字段,就误判物理表缺少固定字段。
|
|
17
17
|
|
|
18
18
|
## 必读参考
|
|
@@ -32,51 +32,73 @@ Config/Data、菜单查询列与缓存保持一致。
|
|
|
32
32
|
3. 新表用 `microi_create_table`;字段用 `microi_add_field`,不得直接写
|
|
33
33
|
`diy_field` 或执行临时 DDL。
|
|
34
34
|
4. 选项控件同时设置 `data/config`;关联控件明确保存字段和显示字段。
|
|
35
|
-
5. 字段多时设置 `diy_table.Tabs` 与字段 `Tab`;只有整行控件设置
|
|
36
|
-
`FormWidth=24`,普通字段省略。`CollapseGroup` 属于整行控件,必须显式保存
|
|
37
|
-
`FormWidth=24`,且 `Config.CollapseGroup.ShowFieldCount` 默认补为 `true`。
|
|
35
|
+
5. 字段多时设置 `diy_table.Tabs` 与字段 `Tab`;只有整行控件设置
|
|
36
|
+
`FormWidth=24`,普通字段省略。`CollapseGroup` 属于整行控件,必须显式保存
|
|
37
|
+
`FormWidth=24`,且 `Config.CollapseGroup.ShowFieldCount` 默认补为 `true`。
|
|
38
38
|
6. 绑定菜单后补齐/允许平台推断列表列、搜索列、隐藏列、排序列、移动端列和默认排序。
|
|
39
39
|
7. 回读 `diy_field`、刷新 schema 缓存,再在真实新增/编辑/查看表单中验收。
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
重型控件密度),默认保存 `diy_table.FormOpenType=Dialog` 与 `FormOpenWidth=80%`。
|
|
43
|
-
Drawer 只服务超长复杂表单,不能作为所有 CRUD 模块的模板默认值。
|
|
44
|
-
若设计器显示而运行态不显示,先检查 `InFormV8`/字段 V8 是否调用
|
|
45
|
-
`V8.FieldSet(..., 'Visible', false)`、`hideField` 或传入 `HideFields`,再判断前端源码。
|
|
41
|
+
## 上传字段配置(AI 生成时强制)
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
`
|
|
54
|
-
`
|
|
55
|
-
`
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
43
|
+
- 图片使用 `Config.ImgUpload`,至少明确 `Limit`、`Multiple`、`MaxCount`、`Preview`、
|
|
44
|
+
`MaxSize` 和 `Crop`;文件使用 `Config.FileUpload`,至少明确 `Limit`、`Multiple`、
|
|
45
|
+
`MaxCount`、`MaxSize`。完整键和值域读取 `references/component-catalog.md`。
|
|
46
|
+
- `ImgUpload.Preview` 未配置时默认开启压缩;普通业务图片优先保持开启。裁剪前的原图无论
|
|
47
|
+
展示图配置为公有或私有、是否压缩,都必须保存在 HDFS 私有桶,业务字段不得保存原图路径。
|
|
48
|
+
- `ImgUpload.Crop.Enabled` 只控制表单打开时是否默认选中裁剪。运行时的裁剪开关、存储范围、
|
|
49
|
+
单/多图数量、压缩状态和最大体积统一显示在紧凑上传面板中;不得把 `Enabled=false` 误解为
|
|
50
|
+
禁止用户裁剪。`Mode` 只允许 `free/fixed/select`。
|
|
51
|
+
- 图片和文件的拖放区都使用同一紧凑配置面板。`Multiple=true` 时必须设置业务合理的
|
|
52
|
+
`MaxCount`;`MaxSize` 单位为 MB,字段限制只能收紧租户/平台上限,不能放大。
|
|
53
|
+
- 富文本使用 `Config.RichText`:必须明确 `Limit`,并按需配置
|
|
54
|
+
`Image.Enabled/MaxSize/MaxCount/Preview/CompressMaxSize/CompressMaxWidth`、
|
|
55
|
+
`Video.Enabled/MaxSize/MaxCount`、`File.Enabled/MaxSize/MaxCount/Accept`。公开公告、商品详情
|
|
56
|
+
等匿名正文显式使用 `Limit=false`;内部正文使用 `true`。旧字段缺失配置时安全默认为私有桶,
|
|
57
|
+
图片默认压缩到约 500 KB、最长边 1920 px。
|
|
58
|
+
- 私有富文本只能持久化稳定对象标识,禁止把 HDFS 签名 URL、审计代理 Ticket 或 DiyToken 写入
|
|
59
|
+
HTML。每次查看/编辑按当前菜单、表、记录和字段权限换取新短效地址;外部匿名页面没有此权限
|
|
60
|
+
上下文,因此不能把私有 RichText 当作公开正文。普通交互式帐号也不能用 `Limit=false` 绕过
|
|
61
|
+
后端强制私有策略。
|
|
62
|
+
|
|
63
|
+
新建表/模块时,除非用户显式指定或表单达到极重阈值(约 36+ 业务字段、2+ 子表或同等
|
|
64
|
+
重型控件密度),默认保存 `diy_table.FormOpenType=Dialog` 与 `FormOpenWidth=80%`。
|
|
65
|
+
Drawer 只服务超长复杂表单,不能作为所有 CRUD 模块的模板默认值。
|
|
66
|
+
若设计器显示而运行态不显示,先检查 `InFormV8`/字段 V8 是否调用
|
|
67
|
+
`V8.FieldSet(..., 'Visible', false)`、`hideField` 或传入 `HideFields`,再判断前端源码。
|
|
68
|
+
|
|
69
|
+
## 表单 Banner(所有新业务表必做)
|
|
70
|
+
|
|
71
|
+
标准表单 Banner 默认显示,以当前主题色约 50% 混合强度叠加深蓝灰渐变,并适配浅色、
|
|
72
|
+
深色与移动端。视觉应有层次但保持清爽,标题始终维持安全对比度;统计卡片使用半透明背景
|
|
73
|
+
和柔和阴影分层,避免堆叠边框。它属于表单语义,配置
|
|
74
|
+
必须写入 `diy_table` 的 `FormBannerEnabled`、`FormBannerTitleField`、
|
|
75
|
+
`FormBannerSubtitleField`、`FormBannerImageField`、`FormBannerIcon`、
|
|
76
|
+
`FormBannerBackgroundField`、`FormBannerTagFields`、`FormBannerMetrics`,禁止写进
|
|
77
|
+
`sys_menu`、`DiyConfig` 或项目定制组件。
|
|
78
|
+
|
|
79
|
+
- 标题优先业务自动编号/单号/编码,再选名称或标题;副标题优先客户、项目、公司、分类、
|
|
80
|
+
日期等可读字段。
|
|
81
|
+
- 左侧图片使用 `ImgUpload`。单图、多图取首图,继续遵循吾码公有/私有文件路径与授权
|
|
82
|
+
规则;图片为空时必须有语义合适的 Font Awesome 图标回退。
|
|
83
|
+
- 右侧标签优先 `Select/Radio/Switch/Checkbox/SelectTree/Department` 等选项字段,最多
|
|
84
|
+
选择 3 个有业务意义的状态、类型或等级。显式 `[]` 表示不要自动标签。
|
|
85
|
+
- 自动统计最多 3 项,只选择真实金额、合计、数量、成本、余额、评分、比率、进度等具有
|
|
86
|
+
明确业务口径的数值字段;必须排除 Id、排序、启用、状态、版本、分页和本页加载量。
|
|
87
|
+
存在 `TableChild` 时,默认统计必须携带完整父表/父字段/父记录授权上下文,在服务端对全部
|
|
88
|
+
关联子表数据计算行数或业务数值合计,不能只统计当前页。跨表自定义口径使用 `ApiEngineKey +
|
|
89
|
+
ValuePath + ParamMap + RefreshSeconds`,相同接口批量返回,禁止 N+1、随机数和固定演示数;
|
|
90
|
+
没有可靠指标时隐藏统计区。显式 `[]` 表示不要自动统计。
|
|
91
|
+
- 兼容旧模块 Hero 时仅迁移视觉、`Source=Field` 或显式记录作用域指标;列表总数、分类数量和
|
|
92
|
+
未引用当前 `Form/RecordId` 的全局接口统计不得进入单记录 Banner,缺省时回到当前记录和
|
|
93
|
+
授权 `TableChild` 的语义统计。
|
|
94
|
+
- 未配置的存量表由运行时按字段类型智能推断,不能因为物理字段为空而隐藏或展示空壳。
|
|
95
|
+
只有 `FormBannerEnabled=0` 才隐藏。
|
|
96
|
+
- 完整系统 Manifest 使用 `tables[].formBanner`;未提供时 `microi_generate_system` 仍须写入
|
|
97
|
+
类型感知的默认值。逐步创建字段后调用 `microi_configure_form_banner` 并回读验证。
|
|
98
|
+
- 表单设计器验收必须覆盖有/无图片、有/无统计、子表完整聚合、接口失败回退、浅色、深色、
|
|
99
|
+
PC 和窄屏,并检查文字对比度以及不存在技术字段伪统计。
|
|
100
|
+
|
|
101
|
+
## 物理类型底线
|
|
80
102
|
|
|
81
103
|
MCP 建模只使用:
|
|
82
104
|
|
|
@@ -124,10 +146,10 @@ MCP 建模只使用:
|
|
|
124
146
|
- 语义仍不明确时必须在任何 MCP 写入前询问基数;禁止静默退化为 `JoinForm`。
|
|
125
147
|
- 禁止把“明细”设计为主表 `XxxId + JoinForm`;禁止让 `JoinForm.TableId/TableName`
|
|
126
148
|
指向当前表;禁止把 1:N 外键放在主表。
|
|
127
|
-
- 完整系统 Manifest 中,`JoinForm` / `TableChild` 字段必须声明 `relation.cardinality`;
|
|
128
|
-
`microi_plan_system` 与 `microi_generate_system` 会在任何写入前执行本节门禁。直接调用
|
|
129
|
-
`microi_add_field` / `microi_update_field` 时,后端仍会校验目标表、主/子外键、隐藏菜单
|
|
130
|
-
和子表索引,不能靠绕过 Manifest 写入未初始化配置。
|
|
149
|
+
- 完整系统 Manifest 中,`JoinForm` / `TableChild` 字段必须声明 `relation.cardinality`;
|
|
150
|
+
`microi_plan_system` 与 `microi_generate_system` 会在任何写入前执行本节门禁。直接调用
|
|
151
|
+
`microi_add_field` / `microi_update_field` 时,后端仍会校验目标表、主/子外键、隐藏菜单
|
|
152
|
+
和子表索引,不能靠绕过 Manifest 写入未初始化配置。
|
|
131
153
|
|
|
132
154
|
示例:
|
|
133
155
|
|
|
@@ -143,27 +165,27 @@ MCP 建模只使用:
|
|
|
143
165
|
`tables[].indexes`,并以 `microi_get_table_indexes` 回读。
|
|
144
166
|
3. 为子表创建绑定其 `diyTableId` 的隐藏 CRUD 菜单:`Display=0`、`AppDisplay=0`、
|
|
145
167
|
`HasChild=0`。
|
|
146
|
-
4. 在完整系统 Manifest 的主表字段声明:
|
|
147
|
-
|
|
148
|
-
```json
|
|
149
|
-
{
|
|
150
|
-
"name": "Items",
|
|
151
|
-
"label": "明细",
|
|
152
|
-
"component": "TableChild",
|
|
153
|
-
"formWidth": 24,
|
|
154
|
-
"relation": {
|
|
155
|
-
"cardinality": "1:N",
|
|
156
|
-
"targetTable": "Biz_OrderItem",
|
|
157
|
-
"childForeignKey": "OrderId",
|
|
158
|
-
"childModule": "订单明细(隐藏)",
|
|
159
|
-
"primaryTableFieldName": "Id"
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
`microi_generate_system` 会先创建全部表与普通字段,再创建隐藏菜单,最后回读并写入
|
|
165
|
-
当前租户真实的 `diy_table.Id` / `sys_menu.Id`。禁止在 Manifest 中编造这些 Id,禁止
|
|
166
|
-
因依赖尚未创建而退化成 `JoinForm`。
|
|
168
|
+
4. 在完整系统 Manifest 的主表字段声明:
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"name": "Items",
|
|
173
|
+
"label": "明细",
|
|
174
|
+
"component": "TableChild",
|
|
175
|
+
"formWidth": 24,
|
|
176
|
+
"relation": {
|
|
177
|
+
"cardinality": "1:N",
|
|
178
|
+
"targetTable": "Biz_OrderItem",
|
|
179
|
+
"childForeignKey": "OrderId",
|
|
180
|
+
"childModule": "订单明细(隐藏)",
|
|
181
|
+
"primaryTableFieldName": "Id"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`microi_generate_system` 会先创建全部表与普通字段,再创建隐藏菜单,最后回读并写入
|
|
187
|
+
当前租户真实的 `diy_table.Id` / `sys_menu.Id`。禁止在 Manifest 中编造这些 Id,禁止
|
|
188
|
+
因依赖尚未创建而退化成 `JoinForm`。
|
|
167
189
|
5. `TableChild` 控件字段通常只是表单配置位,关系事实存放在子表外键。至少保存:
|
|
168
190
|
|
|
169
191
|
```json
|
|
@@ -205,23 +227,23 @@ MCP 建模只使用:
|
|
|
205
227
|
优先使用现有 44 类标准控件。只有标准控件无法表达交互、且该交互会长期复用时,
|
|
206
228
|
才使用 `DevComponent`:
|
|
207
229
|
|
|
208
|
-
- 多租户共用且与主框架强耦合的 Vue 组件,路径必须稳定并纳入 `Microi.Client` 源码/构建。
|
|
209
|
-
- 支持 Add/Edit/View、只读、必填、清空、校验、移动端和暗色主题。
|
|
210
|
-
- 不在组件内绕过 FormEngine 权限直接访问任意表。
|
|
211
|
-
- 复杂但租户独有、需要固定嵌入表单的区域,优先使用 `DevComponent` + MicroService 路由;临时打开的复杂页面使用 `V8.OpenAppDialog`,都避免把客户逻辑打进主前端。
|
|
212
|
-
- MicroService 表单嵌入使用 `microi.routes.json` 页面级 `LegacyComponentPaths` 作为稳定别名,字段 `Config.DevComponentPath` 与其匹配。主前端存在同路径 Vue 文件时本地优先;不存在时平台自动加载对应 `sys_microiservice_page.RoutePath`。新别名不得与 `/src/views` 真实文件冲突。
|
|
213
|
-
- 组件宿主下发 `componentMode=true`、可序列化 `componentData` 与 `permissionContext`;子应用用 `dev-component:resize` 同步高度,用 `dev-component:event` 回传 `update:modelValue`、`CallbackFormValueChange`、`FormSet` 或 `ParentFormSet`。不传 Vue 实例、函数、循环引用或 `ParentV8`,不直接操作父页面 DOM。
|
|
214
|
-
- 表单嵌入验收必须覆盖 Add/Edit/View/只读、初始值与回写、自动高度、窄屏、暗色主题,以及当前菜单 `ModuleEngineKey` 下的有权/无权账号。
|
|
215
|
-
- `DevComponent` 配置了非空字段标题时必须正常渲染 Label;只有标题本身为空时才允许隐藏,
|
|
216
|
-
不能按组件类型全局吞掉业务标题。`el-form--label-top` 下的字段级 `Button` 仍保留与其它
|
|
217
|
-
控件等高的不可见 Label 占位,使按钮对齐控件区而不是对齐标题行。
|
|
218
|
-
- 字段显式配置 `FormLabelPosition=left/right/top` 时优先于子表、代码编辑器等特殊组件的默认
|
|
219
|
-
`top` 布局;移动端仍可统一回落到 `top`。验收时必须在真实设计器保存后回读该字段配置。
|
|
220
|
-
- 同一标签行同时显示 `Label` 与 `Description` 时,业务 Label 不允许收缩或省略;说明文字使用
|
|
221
|
-
剩余宽度并以省略号截断,完整说明通过 Element Plus tooltip 提供。自定义组件内部不得再次
|
|
222
|
-
输出与宿主字段相同的标题;需要补充的是说明或安全提示。
|
|
223
|
-
- 权限树勾选子菜单时必须补齐全部祖先菜单的 `Read` 权限,祖先不得被动继承子菜单的增删改查;
|
|
224
|
-
这样既保证路由可见,又避免扩大业务操作权限。
|
|
230
|
+
- 多租户共用且与主框架强耦合的 Vue 组件,路径必须稳定并纳入 `Microi.Client` 源码/构建。
|
|
231
|
+
- 支持 Add/Edit/View、只读、必填、清空、校验、移动端和暗色主题。
|
|
232
|
+
- 不在组件内绕过 FormEngine 权限直接访问任意表。
|
|
233
|
+
- 复杂但租户独有、需要固定嵌入表单的区域,优先使用 `DevComponent` + MicroService 路由;临时打开的复杂页面使用 `V8.OpenAppDialog`,都避免把客户逻辑打进主前端。
|
|
234
|
+
- MicroService 表单嵌入使用 `microi.routes.json` 页面级 `LegacyComponentPaths` 作为稳定别名,字段 `Config.DevComponentPath` 与其匹配。主前端存在同路径 Vue 文件时本地优先;不存在时平台自动加载对应 `sys_microiservice_page.RoutePath`。新别名不得与 `/src/views` 真实文件冲突。
|
|
235
|
+
- 组件宿主下发 `componentMode=true`、可序列化 `componentData` 与 `permissionContext`;子应用用 `dev-component:resize` 同步高度,用 `dev-component:event` 回传 `update:modelValue`、`CallbackFormValueChange`、`FormSet` 或 `ParentFormSet`。不传 Vue 实例、函数、循环引用或 `ParentV8`,不直接操作父页面 DOM。
|
|
236
|
+
- 表单嵌入验收必须覆盖 Add/Edit/View/只读、初始值与回写、自动高度、窄屏、暗色主题,以及当前菜单 `ModuleEngineKey` 下的有权/无权账号。
|
|
237
|
+
- `DevComponent` 配置了非空字段标题时必须正常渲染 Label;只有标题本身为空时才允许隐藏,
|
|
238
|
+
不能按组件类型全局吞掉业务标题。`el-form--label-top` 下的字段级 `Button` 仍保留与其它
|
|
239
|
+
控件等高的不可见 Label 占位,使按钮对齐控件区而不是对齐标题行。
|
|
240
|
+
- 字段显式配置 `FormLabelPosition=left/right/top` 时优先于子表、代码编辑器等特殊组件的默认
|
|
241
|
+
`top` 布局;移动端仍可统一回落到 `top`。验收时必须在真实设计器保存后回读该字段配置。
|
|
242
|
+
- 同一标签行同时显示 `Label` 与 `Description` 时,业务 Label 不允许收缩或省略;说明文字使用
|
|
243
|
+
剩余宽度并以省略号截断,完整说明通过 Element Plus tooltip 提供。自定义组件内部不得再次
|
|
244
|
+
输出与宿主字段相同的标题;需要补充的是说明或安全提示。
|
|
245
|
+
- 权限树勾选子菜单时必须补齐全部祖先菜单的 `Read` 权限,祖先不得被动继承子菜单的增删改查;
|
|
246
|
+
这样既保证路由可见,又避免扩大业务操作权限。
|
|
225
247
|
|
|
226
248
|
## 固定审计字段
|
|
227
249
|
|
|
@@ -62,12 +62,23 @@
|
|
|
62
62
|
| `JoinTable` | 关联集合展示 | 查询与权限在服务端完成 |
|
|
63
63
|
| `JoinForm` | 嵌入一个独立记录的完整表单 | 主表字段保存一个目标 Id;目标表不能与当前表相同 |
|
|
64
64
|
| `TableChild` | 主表内嵌 0..N 条明细列表 | 独立子表、子表真实外键、隐藏子菜单、回查索引 |
|
|
65
|
-
| `Map` | 点位 |
|
|
66
|
-
| `MapArea` | 区域 | `mediumtext
|
|
65
|
+
| `Map` | 点位 | 高德/百度/腾讯;`Config.MapCompany=System/AMap/Baidu/Tencent`;凭据只进租户“安全与服务接入”,不得写字段配置或公开 SysConfig |
|
|
66
|
+
| `MapArea` | 区域 | 与 `Map` 共用供应商安全配置;`mediumtext` 保存 `Paths`,限制路径、点数和体积 |
|
|
67
67
|
| `Qrcode` | 二维码卡片展示 | 优先 `IsVirtual=1`;扫码原文另存普通 `varchar` 字段 |
|
|
68
68
|
| `FontAwesome` | 图标选择 | `varchar(200)` |
|
|
69
69
|
| `DevComponent` | 主前端定制 Vue 控件 | 仅用于长期复用且标准控件无法满足的场景 |
|
|
70
70
|
|
|
71
|
+
### `Map / MapArea` 运行时与安全边界
|
|
72
|
+
|
|
73
|
+
- 渲染事实源是 `Microi.Client/src/views/form-engine/diy-field-component/diy-map.vue`;公共错误分类与安全配置请求在同目录 `map-runtime.js`。
|
|
74
|
+
- 字段只保存 `Config.MapCompany`,值为 `System / AMap / Baidu / Tencent`。禁止把 Key、securityJsCode、Secret 或代理凭据写入 `diy_field.Config`、V8 前端事件、公开 `sys_config` 投影或前端构建变量。
|
|
75
|
+
- 租户凭据使用 `mci_system_setting` 的 `Map.*` 模板,在“系统设置 → 安全与服务接入”由超级管理员维护。运行时由可信后端按 DiyToken 租户和当前供应商做白名单投影,只返回一家的 `ClientKey`,必须 `no-store` 并拒绝访问密钥会话。
|
|
76
|
+
- 旧 `sys_config.AMapKey / AMapSecret / BaiduAK` 仅在对应新设置未启用时兼容回退。不要为迁移直接重新公开这些字段。
|
|
77
|
+
- 旧字段 `Config` 中的 `MapKey / MapSecret / AMapKey / AMapSecret / BaiduAK / TencentMapKey` 等明文属性不属于运行时配置;设计器保存地图配置时必须清除。迁移顺序固定为“先写入并启用租户 `Map.*` Secret,再清理字段元数据”。
|
|
78
|
+
- 浏览器 JS Key 天然可见,必须配置供应商域名/Referer 白名单;高德生产环境优先配置 `Map.AMap.ServiceHost`,存在代理时不得再返回 `SecurityJsCode`。
|
|
79
|
+
- 加载中、缺少 Key、运行时接口不匹配、SDK 网络/超时/鉴权/域名/WebGL/容器尺寸错误必须在控件区域显示明确原因码和重试入口,禁止只 `console.warn/error` 后留下空白地图。
|
|
80
|
+
- `Map` 保持 `{Name}_Lng / {Name}_Lat / {Name}.{Address,Center,Zoom}`;`MapArea` 保持 `{Name}.{Paths,Center,Zoom}`。三家供应商切换不得改变持久化格式。
|
|
81
|
+
|
|
71
82
|
### `JoinForm` 不是子表
|
|
72
83
|
|
|
73
84
|
- `JoinForm` 渲染 `diy-form`,通过 `Config.JoinForm.JoinFieldName` 从当前表单取出一个
|
|
@@ -132,13 +143,73 @@ if (V8.LoadMode !== 'Design') {
|
|
|
132
143
|
| CodeEditor / JsonTable | `CodeEditor.Height`、`JsonTable.Columns`、`JsonTable.Columns[].Config` |
|
|
133
144
|
| JoinForm | `JoinForm.TableId`、`JoinForm.TableName`、`JoinForm.JoinFieldName`、`JoinForm.FormMode`、`JoinForm.Id`、`JoinForm._SearchEqual` |
|
|
134
145
|
| TableChild | Config 根节点的 `TableChildTableId`、`TableChildSysMenuId`、`TableChildFkFieldName`;`TableChild.PrimaryTableFieldName`(默认 `Id`)及分页/导入选项 |
|
|
135
|
-
| ImgUpload | `ImgUpload.Multiple
|
|
146
|
+
| ImgUpload | `ImgUpload.Limit/Multiple/MaxCount/Tips/Preview/MaxSize/SaveFullPath`;`ImgUpload.Crop.Enabled` 仅表示默认开启,另有 `Mode=free/fixed/select`、`Ratio`、`CustomWidth/CustomHeight`、`AllowZoom/AllowRotate/AllowFlip`;运行时在上传面板内提供裁剪开关,裁剪弹层提供“不裁剪直接上传”;导出时会按最大图片数展开列 |
|
|
147
|
+
| FileUpload | `FileUpload.Limit/Multiple/MaxCount/Tips/MaxSize/SaveFullPath`,以及 Office 预览/编辑/版本配置;文件不使用 `ImgUpload.Preview/Crop` |
|
|
148
|
+
| RichText | `RichText.Limit`;`Image.Enabled/MaxSize/MaxCount/Preview/CompressMaxSize/CompressMaxWidth`;`Video.Enabled/MaxSize/MaxCount`;`File.Enabled/MaxSize/MaxCount/Accept`;私有正文存稳定标识而不是临时 URL |
|
|
136
149
|
| Qrcode | `Qrcode.DisplayWidth`、`Qrcode.ShowDownload`、`Qrcode.DownloadText`;扫码内容使用运行态 `DataAppend.Code` |
|
|
137
150
|
|
|
138
151
|
其余选择、树、上传、关联和布局选项以当前字段设计器和
|
|
139
152
|
`microi-db-schema/references/form-component-options.md` 为事实源;不要凭旧截图
|
|
140
153
|
发明配置键。
|
|
141
154
|
|
|
155
|
+
### `ImgUpload / FileUpload` 生成与运行时规则
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"ImgUpload": {
|
|
160
|
+
"Limit": true,
|
|
161
|
+
"Multiple": true,
|
|
162
|
+
"MaxCount": 6,
|
|
163
|
+
"Tips": "支持 JPG、PNG、WebP",
|
|
164
|
+
"Preview": true,
|
|
165
|
+
"MaxSize": 10,
|
|
166
|
+
"SaveFullPath": false,
|
|
167
|
+
"Crop": {
|
|
168
|
+
"Enabled": true,
|
|
169
|
+
"Mode": "select",
|
|
170
|
+
"Ratio": "16:9",
|
|
171
|
+
"CustomWidth": 1,
|
|
172
|
+
"CustomHeight": 1,
|
|
173
|
+
"AllowZoom": true,
|
|
174
|
+
"AllowRotate": true,
|
|
175
|
+
"AllowFlip": true
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- `Limit=true` 表示字段配置为私有桶,`false` 表示配置为公有桶;最终访问仍服从后端租户权限和上传安全策略。
|
|
182
|
+
- `Multiple=true` 时 `MaxCount` 必须是正整数;`MaxSize` 单位为 MB。`Preview` 未配置时按 `true` 压缩,普通列表、卡片、商品图不要关闭。
|
|
183
|
+
- `Crop.Enabled` 只决定运行时裁剪开关的初始状态;`false` 或缺失时用户仍可在紧凑上传面板主动开启。裁剪前原图始终进入 HDFS 私有桶,业务字段只保存展示图元数据。
|
|
184
|
+
- 图片和文件都把拖放提示、存储范围、单/多文件、最大数量、处理方式和最大体积合并到同一个紧凑面板;不要在字段外再生成重复说明卡片。
|
|
185
|
+
|
|
186
|
+
### `RichText` 生成与运行时规则
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"RichText": {
|
|
191
|
+
"EditorProduct": "WangEditor",
|
|
192
|
+
"Limit": true,
|
|
193
|
+
"Image": {
|
|
194
|
+
"Enabled": true,
|
|
195
|
+
"MaxSize": 20,
|
|
196
|
+
"MaxCount": 10,
|
|
197
|
+
"Preview": true,
|
|
198
|
+
"CompressMaxSize": 500,
|
|
199
|
+
"CompressMaxWidth": 1920
|
|
200
|
+
},
|
|
201
|
+
"Video": { "Enabled": true, "MaxSize": 200, "MaxCount": 3 },
|
|
202
|
+
"File": { "Enabled": true, "MaxSize": 100, "MaxCount": 10, "Accept": "" }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
- 公开公告、商品详情等匿名网页内容显式用 `Limit=false`;内部公告、合同说明等用 `true`。旧字段缺失时默认私有,不能由 AI 猜成公有。
|
|
208
|
+
- `MaxSize` 单位 MB,`CompressMaxSize` 单位 KB。图片压缩开启时原图仍先进入 HDFS 私有桶,正文只引用展示图。
|
|
209
|
+
- 私有正文只保存 `/__microi_richtext_private__/...` 稳定标识;运行时携带当前菜单、表、记录和字段上下文换取短效代理 URL,禁止把临时 Token/Ticket 回写字段。
|
|
210
|
+
- 普通文件通过富文本工具栏附件入口插入 `a.href`;私有授权只接受真实 `img/video/source.src` 与 `a.href` 的精确路径,不接受正文文字、`data-*` 或脚本标签。
|
|
211
|
+
- RichText 通常使用 `FormWidth=24`,配置摘要保持单行紧凑,不要再生成独立的大说明卡。
|
|
212
|
+
|
|
142
213
|
## 宽度与重字段
|
|
143
214
|
|
|
144
215
|
- 普通 Text、Select、NumberText、DateTime 默认不写 `FormWidth`。
|
|
@@ -18,14 +18,21 @@ Microi 吾码低代码提供 **三种** 表单分组能力,但每种都有明
|
|
|
18
18
|
表单打开方式与分组是两个独立决策:新表默认 `FormOpenType=Dialog`、
|
|
19
19
|
`FormOpenWidth=80%`。只有约 36 个以上业务字段、至少 2 个大型子表,或同等密度的重型控件
|
|
20
20
|
才评估 Drawer;不能用 Drawer 代替 Tabs/CollapseGroup 的信息架构。Dialog 统一使用居中、可拖动、
|
|
21
|
-
大圆角弹层;Drawer 贴边且不使用大圆角。
|
|
22
|
-
|
|
23
|
-
`CollapseGroup` 的运行态视觉统一使用清爽的白色/主题表面卡片:短主题色指示条、紧凑
|
|
24
|
-
标题、可选图标、单行副标题、标题旁轻量 `x 项` 文案,以及最右侧无底色的折叠箭头。
|
|
21
|
+
大圆角弹层;Drawer 贴边且不使用大圆角。
|
|
22
|
+
|
|
23
|
+
`CollapseGroup` 的运行态视觉统一使用清爽的白色/主题表面卡片:短主题色指示条、紧凑
|
|
24
|
+
标题、可选图标、单行副标题、标题旁轻量 `x 项` 文案,以及最右侧无底色的折叠箭头。
|
|
25
25
|
不得使用整块主题色填充、蓝色大描边或醒目的实心数量胶囊;分组内容与标题属于同一张
|
|
26
26
|
卡片,展开后不再嵌套第二套外框。深色模式使用 Element 主题变量,不能写死白色/蓝色。
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
## 配置类表单的二级分组硬规则
|
|
29
|
+
|
|
30
|
+
- `sys_config`、`sys_user`、SaaS 设置、接口参数、打印/工作流设置等“配置类表单”不能因为已经有表级 Tab 就停止信息架构审计。表级 Tab 只负责一级领域;同一 Tab 内存在 **7 个以上可见设置**或 **2 个以上明确语义域**时,必须继续按语义放入 `CollapseGroup`。
|
|
31
|
+
- 水印、主题、菜单、登录入口、安全策略、桌面偏好等一组相互关联的开关/参数必须由一个带图标、说明、计数的 CollapseGroup 包裹;不能把 5~20 个设置直接平铺在 Tab 中,也不能让每个小设置单独占一个 Tab。
|
|
32
|
+
- 新增设置字段时必须同时审计所在 Tab 的现有字段,而不只是包住本次新增字段。若相邻设置已形成稳定语义域,应一次性补齐该域的 CollapseGroup;隐藏兼容字段继续保留但不计入可见项数。
|
|
33
|
+
- 配置表采用“表级 Tab + Tab 内 CollapseGroup”时,CollapseGroup 必须与成员字段写入同一个 `Tab`,并用连续 `Sort` 保证作用范围在下一个布局节点前结束。发布前必须打开真实编辑表单验证,不能只凭元数据字符串判断布局成功。
|
|
34
|
+
|
|
35
|
+
<!-- microi-progressive:begin -->
|
|
29
36
|
<!-- microi-progressive:chunk id=microi-form-layout-000 sha256=cade6a415454aa04f5fcf840e6d9df1323ac9751c0e3c8e1b07b360007413819 -->
|
|
30
37
|
## 1. 三种分组能力速查
|
|
31
38
|
|
|
@@ -138,8 +145,10 @@ V8 事件中可用 `V8.HideFormTab('tabId')` / `V8.ShowFormTab('tabId')` / `V8.C
|
|
|
138
145
|
- 字段数 13~30 的表单,必须有可见的**业务分组**(Tab 或 CollapseGroup 二选一),不能让用户上下滚动 5 屏找字段。
|
|
139
146
|
- 创建 CollapseGroup 分组时,必须设置 `Icon`(如 `fas fa-calculator` / `fas fa-info-circle`),不要默认空白。
|
|
140
147
|
- 任何 Tab / CollapseGroup 都必须有 `Description` 解释分组用途,不要只放一个标题。
|
|
141
|
-
- 每个 CollapseGroup 必须回读到 `FormWidth=24`;`Config.CollapseGroup.ShowFieldCount` 默认必须为 `true`。
|
|
142
|
-
-
|
|
148
|
+
- 每个 CollapseGroup 必须回读到 `FormWidth=24`;`Config.CollapseGroup.ShowFieldCount` 默认必须为 `true`。
|
|
149
|
+
- 可扩展配置表或设置页的末尾 CollapseGroup 不得无边界使用 `ScopeMode=UntilNextGroup`。已知标准子项数量时必须改用 `ScopeMode=FieldCount` 并显式保存准确 `FieldCount`;否则必须增加后续分组边界,避免未来新增字段或租户扩展字段被末尾分组误吞。
|
|
150
|
+
- 表级 Tab 与 CollapseGroup 的 `Description` 作为副标题显示;开启计数时统一追加 `x 项`,禁止继续显示 `x 个字段`。运行时动态显隐字段后必须重算计数,已有数字角标配置继续生效,不能被静态字段数覆盖。
|
|
151
|
+
- 分组/Tab 的字段计数必须基于字段原始可见性(如 `_baseIsShow`),不能把“当前因折叠而隐藏”误判成不可见,否则收起后的分组会错误显示 `0 项`。
|
|
143
152
|
- 表级分组方向完整支持 `TabsPosition=left/top/right/bottom`;每个方向都要检查标题、副标题、动态角标和选中指示线,纵向指示线端点固定为直角。
|
|
144
153
|
- 修改 `diy_table.Tabs` 或 `diy_field.Tab` / `Config.CollapseGroup` / `Config.FieldTabs` 后,必须调用 `microi_refresh_schema_cache`。
|
|
145
154
|
- Tab 内嵌套 CollapseGroup 时,CollapseGroup 必须设 `DefaultCollapsed=true`(默认收起),避免 Tab 内继续被折叠分组抢首屏空间。
|
|
@@ -169,3 +169,7 @@ if (ctx.token && ctx.token !== appliedHostToken) {
|
|
|
169
169
|
|
|
170
170
|
普通 `request`、浏览器 `fetch(FormData)` 上传和 `uni.uploadFile` 都必须读取响应头的新 Token。验收时必须连续执行至少两个需要登录态的请求(前一个允许发生 Token 轮换),确认后一个仍返回 `Code=1`;不能只看页面首屏渲染成功。
|
|
171
171
|
<!-- /microi-progressive:chunk -->
|
|
172
|
+
|
|
173
|
+
## 运行时 ApiBase / OsClient 切换
|
|
174
|
+
|
|
175
|
+
允许用户切换平台的客户端必须把 `ApiBase + OsClient` 视为完整安全边界,而不是只替换请求 URL。候选端点应先匿名探测,成功后再原子更新配置并清除旧 Token、用户和平台派生缓存;账号、RSA 密文、菜单、表元数据和页面状态不得跨边界复用。SDK 每次修改 `apiBase` 或 `osClient` 都必须推进端点代次,请求记录发起时代次,并在处理响应头 Token、鉴权失效或响应体之前拒绝旧代次的迟到响应。验收至少覆盖“旧平台登录请求未返回 -> 切换平台 -> 旧响应携带 Token 返回”,并确认旧 Token 没有写入、新请求只发送一个新 `osclient`。
|
|
@@ -207,3 +207,7 @@ Microi.Client 的标准模块移动端不应把 PC 表格字段机械纵向堆
|
|
|
207
207
|
- 构建 H5 和微信小程序目标。
|
|
208
208
|
|
|
209
209
|
<!-- /microi-progressive:chunk -->
|
|
210
|
+
|
|
211
|
+
## 平台方通用 App 的登录连接器例外
|
|
212
|
+
|
|
213
|
+
“登录页不要展示 ApiBase / OsClient”仍是 H5、小程序与客户专属 App 的默认规则。只有用户明确要求、并由平台方提交一个聚合多租户的通用 `APP-PLUS` 安装包时,才允许把平台连接器作为登录页次级折叠卡片;必须保留清晰的当前连接摘要、固定协议下拉、HTTP 风险提示、带图标的应用按钮、连接 loading/disabled 状态,并在展开后通过滚动和安全区保证小屏设备不裁切登录操作。连接器不能伪装成调试面板,也不能展示 Token、密码或其它秘密。
|