@microi.net/cli 5.7.8 → 5.8.0

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.
Files changed (189) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/LICENSE +21 -21
  7. package/README.md +71 -71
  8. package/assets/build-meta.json +6 -6
  9. package/assets/feature-matrix.json +138 -138
  10. package/assets/logo.svg +4 -4
  11. package/cordis.patch.yml +1 -1
  12. package/package.json +1 -1
  13. package/scripts/mcp-codex-stdio-adapter.js +0 -0
  14. package/scripts/mcp-server.js +113 -112
  15. package/scripts/microi-cli.js +57 -57
  16. package/scripts/microi-codex-broker.js +450 -450
  17. package/scripts/microi-codex-router.js +0 -0
  18. package/scripts/microi-skills.meta.json +364 -364
  19. package/skills/.microi-skills-version.json +2 -2
  20. package/skills/README.md +286 -286
  21. package/skills/ai-engine/SKILL.md +265 -265
  22. package/skills/ai-engine/agents/openai.yaml +4 -4
  23. package/skills/ai-platform-governance/SKILL.md +177 -177
  24. package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -190
  25. package/skills/app-store/SKILL.md +396 -396
  26. package/skills/app-store/agents/openai.yaml +4 -4
  27. package/skills/business-blueprint/SKILL.md +193 -193
  28. package/skills/datasource-engine/SKILL.md +90 -90
  29. package/skills/datasource-engine/agents/openai.yaml +4 -4
  30. package/skills/dos-orm/references/api-reference.md +229 -229
  31. package/skills/email-engine/SKILL.md +78 -78
  32. package/skills/email-engine/references/v8-email.md +34 -34
  33. package/skills/job-engine/SKILL.md +172 -172
  34. package/skills/job-engine/agents/openai.yaml +4 -4
  35. package/skills/message-notification/SKILL.md +156 -156
  36. package/skills/message-notification/agents/openai.yaml +5 -5
  37. package/skills/message-notification/references/contracts.md +102 -102
  38. package/skills/microi-ai-app-auth.js +652 -652
  39. package/skills/microi-ai-application/SKILL.md +106 -106
  40. package/skills/microi-ai-application/agents/openai.yaml +4 -4
  41. package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
  42. package/skills/microi-client-frontend/SKILL.md +237 -237
  43. package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +144 -144
  44. package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +196 -196
  45. package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +167 -167
  46. package/skills/microi-codex/SKILL.md +72 -70
  47. package/skills/microi-codex-installer/SKILL.md +225 -223
  48. package/skills/microi-codex-installer/agents/openai.yaml +7 -7
  49. package/skills/microi-datasource-mapping/SKILL.md +108 -108
  50. package/skills/microi-db-schema/SKILL.md +175 -175
  51. package/skills/microi-db-schema/agents/openai.yaml +4 -4
  52. package/skills/microi-db-schema/references/core-tables.md +695 -695
  53. package/skills/microi-db-schema/references/form-component-options.md +256 -256
  54. package/skills/microi-db-schema/references/schema-overview.md +202 -202
  55. package/skills/microi-db-schema/references/schema.md +646 -646
  56. package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
  57. package/skills/microi-deployment/references/deployment-matrix.md +101 -101
  58. package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
  59. package/skills/microi-form-engine/SKILL.md +226 -226
  60. package/skills/microi-form-engine/references/component-catalog.md +216 -216
  61. package/skills/microi-form-engine/references/data-source-events.md +124 -124
  62. package/skills/microi-form-layout/SKILL.md +205 -205
  63. package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -235
  64. package/skills/microi-frontend-sdk/SKILL.md +188 -188
  65. 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 +176 -176
  66. package/skills/microi-left-right-layout/SKILL.md +141 -141
  67. package/skills/microi-microservice/SKILL.md +323 -323
  68. package/skills/microi-microservice/references/runtime-delivery.md +278 -278
  69. package/skills/microi-mobile-app-quality/SKILL.md +181 -181
  70. 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 +213 -213
  71. package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +128 -128
  72. package/skills/microi-solution-quotation/SKILL.md +78 -78
  73. package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
  74. package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
  75. package/skills/microi-sso/references/acceptance.md +49 -49
  76. package/skills/microi-sso/references/configuration-and-security.md +53 -53
  77. package/skills/microi-sso/references/inbound.md +53 -53
  78. package/skills/microi-sso/references/outbound.md +39 -39
  79. package/skills/microi-system-delivery/SKILL.md +134 -134
  80. package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +193 -193
  81. package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +189 -189
  82. package/skills/microi-ui/SKILL.md +174 -174
  83. package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -183
  84. package/skills/microi-uniapp-frontend/SKILL.md +193 -193
  85. package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -225
  86. package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -154
  87. package/skills/microi.v8.js +1921 -1921
  88. package/skills/module-engine/SKILL.md +250 -250
  89. package/skills/module-engine/references/module-config.md +204 -204
  90. package/skills/ocr-engine/SKILL.md +113 -113
  91. package/skills/ocr-engine/agents/openai.yaml +4 -4
  92. package/skills/page-engine/SKILL.md +182 -182
  93. package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -234
  94. package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -60
  95. package/skills/performance-testing/SKILL.md +221 -221
  96. package/skills/playwright-e2e/SKILL.md +197 -197
  97. package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -173
  98. package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -183
  99. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -221
  100. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +115 -115
  101. package/skills/print-engine/SKILL.md +259 -259
  102. package/skills/production-readonly-audit/SKILL.md +41 -41
  103. package/skills/report-engine/SKILL.md +71 -71
  104. package/skills/report-engine/agents/openai.yaml +4 -4
  105. package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
  106. package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
  107. package/skills/search-engine/SKILL.md +75 -75
  108. package/skills/search-engine/agents/openai.yaml +4 -4
  109. package/skills/spider-engine/SKILL.md +190 -190
  110. package/skills/system-observability/SKILL.md +238 -238
  111. package/skills/system-observability/references/memory-incident-triage.md +70 -70
  112. package/skills/translate-engine/SKILL.md +140 -140
  113. package/skills/translate-engine/agents/openai.yaml +4 -4
  114. package/skills/ui-design/SKILL.md +191 -191
  115. package/skills/ui-design/assets/templates/MCI-DESIGN.md +198 -198
  116. package/skills/ui-design/references/design-pattern-library.md +184 -184
  117. package/skills/ui-design/references/mci-design-contract.md +163 -163
  118. package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -218
  119. package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +137 -137
  120. package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -235
  121. package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -152
  122. package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -238
  123. package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -194
  124. package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -207
  125. package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +117 -117
  126. package/skills/uniapp-mall-assets/SKILL.md +176 -176
  127. package/skills/unity-integration/SKILL.md +155 -155
  128. package/skills/unity-integration/agents/openai.yaml +4 -4
  129. package/skills/unity-integration/references/ai-app-delivery.md +103 -103
  130. package/skills/unity-integration/references/sdk-api.md +82 -82
  131. package/skills/unity-integration/references/toolbox-migration.md +66 -66
  132. package/skills/unity-integration/references/webgl-hosting.md +57 -57
  133. package/skills/v8-cache-pattern/SKILL.md +306 -306
  134. package/skills/v8-crud-api/SKILL.md +175 -175
  135. package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -226
  136. package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -49
  137. package/skills/v8-debugging/SKILL.md +284 -284
  138. package/skills/v8-explorer-tree/SKILL.md +228 -228
  139. package/skills/v8-export-import/SKILL.md +209 -209
  140. package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -211
  141. package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -202
  142. package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -42
  143. package/skills/v8-file-upload/SKILL.md +263 -263
  144. 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 +101 -101
  145. package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +150 -150
  146. package/skills/v8-formengine-http/SKILL.md +219 -219
  147. package/skills/v8-frontend-events/SKILL.md +178 -178
  148. package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
  149. package/skills/v8-frontend-events/references/bluetooth-print.md +246 -246
  150. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -219
  151. package/skills/v8-http-integration/SKILL.md +182 -182
  152. package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -220
  153. package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -44
  154. package/skills/v8-image-processing/SKILL.md +190 -190
  155. package/skills/v8-image-processing/agents/openai.yaml +4 -4
  156. package/skills/v8-image-processing/references/api-reference.md +623 -623
  157. package/skills/v8-menu-buttons/SKILL.md +180 -180
  158. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +222 -222
  159. package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +228 -228
  160. package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -104
  161. package/skills/v8-mongodb/SKILL.md +192 -192
  162. package/skills/v8-mq-mqtt/SKILL.md +176 -176
  163. package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
  164. package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -181
  165. package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
  166. package/skills/v8-saas-multi-tenant/SKILL.md +219 -219
  167. package/skills/v8-security/SKILL.md +168 -168
  168. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +198 -198
  169. package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +158 -158
  170. package/skills/v8-sql-query/SKILL.md +302 -302
  171. package/skills/v8-table-event/SKILL.md +144 -144
  172. package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +197 -197
  173. package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -46
  174. package/skills/v8-tcp-integration/SKILL.md +147 -147
  175. package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
  176. package/skills/v8-template-engine/SKILL.md +167 -167
  177. package/skills/v8-utilities/SKILL.md +90 -90
  178. package/skills/v8-utilities/references/client-api-index.md +143 -143
  179. package/skills/v8-utilities/references/platform-http-routes.md +83 -83
  180. package/skills/v8-utilities/references/server-api-index.md +188 -188
  181. package/skills/v8-workflow/SKILL.md +243 -243
  182. package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -180
  183. package/skills/vision-engine/SKILL.md +159 -159
  184. package/skills/vision-engine/agents/openai.yaml +4 -4
  185. package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
  186. package/skills/workspace-conventions/SKILL.md +261 -261
  187. package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +208 -208
  188. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +216 -216
  189. package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +27 -27
@@ -1,95 +1,95 @@
1
- ---
2
- name: v8-formengine-http
3
- description: 移动端 / 外部系统通过 HTTP 直接调用 Microi FormEngine(GetTableData / GetFormData / Add / Upt / Del)的 RESTful 路由约定与排错指南
4
- ---
5
-
6
- > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
-
8
- # FormEngine HTTP 路由约定(外部系统调用)
9
-
10
- > 适用于:uni-app H5、原生 App、Postman、第三方系统、Playwright/Cypress 自动化测试等任何**没有进入 V8 引擎**的客户端。
11
- > 不适用于:服务器端 V8 接口引擎内部 — 那种情况请直接 `V8.FormEngine.GetTableData(...)`。
12
-
13
- ## ⚠️ 最常见错误
14
-
15
- ```text
16
- ❌ POST /formengine/{表名}/gettabledata → 404
17
- ❌ POST /api/formengine/{表名}/gettabledata → 404
18
- ✅ POST /api/formengine/gettabledata-{表名} → OK (动态短路由)
19
- ✅ POST /api/formengine/GetTableData body 中带 FormEngineKey → OK (标准路由)
20
- ```
21
-
22
- 平台路由由 `Microi.Server/Microi.net.Api/Handler/DynamicApiEngine.cs` 的 `FormEngineRoutes` 字典决定,**只认上面两种形式**。
23
-
24
- ## 路由总表
25
-
26
- ### 形式一:标准 Controller 路由 — 推荐
27
- 全部为 `POST`,URL 不含表名,`FormEngineKey` 放在 Body 中。
28
-
29
- | URL | 动作 |
30
- | --- | --- |
31
- | `/api/formengine/GetFormData` | 取一条 |
32
- | `/api/formengine/GetTableData` | 取列表(分页) |
33
- | `/api/formengine/AddFormData` | 新增 |
34
- | `/api/formengine/UptFormData` | 按 Id 修改 |
35
- | `/api/formengine/UptFormDataByWhere` | 按 _Where 批量改 |
36
- | `/api/formengine/DelFormData` | 删除(Id / Ids) |
37
- | `/api/formengine/DelFormDataByWhere` | 按 _Where 批量删 |
38
- | `/api/formengine/GetFormDataAnonymous` | 匿名取一条 |
39
- | `/api/formengine/GetTableDataAnonymous` | 匿名取列表 |
40
- | `/api/formengine/AddFormDataAnonymous` | 匿名新增 |
41
-
42
- ### 形式二:动态短路由(表名写进 URL,URL-friendly)
43
- | URL 前缀 | 等价于 |
44
- | --- | --- |
45
- | `/api/formengine/getformdata-{table}` | `/api/formengine/GetFormData` |
46
- | `/api/formengine/get-formdata-{table}` | `/api/formengine/GetFormData` |
47
- | `/api/formengine/gettabledata-{table}` | `/api/formengine/GetTableData` |
48
- | `/api/formengine/get-tabledata-{table}` | `/api/formengine/GetTableData` |
49
- | `/api/formengine/addformdata-{table}` | `/api/formengine/AddFormData` |
50
- | `/api/formengine/add-formdata-{table}` | `/api/formengine/AddFormData` |
51
- | `/api/formengine/uptformdata-{table}` | `/api/formengine/UptFormData` |
52
- | `/api/formengine/upt-formdata-{table}` | `/api/formengine/UptFormData` |
53
- | `/api/formengine/delformdata-{table}` | `/api/formengine/DelFormData` |
54
- | `/api/formengine/del-formdata-{table}` | `/api/formengine/DelFormData` |
55
-
56
- URL 中的表名小写最稳,平台不区分大小写。匿名版本目前**只在形式一上有**(`GetTableDataAnonymous` 等)。
57
-
58
- ## 请求 Header
59
-
60
- | Header | 是否必填 | 说明 |
61
- | --- | --- | --- |
62
- | `Content-Type` | 必填 | `application/json` 推荐 |
63
- | `OsClient` | 必填 | 租户标识;亦可放 querystring `?OsClient=xxx` 或 body |
64
- | `authorization` | 鉴权接口必填 | `Bearer <Token>`;兼容旧客户端的 `Token` Header |
65
- | `did` | 登录及鉴权接口推荐 | 当前终端稳定设备标识;首次生成后持久化,不能每次请求随机变化 |
66
-
67
- 注意:上表是 FormEngine 路由约定。ApiEngine HTTP 复测和移动端 `callEngine` 使用稳定路径 `/apiengine/{key}`,租户通过唯一的 `osclient` Header 传递,JSON/Form Body 可冗余携带 `OsClient`。普通 POST/PUT/PATCH/DELETE 禁止追加 `--OsClient--...--`;特殊路径只用于无法设置 Header/Form/Query 的 GET/HEAD 或第三方回调。
68
-
69
- 平台可能通过响应 Header `authorization`(兼容 `token`)续签或替换 Token。客户端必须立即保存新 Token,并保证并发旧响应不能覆盖已经写入的新 Token。跨域部署还必须在 CORS 中暴露 `authorization`、`token` 等需要读取的响应 Header。Token 属于凭据,禁止写入 URL、日志、错误上报和页面源码。
70
-
71
- ## FormEngine 数据授权边界
72
-
73
- “Token 有效”只代表身份有效,不代表可以访问任意表。客户端 FormEngine CRUD 还会经过表、菜单、角色和行级范围授权:
74
-
75
- 1. 受保护的平台敏感表优先拒绝普通用户;匿名接口也不能绕过。
76
- 2. 标准菜单页应携带真实 `_SysMenuId`,或使用 `ModuleEngineKey`。服务器会严格校验该菜单是否绑定目标表、当前角色是否拥有菜单及对应操作权限;列表、计数、导出追加该菜单的数据范围。
77
- 3. 列表、写入、导入、导出显式传错 `_SysMenuId` / `ModuleEngineKey` 会直接拒绝,不会降级为其它菜单或表权限。单行详情只要当前角色拥有至少一个直接绑定同表的菜单(或精确表级 `Read` 权限)即可读取,不应用菜单 `SqlWhere` / `SqlJoin`;旧客户端携带过期菜单 Id 时也按该规则恢复。
78
- 4. 为兼容历史前端 V8/外部客户端,普通 CRUD 未传菜单上下文时,服务器会从当前用户的版本化授权缓存中查找“当前角色已获授权且直接绑定目标表”的菜单。无菜单列表仍安全合并候选菜单的数据范围,不能靠漏参绕过;详情按同表菜单访问,写入按 `Add/Edit/Del` 动作权限。也可以使用角色的精确表级 `Read/Add/Edit/Del` 授权。`JoinTables` 不是独立访问授权。
79
- 5. 导入、导出必须锚定具体菜单,不能依赖无菜单兼容推断。
80
- 6. `TableChild` 子表委托由标准表单运行时生成 `_TableChildAuth`,服务器重新校验父菜单、父记录、字段绑定、子表和外键,并强制父子范围。它是内部不透明上下文,外部客户端不要手工拼装。
81
- 7. `_InvokeType:'Client'` 只决定是否执行客户端语义的表单事件,不是权限开关。可信服务器调用标记也不能通过 HTTP Body 伪造。
82
-
83
- 因此:
84
-
85
- - 标准模块、详情页和其字段元数据请求优先传真实 `_SysMenuId`,使服务器确定菜单绑定与操作权限;其中只有列表、计数、导出应用菜单查询范围。
86
- - 历史无 `_SysMenuId` 请求可继续工作,但前提是当前用户确实拥有目标表对应的菜单或精确表权限;不能把兼容推断理解为“有 Token 即可查表”。
87
- - 历史单表字段请求可在菜单缺失/过期时回退到当前角色另一个引用同表的已授权菜单;`GetDiyFieldByDiyTables` 批量字段请求按“第一张主表必须授权、后续表逐张授权并过滤”兼容。后续未授权/保护表不会导致主表失败,也不会返回其字段配置;这些规则不授予数据行权限。
88
- - 表单设计器 `/api/DiyField/UptDiyFieldList` 属于 `Level >= 9999` 控制面:外层一次授权、字段归属校验、同事务批量更新、批次末一次缓存/版本刷新。禁止在 100+ 字段循环中逐条调用完整 `UptFormDataAsync("diy_field", ...)`,否则会重复执行授权、V8、日志及 SaaS/Redis 缓存工作。
89
- - 接口引擎内的 `V8.FormEngine.*` 属于服务器端调用,不要求客户端 `_SysMenuId`。但接口引擎本身必须正确限制谁能调用,并在服务端校验业务对象范围,不能把表名和条件原样交给不可信客户端。
90
- - 客户端新增、修改、删除分别校验真实菜单的 `Add`、`Edit`、`Del` 权限。`SqlWhere` / `SqlJoin` 是模块查询过滤,不是行级写权限:不得把它们追加到写入 SQL,也不得因查询包含 Join 拒绝已获授权的主表写入。
91
- - 进入 `SubmitBeforeServerV8` / `SubmitAfterServerV8` 后,事件内 FormEngine/数据库调用与接口引擎一样属于可信服务器执行,可实现当前租户内的跨表事务。需要“只能修改本人数据”等业务约束以及归属字段写入时,应在这里或专用接口引擎中完成。
92
-
1
+ ---
2
+ name: v8-formengine-http
3
+ description: 移动端 / 外部系统通过 HTTP 直接调用 Microi FormEngine(GetTableData / GetFormData / Add / Upt / Del)的 RESTful 路由约定与排错指南
4
+ ---
5
+
6
+ > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
+
8
+ # FormEngine HTTP 路由约定(外部系统调用)
9
+
10
+ > 适用于:uni-app H5、原生 App、Postman、第三方系统、Playwright/Cypress 自动化测试等任何**没有进入 V8 引擎**的客户端。
11
+ > 不适用于:服务器端 V8 接口引擎内部 — 那种情况请直接 `V8.FormEngine.GetTableData(...)`。
12
+
13
+ ## ⚠️ 最常见错误
14
+
15
+ ```text
16
+ ❌ POST /formengine/{表名}/gettabledata → 404
17
+ ❌ POST /api/formengine/{表名}/gettabledata → 404
18
+ ✅ POST /api/formengine/gettabledata-{表名} → OK (动态短路由)
19
+ ✅ POST /api/formengine/GetTableData body 中带 FormEngineKey → OK (标准路由)
20
+ ```
21
+
22
+ 平台路由由 `Microi.Server/Microi.net.Api/Handler/DynamicApiEngine.cs` 的 `FormEngineRoutes` 字典决定,**只认上面两种形式**。
23
+
24
+ ## 路由总表
25
+
26
+ ### 形式一:标准 Controller 路由 — 推荐
27
+ 全部为 `POST`,URL 不含表名,`FormEngineKey` 放在 Body 中。
28
+
29
+ | URL | 动作 |
30
+ | --- | --- |
31
+ | `/api/formengine/GetFormData` | 取一条 |
32
+ | `/api/formengine/GetTableData` | 取列表(分页) |
33
+ | `/api/formengine/AddFormData` | 新增 |
34
+ | `/api/formengine/UptFormData` | 按 Id 修改 |
35
+ | `/api/formengine/UptFormDataByWhere` | 按 _Where 批量改 |
36
+ | `/api/formengine/DelFormData` | 删除(Id / Ids) |
37
+ | `/api/formengine/DelFormDataByWhere` | 按 _Where 批量删 |
38
+ | `/api/formengine/GetFormDataAnonymous` | 匿名取一条 |
39
+ | `/api/formengine/GetTableDataAnonymous` | 匿名取列表 |
40
+ | `/api/formengine/AddFormDataAnonymous` | 匿名新增 |
41
+
42
+ ### 形式二:动态短路由(表名写进 URL,URL-friendly)
43
+ | URL 前缀 | 等价于 |
44
+ | --- | --- |
45
+ | `/api/formengine/getformdata-{table}` | `/api/formengine/GetFormData` |
46
+ | `/api/formengine/get-formdata-{table}` | `/api/formengine/GetFormData` |
47
+ | `/api/formengine/gettabledata-{table}` | `/api/formengine/GetTableData` |
48
+ | `/api/formengine/get-tabledata-{table}` | `/api/formengine/GetTableData` |
49
+ | `/api/formengine/addformdata-{table}` | `/api/formengine/AddFormData` |
50
+ | `/api/formengine/add-formdata-{table}` | `/api/formengine/AddFormData` |
51
+ | `/api/formengine/uptformdata-{table}` | `/api/formengine/UptFormData` |
52
+ | `/api/formengine/upt-formdata-{table}` | `/api/formengine/UptFormData` |
53
+ | `/api/formengine/delformdata-{table}` | `/api/formengine/DelFormData` |
54
+ | `/api/formengine/del-formdata-{table}` | `/api/formengine/DelFormData` |
55
+
56
+ URL 中的表名小写最稳,平台不区分大小写。匿名版本目前**只在形式一上有**(`GetTableDataAnonymous` 等)。
57
+
58
+ ## 请求 Header
59
+
60
+ | Header | 是否必填 | 说明 |
61
+ | --- | --- | --- |
62
+ | `Content-Type` | 必填 | `application/json` 推荐 |
63
+ | `OsClient` | 必填 | 租户标识;亦可放 querystring `?OsClient=xxx` 或 body |
64
+ | `authorization` | 鉴权接口必填 | `Bearer <Token>`;兼容旧客户端的 `Token` Header |
65
+ | `did` | 登录及鉴权接口推荐 | 当前终端稳定设备标识;首次生成后持久化,不能每次请求随机变化 |
66
+
67
+ 注意:上表是 FormEngine 路由约定。ApiEngine HTTP 复测和移动端 `callEngine` 使用稳定路径 `/apiengine/{key}`,租户通过唯一的 `osclient` Header 传递,JSON/Form Body 可冗余携带 `OsClient`。普通 POST/PUT/PATCH/DELETE 禁止追加 `--OsClient--...--`;特殊路径只用于无法设置 Header/Form/Query 的 GET/HEAD 或第三方回调。
68
+
69
+ 平台可能通过响应 Header `authorization`(兼容 `token`)续签或替换 Token。客户端必须立即保存新 Token,并保证并发旧响应不能覆盖已经写入的新 Token。跨域部署还必须在 CORS 中暴露 `authorization`、`token` 等需要读取的响应 Header。Token 属于凭据,禁止写入 URL、日志、错误上报和页面源码。
70
+
71
+ ## FormEngine 数据授权边界
72
+
73
+ “Token 有效”只代表身份有效,不代表可以访问任意表。客户端 FormEngine CRUD 还会经过表、菜单、角色和行级范围授权:
74
+
75
+ 1. 受保护的平台敏感表优先拒绝普通用户;匿名接口也不能绕过。
76
+ 2. 标准菜单页应携带真实 `_SysMenuId`,或使用 `ModuleEngineKey`。服务器会严格校验该菜单是否绑定目标表、当前角色是否拥有菜单及对应操作权限;列表、计数、导出追加该菜单的数据范围。
77
+ 3. 列表、写入、导入、导出显式传错 `_SysMenuId` / `ModuleEngineKey` 会直接拒绝,不会降级为其它菜单或表权限。单行详情只要当前角色拥有至少一个直接绑定同表的菜单(或精确表级 `Read` 权限)即可读取,不应用菜单 `SqlWhere` / `SqlJoin`;旧客户端携带过期菜单 Id 时也按该规则恢复。
78
+ 4. 为兼容历史前端 V8/外部客户端,普通 CRUD 未传菜单上下文时,服务器会从当前用户的版本化授权缓存中查找“当前角色已获授权且直接绑定目标表”的菜单。无菜单列表仍安全合并候选菜单的数据范围,不能靠漏参绕过;详情按同表菜单访问,写入按 `Add/Edit/Del` 动作权限。也可以使用角色的精确表级 `Read/Add/Edit/Del` 授权。`JoinTables` 不是独立访问授权。
79
+ 5. 导入、导出必须锚定具体菜单,不能依赖无菜单兼容推断。
80
+ 6. `TableChild` 子表委托由标准表单运行时生成 `_TableChildAuth`,服务器重新校验父菜单、父记录、字段绑定、子表和外键,并强制父子范围。它是内部不透明上下文,外部客户端不要手工拼装。
81
+ 7. `_InvokeType:'Client'` 只决定是否执行客户端语义的表单事件,不是权限开关。可信服务器调用标记也不能通过 HTTP Body 伪造。
82
+
83
+ 因此:
84
+
85
+ - 标准模块、详情页和其字段元数据请求优先传真实 `_SysMenuId`,使服务器确定菜单绑定与操作权限;其中只有列表、计数、导出应用菜单查询范围。
86
+ - 历史无 `_SysMenuId` 请求可继续工作,但前提是当前用户确实拥有目标表对应的菜单或精确表权限;不能把兼容推断理解为“有 Token 即可查表”。
87
+ - 历史单表字段请求可在菜单缺失/过期时回退到当前角色另一个引用同表的已授权菜单;`GetDiyFieldByDiyTables` 批量字段请求按“第一张主表必须授权、后续表逐张授权并过滤”兼容。后续未授权/保护表不会导致主表失败,也不会返回其字段配置;这些规则不授予数据行权限。
88
+ - 表单设计器 `/api/DiyField/UptDiyFieldList` 属于 `Level >= 9999` 控制面:外层一次授权、字段归属校验、同事务批量更新、批次末一次缓存/版本刷新。禁止在 100+ 字段循环中逐条调用完整 `UptFormDataAsync("diy_field", ...)`,否则会重复执行授权、V8、日志及 SaaS/Redis 缓存工作。
89
+ - 接口引擎内的 `V8.FormEngine.*` 属于服务器端调用,不要求客户端 `_SysMenuId`。但接口引擎本身必须正确限制谁能调用,并在服务端校验业务对象范围,不能把表名和条件原样交给不可信客户端。
90
+ - 客户端新增、修改、删除分别校验真实菜单的 `Add`、`Edit`、`Del` 权限。`SqlWhere` / `SqlJoin` 是模块查询过滤,不是行级写权限:不得把它们追加到写入 SQL,也不得因查询包含 Join 拒绝已获授权的主表写入。
91
+ - 进入 `SubmitBeforeServerV8` / `SubmitAfterServerV8` 后,事件内 FormEngine/数据库调用与接口引擎一样属于可信服务器执行,可实现当前租户内的跨表事务。需要“只能修改本人数据”等业务约束以及归属字段写入时,应在这里或专用接口引擎中完成。
92
+
93
93
  ## 原生详情关联数据
94
94
 
95
95
  - `POST /api/FormEngine/GetFormRelatedData` 接收父表 `ParentFormEngineKey`、父记录
@@ -109,130 +109,130 @@ URL 中的表名小写最稳,平台不区分大小写。匿名版本目前**
109
109
  安全评论绑定写入及旧数据处理须独立交付后才能宣称评论完整可用。
110
110
 
111
111
  ## Body 结构(POST JSON)
112
-
113
- ```jsonc
114
- {
115
- "OsClient": "demo",
116
- "FormEngineKey": "mall_product", // 形式一必填;形式二可选(已在 URL 中)
117
- "_SysMenuId": "目标菜单Id", // 标准模块推荐;必须是真实绑定目标表且当前角色有权访问的菜单
118
- "_Where": [["Status","=","OnSale"], ["AND","Stock",">",0]],
119
- "_SelectFields": ["Id","Title","CurrentPrice","MainImg"],
120
- "_OrderBy": "SoldCount",
121
- "_OrderByType": "DESC",
122
- "_PageIndex": 1,
123
- "_PageSize": 20
124
- }
125
- ```
126
-
127
- 写操作(Add/Upt)将业务字段平铺到 body:
128
- ```jsonc
129
- { "OsClient":"demo", "FormEngineKey":"biz_order",
130
- "Id":"01ABC...", "Quantity": 2, "Selected": 1 }
131
- ```
132
-
133
- ## 响应 DosResult 标准格式
134
-
135
- ```jsonc
136
- { "Code": 1, "Data": [...], "DataCount": 123, "Msg": "" }
137
- ```
138
- | Code | 含义 |
139
- | --- | --- |
140
- | 1 | 成功 |
141
- | 0 | 业务失败(看 `Msg`) |
142
- | 1001 | 登录身份已过期 / Token 无效 |
143
- | 1002 | 身份验证失败(OsClient 与 Token 不匹配) |
144
-
145
- ## 客户端封装样板(uni-app)
146
-
147
- ```javascript
148
- const BASE = 'https://api.itdos.com';
149
- const OS_CLIENT = runtimeConfig.osClient;
150
- const TOKEN_KEY = 'mall_token';
151
- const DID_KEY = 'mall_did';
152
-
153
- function normalizeToken(value) {
154
- return String(value || '').replace(/^Bearer\s+/i, '').trim();
155
- }
156
- function getToken() {
157
- return normalizeToken(uni.getStorageSync(TOKEN_KEY));
158
- }
159
- function getDid() {
160
- let did = uni.getStorageSync(DID_KEY);
161
- if (!did) {
162
- did = `uni-${Date.now()}-${Math.random().toString(36).slice(2)}`;
163
- uni.setStorageSync(DID_KEY, did);
164
- }
165
- return did;
166
- }
167
- function readHeader(headers, name) {
168
- const key = Object.keys(headers || {}).find(k => k.toLowerCase() === name);
169
- return key ? headers[key] : '';
170
- }
171
- function applyResponseToken(headers, requestToken) {
172
- const responseToken = normalizeToken(
173
- readHeader(headers, 'authorization') || readHeader(headers, 'token')
174
- );
175
- if (!responseToken) return;
176
-
177
- const currentToken = getToken();
178
- // 旧请求若只回显旧 Token,不得覆盖其它请求/标签页已保存的新 Token。
179
- if (currentToken && requestToken && currentToken !== requestToken && responseToken === requestToken) {
180
- return;
181
- }
182
- uni.setStorageSync(TOKEN_KEY, responseToken);
183
- }
184
-
185
- function formEngineRequest(action, table, body = {}) {
186
- return new Promise((resolve, reject) => {
187
- const requestToken = getToken();
188
- uni.request({
189
- url: `${BASE}/api/formengine/${action}-${table}`,
190
- method: 'POST',
191
- header: {
192
- 'Content-Type': 'application/json',
193
- 'OsClient': OS_CLIENT,
194
- 'authorization': requestToken ? `Bearer ${requestToken}` : '',
195
- 'did': getDid()
196
- },
197
- data: { OsClient: OS_CLIENT, FormEngineKey: table, ...body },
198
- success: (res) => {
199
- applyResponseToken(res.header || res.headers, requestToken);
200
- resolve(res.data || {});
201
- },
202
- fail: reject
203
- });
204
- });
205
- }
206
- export const formEngineGet = (t, w) => formEngineRequest('gettabledata', t, w);
207
- export const formEngineGetOne = (t, w) => formEngineRequest('getformdata', t, w);
208
- export const formEngineAdd = (t, d) => formEngineRequest('addformdata', t, d);
209
- export const formEngineUpt = (t, d) => formEngineRequest('uptformdata', t, d);
210
- export const formEngineDel = (t, d) => formEngineRequest('delformdata', t, d);
211
- ```
212
-
213
- ## 排错速查
214
-
215
- | 现象 | 真实原因 |
216
- | --- | --- |
217
- | 404 Not Found | URL 缺 `/api/` 前缀,或表名/动作之间用 `/` 而不是 `-` |
218
- | 405 Method Not Allowed | 用了 GET(FormEngine 全部为 POST) |
219
- | 1001 登录身份已过期 | 没传 Token / Token 过期 / Redis 重启 |
220
- | 1002 身份验证失败 | OsClient 不匹配 |
221
- | `NoAuth` / `您没有权限做此操作` | Token 有效但菜单、表操作权限、表绑定角色、行级范围或敏感表策略不允许 |
222
- | 显式传 `_SysMenuId` 后无权限 | 列表/写入使用错误菜单会严格拒绝;唯一详情在当前角色仍拥有另一个同表菜单时可恢复,不应用菜单查询范围 |
223
- | 无 `_SysMenuId` 仍无权限 | 当前角色没有直接绑定该表的菜单授权,也没有精确表级授权 |
224
- | 并发后提示 TokenReplaced / MissingToken | 客户端没有接收响应新 Token,或旧请求/其它标签页覆盖或清除了共享新 Token |
225
- | Code:0 表不存在 | `FormEngineKey` 在 `diy_table` 不存在 |
226
- | Code:0 字段不存在 | `_Where` / `_SelectFields` 写了表上没有的字段 |
227
- | 返回 `null` 而不是 DosResult | Controller 抛了异常被吞,到后端日志看 `Microi.Core` 报错 |
228
-
229
- ## 与服务器端 V8 的对照
230
-
231
- | 客户端 HTTP 路由 | V8 内等价写法 |
232
- | --- | --- |
233
- | POST `/api/formengine/gettabledata-mall_product` | `V8.FormEngine.GetTableData('mall_product', {...})` |
234
- | POST `/api/formengine/getformdata-mall_member` | `V8.FormEngine.GetFormData('mall_member', {...})` |
235
- | POST `/api/formengine/uptformdata-mall_shopping_cart` | `V8.FormEngine.UptFormData('mall_shopping_cart', {...})` |
236
-
237
- > 客户端 HTTP 调用**会**触发 `SubmitBeforeServerV8`、`SubmitAfterServerV8`、`DataFilterV8` 等服务端事件;
238
- > 而 V8 引擎内调用 `V8.FormEngine.*` 默认**不**触发,除非显式传 `_InvokeType:'Client'`。`_InvokeType` 只影响事件语义,不授予任何客户端表权限。
112
+
113
+ ```jsonc
114
+ {
115
+ "OsClient": "demo",
116
+ "FormEngineKey": "mall_product", // 形式一必填;形式二可选(已在 URL 中)
117
+ "_SysMenuId": "目标菜单Id", // 标准模块推荐;必须是真实绑定目标表且当前角色有权访问的菜单
118
+ "_Where": [["Status","=","OnSale"], ["AND","Stock",">",0]],
119
+ "_SelectFields": ["Id","Title","CurrentPrice","MainImg"],
120
+ "_OrderBy": "SoldCount",
121
+ "_OrderByType": "DESC",
122
+ "_PageIndex": 1,
123
+ "_PageSize": 20
124
+ }
125
+ ```
126
+
127
+ 写操作(Add/Upt)将业务字段平铺到 body:
128
+ ```jsonc
129
+ { "OsClient":"demo", "FormEngineKey":"biz_order",
130
+ "Id":"01ABC...", "Quantity": 2, "Selected": 1 }
131
+ ```
132
+
133
+ ## 响应 DosResult 标准格式
134
+
135
+ ```jsonc
136
+ { "Code": 1, "Data": [...], "DataCount": 123, "Msg": "" }
137
+ ```
138
+ | Code | 含义 |
139
+ | --- | --- |
140
+ | 1 | 成功 |
141
+ | 0 | 业务失败(看 `Msg`) |
142
+ | 1001 | 登录身份已过期 / Token 无效 |
143
+ | 1002 | 身份验证失败(OsClient 与 Token 不匹配) |
144
+
145
+ ## 客户端封装样板(uni-app)
146
+
147
+ ```javascript
148
+ const BASE = 'https://api.itdos.com';
149
+ const OS_CLIENT = runtimeConfig.osClient;
150
+ const TOKEN_KEY = 'mall_token';
151
+ const DID_KEY = 'mall_did';
152
+
153
+ function normalizeToken(value) {
154
+ return String(value || '').replace(/^Bearer\s+/i, '').trim();
155
+ }
156
+ function getToken() {
157
+ return normalizeToken(uni.getStorageSync(TOKEN_KEY));
158
+ }
159
+ function getDid() {
160
+ let did = uni.getStorageSync(DID_KEY);
161
+ if (!did) {
162
+ did = `uni-${Date.now()}-${Math.random().toString(36).slice(2)}`;
163
+ uni.setStorageSync(DID_KEY, did);
164
+ }
165
+ return did;
166
+ }
167
+ function readHeader(headers, name) {
168
+ const key = Object.keys(headers || {}).find(k => k.toLowerCase() === name);
169
+ return key ? headers[key] : '';
170
+ }
171
+ function applyResponseToken(headers, requestToken) {
172
+ const responseToken = normalizeToken(
173
+ readHeader(headers, 'authorization') || readHeader(headers, 'token')
174
+ );
175
+ if (!responseToken) return;
176
+
177
+ const currentToken = getToken();
178
+ // 旧请求若只回显旧 Token,不得覆盖其它请求/标签页已保存的新 Token。
179
+ if (currentToken && requestToken && currentToken !== requestToken && responseToken === requestToken) {
180
+ return;
181
+ }
182
+ uni.setStorageSync(TOKEN_KEY, responseToken);
183
+ }
184
+
185
+ function formEngineRequest(action, table, body = {}) {
186
+ return new Promise((resolve, reject) => {
187
+ const requestToken = getToken();
188
+ uni.request({
189
+ url: `${BASE}/api/formengine/${action}-${table}`,
190
+ method: 'POST',
191
+ header: {
192
+ 'Content-Type': 'application/json',
193
+ 'OsClient': OS_CLIENT,
194
+ 'authorization': requestToken ? `Bearer ${requestToken}` : '',
195
+ 'did': getDid()
196
+ },
197
+ data: { OsClient: OS_CLIENT, FormEngineKey: table, ...body },
198
+ success: (res) => {
199
+ applyResponseToken(res.header || res.headers, requestToken);
200
+ resolve(res.data || {});
201
+ },
202
+ fail: reject
203
+ });
204
+ });
205
+ }
206
+ export const formEngineGet = (t, w) => formEngineRequest('gettabledata', t, w);
207
+ export const formEngineGetOne = (t, w) => formEngineRequest('getformdata', t, w);
208
+ export const formEngineAdd = (t, d) => formEngineRequest('addformdata', t, d);
209
+ export const formEngineUpt = (t, d) => formEngineRequest('uptformdata', t, d);
210
+ export const formEngineDel = (t, d) => formEngineRequest('delformdata', t, d);
211
+ ```
212
+
213
+ ## 排错速查
214
+
215
+ | 现象 | 真实原因 |
216
+ | --- | --- |
217
+ | 404 Not Found | URL 缺 `/api/` 前缀,或表名/动作之间用 `/` 而不是 `-` |
218
+ | 405 Method Not Allowed | 用了 GET(FormEngine 全部为 POST) |
219
+ | 1001 登录身份已过期 | 没传 Token / Token 过期 / Redis 重启 |
220
+ | 1002 身份验证失败 | OsClient 不匹配 |
221
+ | `NoAuth` / `您没有权限做此操作` | Token 有效但菜单、表操作权限、表绑定角色、行级范围或敏感表策略不允许 |
222
+ | 显式传 `_SysMenuId` 后无权限 | 列表/写入使用错误菜单会严格拒绝;唯一详情在当前角色仍拥有另一个同表菜单时可恢复,不应用菜单查询范围 |
223
+ | 无 `_SysMenuId` 仍无权限 | 当前角色没有直接绑定该表的菜单授权,也没有精确表级授权 |
224
+ | 并发后提示 TokenReplaced / MissingToken | 客户端没有接收响应新 Token,或旧请求/其它标签页覆盖或清除了共享新 Token |
225
+ | Code:0 表不存在 | `FormEngineKey` 在 `diy_table` 不存在 |
226
+ | Code:0 字段不存在 | `_Where` / `_SelectFields` 写了表上没有的字段 |
227
+ | 返回 `null` 而不是 DosResult | Controller 抛了异常被吞,到后端日志看 `Microi.Core` 报错 |
228
+
229
+ ## 与服务器端 V8 的对照
230
+
231
+ | 客户端 HTTP 路由 | V8 内等价写法 |
232
+ | --- | --- |
233
+ | POST `/api/formengine/gettabledata-mall_product` | `V8.FormEngine.GetTableData('mall_product', {...})` |
234
+ | POST `/api/formengine/getformdata-mall_member` | `V8.FormEngine.GetFormData('mall_member', {...})` |
235
+ | POST `/api/formengine/uptformdata-mall_shopping_cart` | `V8.FormEngine.UptFormData('mall_shopping_cart', {...})` |
236
+
237
+ > 客户端 HTTP 调用**会**触发 `SubmitBeforeServerV8`、`SubmitAfterServerV8`、`DataFilterV8` 等服务端事件;
238
+ > 而 V8 引擎内调用 `V8.FormEngine.*` 默认**不**触发,除非显式传 `_InvokeType:'Client'`。`_InvokeType` 只影响事件语义,不授予任何客户端表权限。