@microi.net/cli 5.5.9 → 5.6.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 (166) 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/.mcp.json +1 -1
  5. package/.workbuddy-plugin/marketplace.json +2 -2
  6. package/.workbuddy-plugin/plugin.json +1 -1
  7. package/README.md +71 -71
  8. package/assets/build-meta.json +5 -5
  9. package/assets/feature-matrix.json +129 -129
  10. package/cordis.patch.yml +1 -1
  11. package/package.json +1 -1
  12. package/scripts/codex-marketplace.json +20 -20
  13. package/scripts/mcp-codex-stdio-adapter.js +189 -189
  14. package/scripts/mcp-trae-windows-launcher.cmd +21 -21
  15. package/scripts/microi-cli-mcp.js +7 -7
  16. package/scripts/microi-codex-broker.js +447 -447
  17. package/scripts/microi-codex-router.js +582 -582
  18. package/scripts/microi-skills.meta.json +336 -336
  19. package/skills/.microi-skills-version.json +2 -2
  20. package/skills/.progressive-disclosure-manifest.json +3566 -3566
  21. package/skills/README.md +3 -3
  22. package/skills/ai-engine/SKILL.md +45 -45
  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 +177 -177
  26. package/skills/business-blueprint/SKILL.md +85 -85
  27. package/skills/datasource-engine/SKILL.md +91 -91
  28. package/skills/dos-orm/SKILL.md +81 -81
  29. package/skills/dos-orm/references/api-reference.md +229 -229
  30. package/skills/email-engine/SKILL.md +80 -80
  31. package/skills/email-engine/references/v8-email.md +34 -34
  32. package/skills/job-engine/SKILL.md +154 -154
  33. package/skills/message-notification/SKILL.md +126 -126
  34. package/skills/message-notification/agents/openai.yaml +5 -5
  35. package/skills/message-notification/references/contracts.md +102 -102
  36. package/skills/microi-ai-app-auth.js +652 -652
  37. package/skills/microi-ai-application/SKILL.md +102 -102
  38. package/skills/microi-ai-application/agents/openai.yaml +4 -4
  39. package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
  40. package/skills/microi-client-frontend/SKILL.md +43 -43
  41. 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 +2 -2
  42. 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 +28 -28
  43. 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 +56 -56
  44. package/skills/microi-codex/SKILL.md +46 -46
  45. package/skills/microi-codex-installer/SKILL.md +216 -216
  46. package/skills/microi-codex-installer/agents/openai.yaml +7 -7
  47. package/skills/microi-datasource-mapping/SKILL.md +67 -67
  48. package/skills/microi-db-schema/SKILL.md +6 -6
  49. package/skills/microi-db-schema/references/core-tables.md +18 -18
  50. package/skills/microi-db-schema/references/form-component-options.md +256 -256
  51. package/skills/microi-db-schema/references/schema-overview.md +11 -11
  52. package/skills/microi-db-schema/references/schema.md +46 -46
  53. package/skills/microi-db-schema/references/table-catalog.md +57 -57
  54. package/skills/microi-deployment/SKILL.md +18 -1
  55. package/skills/microi-deployment/references/deployment-matrix.md +101 -101
  56. package/skills/microi-docs-coverage/SKILL.md +123 -123
  57. package/skills/microi-docs-coverage/references/capability-map.md +1 -0
  58. package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
  59. package/skills/microi-form-engine/SKILL.md +50 -50
  60. package/skills/microi-form-engine/references/component-catalog.md +218 -218
  61. package/skills/microi-form-engine/references/data-source-events.md +124 -124
  62. package/skills/microi-form-layout/SKILL.md +13 -13
  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 +4 -4
  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 +175 -175
  66. package/skills/microi-left-right-layout/SKILL.md +141 -141
  67. package/skills/microi-microservice/SKILL.md +15 -15
  68. package/skills/microi-microservice/references/runtime-delivery.md +278 -278
  69. 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
  70. package/skills/microi-solution-quotation/SKILL.md +78 -78
  71. package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
  72. package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
  73. package/skills/microi-sso/SKILL.md +85 -85
  74. package/skills/microi-sso/references/acceptance.md +49 -49
  75. package/skills/microi-sso/references/configuration-and-security.md +53 -53
  76. package/skills/microi-sso/references/inbound.md +53 -53
  77. package/skills/microi-sso/references/outbound.md +39 -39
  78. 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 +20 -20
  79. package/skills/microi-ui/SKILL.md +7 -2
  80. package/skills/microi-uniapp-frontend/SKILL.md +134 -134
  81. 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 +136 -136
  82. 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 +124 -124
  83. package/skills/module-engine/SKILL.md +16 -16
  84. package/skills/ocr-engine/SKILL.md +2 -2
  85. package/skills/ocr-engine/agents/openai.yaml +1 -1
  86. package/skills/page-engine/SKILL.md +28 -28
  87. 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 +126 -126
  88. 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 +42 -42
  89. package/skills/performance-testing/SKILL.md +120 -120
  90. package/skills/playwright-e2e/SKILL.md +84 -84
  91. 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 +68 -68
  92. 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 +64 -64
  93. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +20 -20
  94. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +69 -69
  95. package/skills/print-engine/SKILL.md +36 -36
  96. package/skills/production-readonly-audit/SKILL.md +41 -41
  97. package/skills/report-engine/SKILL.md +71 -71
  98. package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
  99. package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
  100. package/skills/scripts/validate-progressive-disclosure.mjs +52 -52
  101. package/skills/search-engine/SKILL.md +75 -75
  102. package/skills/spider-engine/SKILL.md +190 -190
  103. package/skills/system-observability/SKILL.md +162 -162
  104. package/skills/system-observability/references/memory-incident-triage.md +73 -73
  105. package/skills/translate-engine/SKILL.md +1 -1
  106. package/skills/ui-design/SKILL.md +3 -1
  107. package/skills/uniapp-mall-assets/SKILL.md +170 -170
  108. package/skills/unity-integration/SKILL.md +155 -155
  109. package/skills/unity-integration/agents/openai.yaml +4 -4
  110. package/skills/unity-integration/references/ai-app-delivery.md +103 -103
  111. package/skills/unity-integration/references/sdk-api.md +82 -82
  112. package/skills/unity-integration/references/toolbox-migration.md +66 -66
  113. package/skills/unity-integration/references/webgl-hosting.md +57 -57
  114. package/skills/v8-api-config/SKILL.md +378 -378
  115. package/skills/v8-cache-pattern/SKILL.md +306 -306
  116. package/skills/v8-crud-api/SKILL.md +29 -29
  117. 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 +56 -56
  118. package/skills/v8-debugging/SKILL.md +143 -143
  119. package/skills/v8-explorer-tree/SKILL.md +64 -64
  120. 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 +201 -201
  121. package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +118 -118
  122. 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 +32 -32
  123. package/skills/v8-file-upload/SKILL.md +154 -154
  124. 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 +133 -133
  125. 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 +138 -138
  126. package/skills/v8-formengine-http/SKILL.md +107 -107
  127. package/skills/v8-frontend-events/SKILL.md +22 -22
  128. package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
  129. package/skills/v8-frontend-events/references/bluetooth-print.md +247 -247
  130. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +50 -50
  131. package/skills/v8-http-integration/SKILL.md +106 -106
  132. package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +31 -31
  133. 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 +5 -5
  134. package/skills/v8-image-processing/SKILL.md +190 -190
  135. package/skills/v8-image-processing/agents/openai.yaml +4 -4
  136. package/skills/v8-image-processing/references/api-reference.md +623 -623
  137. package/skills/v8-menu-buttons/SKILL.md +103 -103
  138. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +145 -145
  139. 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
  140. 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 +43 -43
  141. package/skills/v8-mongodb/SKILL.md +65 -65
  142. package/skills/v8-mq-mqtt/SKILL.md +175 -175
  143. package/skills/v8-mq-mqtt/references/mqtt-production.md +342 -342
  144. package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +137 -137
  145. package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
  146. package/skills/v8-saas-multi-tenant/SKILL.md +223 -223
  147. package/skills/v8-security/SKILL.md +25 -25
  148. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +122 -122
  149. package/skills/v8-sql-query/SKILL.md +127 -127
  150. package/skills/v8-table-event/SKILL.md +20 -20
  151. 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 +18 -18
  152. 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 +15 -15
  153. package/skills/v8-tcp-integration/SKILL.md +1 -1
  154. package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
  155. package/skills/v8-template-engine/SKILL.md +59 -59
  156. package/skills/v8-utilities/SKILL.md +92 -92
  157. package/skills/v8-utilities/references/client-api-index.md +143 -143
  158. package/skills/v8-utilities/references/platform-http-routes.md +83 -83
  159. package/skills/v8-utilities/references/server-api-index.md +74 -74
  160. package/skills/v8-workflow/SKILL.md +44 -44
  161. package/skills/vision-engine/SKILL.md +19 -19
  162. package/skills/vision-engine/references/architecture-and-acceptance.md +34 -34
  163. package/skills/workspace-conventions/SKILL.md +236 -236
  164. 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
  165. 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 +179 -179
  166. 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 +21 -21
@@ -55,50 +55,50 @@ description: 移动端 / 外部系统通过 HTTP 直接调用 Microi FormEngine
55
55
 
56
56
  URL 中的表名小写最稳,平台不区分大小写。匿名版本目前**只在形式一上有**(`GetTableDataAnonymous` 等)。
57
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/数据库调用与接口引擎一样属于可信服务器执行,可实现当前租户内的跨表事务。需要“只能修改本人数据”等业务约束以及归属字段写入时,应在这里或专用接口引擎中完成。
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
92
 
93
93
  ## Body 结构(POST JSON)
94
94
 
95
- ```jsonc
96
- {
97
- "OsClient": "demo",
98
- "FormEngineKey": "mall_product", // 形式一必填;形式二可选(已在 URL 中)
99
- "_SysMenuId": "目标菜单Id", // 标准模块推荐;必须是真实绑定目标表且当前角色有权访问的菜单
100
- "_Where": [["Status","=","OnSale"], ["AND","Stock",">",0]],
101
- "_SelectFields": ["Id","Title","CurrentPrice","MainImg"],
95
+ ```jsonc
96
+ {
97
+ "OsClient": "demo",
98
+ "FormEngineKey": "mall_product", // 形式一必填;形式二可选(已在 URL 中)
99
+ "_SysMenuId": "目标菜单Id", // 标准模块推荐;必须是真实绑定目标表且当前角色有权访问的菜单
100
+ "_Where": [["Status","=","OnSale"], ["AND","Stock",">",0]],
101
+ "_SelectFields": ["Id","Title","CurrentPrice","MainImg"],
102
102
  "_OrderBy": "SoldCount",
103
103
  "_OrderByType": "DESC",
104
104
  "_PageIndex": 1,
@@ -108,7 +108,7 @@ URL 中的表名小写最稳,平台不区分大小写。匿名版本目前**
108
108
 
109
109
  写操作(Add/Upt)将业务字段平铺到 body:
110
110
  ```jsonc
111
- { "OsClient":"demo", "FormEngineKey":"biz_order",
111
+ { "OsClient":"demo", "FormEngineKey":"biz_order",
112
112
  "Id":"01ABC...", "Quantity": 2, "Selected": 1 }
113
113
  ```
114
114
 
@@ -127,63 +127,63 @@ URL 中的表名小写最稳,平台不区分大小写。匿名版本目前**
127
127
  ## 客户端封装样板(uni-app)
128
128
 
129
129
  ```javascript
130
- const BASE = 'https://api.itdos.com';
131
- const OS_CLIENT = runtimeConfig.osClient;
132
- const TOKEN_KEY = 'mall_token';
133
- const DID_KEY = 'mall_did';
134
-
135
- function normalizeToken(value) {
136
- return String(value || '').replace(/^Bearer\s+/i, '').trim();
137
- }
138
- function getToken() {
139
- return normalizeToken(uni.getStorageSync(TOKEN_KEY));
140
- }
141
- function getDid() {
142
- let did = uni.getStorageSync(DID_KEY);
143
- if (!did) {
144
- did = `uni-${Date.now()}-${Math.random().toString(36).slice(2)}`;
145
- uni.setStorageSync(DID_KEY, did);
146
- }
147
- return did;
148
- }
149
- function readHeader(headers, name) {
150
- const key = Object.keys(headers || {}).find(k => k.toLowerCase() === name);
151
- return key ? headers[key] : '';
152
- }
153
- function applyResponseToken(headers, requestToken) {
154
- const responseToken = normalizeToken(
155
- readHeader(headers, 'authorization') || readHeader(headers, 'token')
156
- );
157
- if (!responseToken) return;
158
-
159
- const currentToken = getToken();
160
- // 旧请求若只回显旧 Token,不得覆盖其它请求/标签页已保存的新 Token。
161
- if (currentToken && requestToken && currentToken !== requestToken && responseToken === requestToken) {
162
- return;
163
- }
164
- uni.setStorageSync(TOKEN_KEY, responseToken);
165
- }
166
-
167
- function formEngineRequest(action, table, body = {}) {
168
- return new Promise((resolve, reject) => {
169
- const requestToken = getToken();
170
- uni.request({
171
- url: `${BASE}/api/formengine/${action}-${table}`,
172
- method: 'POST',
130
+ const BASE = 'https://api.itdos.com';
131
+ const OS_CLIENT = runtimeConfig.osClient;
132
+ const TOKEN_KEY = 'mall_token';
133
+ const DID_KEY = 'mall_did';
134
+
135
+ function normalizeToken(value) {
136
+ return String(value || '').replace(/^Bearer\s+/i, '').trim();
137
+ }
138
+ function getToken() {
139
+ return normalizeToken(uni.getStorageSync(TOKEN_KEY));
140
+ }
141
+ function getDid() {
142
+ let did = uni.getStorageSync(DID_KEY);
143
+ if (!did) {
144
+ did = `uni-${Date.now()}-${Math.random().toString(36).slice(2)}`;
145
+ uni.setStorageSync(DID_KEY, did);
146
+ }
147
+ return did;
148
+ }
149
+ function readHeader(headers, name) {
150
+ const key = Object.keys(headers || {}).find(k => k.toLowerCase() === name);
151
+ return key ? headers[key] : '';
152
+ }
153
+ function applyResponseToken(headers, requestToken) {
154
+ const responseToken = normalizeToken(
155
+ readHeader(headers, 'authorization') || readHeader(headers, 'token')
156
+ );
157
+ if (!responseToken) return;
158
+
159
+ const currentToken = getToken();
160
+ // 旧请求若只回显旧 Token,不得覆盖其它请求/标签页已保存的新 Token。
161
+ if (currentToken && requestToken && currentToken !== requestToken && responseToken === requestToken) {
162
+ return;
163
+ }
164
+ uni.setStorageSync(TOKEN_KEY, responseToken);
165
+ }
166
+
167
+ function formEngineRequest(action, table, body = {}) {
168
+ return new Promise((resolve, reject) => {
169
+ const requestToken = getToken();
170
+ uni.request({
171
+ url: `${BASE}/api/formengine/${action}-${table}`,
172
+ method: 'POST',
173
173
  header: {
174
- 'Content-Type': 'application/json',
175
- 'OsClient': OS_CLIENT,
176
- 'authorization': requestToken ? `Bearer ${requestToken}` : '',
177
- 'did': getDid()
178
- },
179
- data: { OsClient: OS_CLIENT, FormEngineKey: table, ...body },
180
- success: (res) => {
181
- applyResponseToken(res.header || res.headers, requestToken);
182
- resolve(res.data || {});
183
- },
184
- fail: reject
185
- });
186
- });
174
+ 'Content-Type': 'application/json',
175
+ 'OsClient': OS_CLIENT,
176
+ 'authorization': requestToken ? `Bearer ${requestToken}` : '',
177
+ 'did': getDid()
178
+ },
179
+ data: { OsClient: OS_CLIENT, FormEngineKey: table, ...body },
180
+ success: (res) => {
181
+ applyResponseToken(res.header || res.headers, requestToken);
182
+ resolve(res.data || {});
183
+ },
184
+ fail: reject
185
+ });
186
+ });
187
187
  }
188
188
  export const formEngineGet = (t, w) => formEngineRequest('gettabledata', t, w);
189
189
  export const formEngineGetOne = (t, w) => formEngineRequest('getformdata', t, w);
@@ -198,13 +198,13 @@ export const formEngineDel = (t, d) => formEngineRequest('delformdata', t, d
198
198
  | --- | --- |
199
199
  | 404 Not Found | URL 缺 `/api/` 前缀,或表名/动作之间用 `/` 而不是 `-` |
200
200
  | 405 Method Not Allowed | 用了 GET(FormEngine 全部为 POST) |
201
- | 1001 登录身份已过期 | 没传 Token / Token 过期 / Redis 重启 |
202
- | 1002 身份验证失败 | OsClient 不匹配 |
203
- | `NoAuth` / `您没有权限做此操作` | Token 有效但菜单、表操作权限、表绑定角色、行级范围或敏感表策略不允许 |
204
- | 显式传 `_SysMenuId` 后无权限 | 列表/写入使用错误菜单会严格拒绝;唯一详情在当前角色仍拥有另一个同表菜单时可恢复,不应用菜单查询范围 |
205
- | 无 `_SysMenuId` 仍无权限 | 当前角色没有直接绑定该表的菜单授权,也没有精确表级授权 |
206
- | 并发后提示 TokenReplaced / MissingToken | 客户端没有接收响应新 Token,或旧请求/其它标签页覆盖或清除了共享新 Token |
207
- | Code:0 表不存在 | `FormEngineKey` 在 `diy_table` 不存在 |
201
+ | 1001 登录身份已过期 | 没传 Token / Token 过期 / Redis 重启 |
202
+ | 1002 身份验证失败 | OsClient 不匹配 |
203
+ | `NoAuth` / `您没有权限做此操作` | Token 有效但菜单、表操作权限、表绑定角色、行级范围或敏感表策略不允许 |
204
+ | 显式传 `_SysMenuId` 后无权限 | 列表/写入使用错误菜单会严格拒绝;唯一详情在当前角色仍拥有另一个同表菜单时可恢复,不应用菜单查询范围 |
205
+ | 无 `_SysMenuId` 仍无权限 | 当前角色没有直接绑定该表的菜单授权,也没有精确表级授权 |
206
+ | 并发后提示 TokenReplaced / MissingToken | 客户端没有接收响应新 Token,或旧请求/其它标签页覆盖或清除了共享新 Token |
207
+ | Code:0 表不存在 | `FormEngineKey` 在 `diy_table` 不存在 |
208
208
  | Code:0 字段不存在 | `_Where` / `_SelectFields` 写了表上没有的字段 |
209
209
  | 返回 `null` 而不是 DosResult | Controller 抛了异常被吞,到后端日志看 `Microi.Core` 报错 |
210
210
 
@@ -216,5 +216,5 @@ export const formEngineDel = (t, d) => formEngineRequest('delformdata', t, d
216
216
  | POST `/api/formengine/getformdata-mall_member` | `V8.FormEngine.GetFormData('mall_member', {...})` |
217
217
  | POST `/api/formengine/uptformdata-mall_shopping_cart` | `V8.FormEngine.UptFormData('mall_shopping_cart', {...})` |
218
218
 
219
- > 客户端 HTTP 调用**会**触发 `SubmitBeforeServerV8`、`SubmitAfterServerV8`、`DataFilterV8` 等服务端事件;
220
- > 而 V8 引擎内调用 `V8.FormEngine.*` 默认**不**触发,除非显式传 `_InvokeType:'Client'`。`_InvokeType` 只影响事件语义,不授予任何客户端表权限。
219
+ > 客户端 HTTP 调用**会**触发 `SubmitBeforeServerV8`、`SubmitAfterServerV8`、`DataFilterV8` 等服务端事件;
220
+ > 而 V8 引擎内调用 `V8.FormEngine.*` 默认**不**触发,除非显式传 `_InvokeType:'Client'`。`_InvokeType` 只影响事件语义,不授予任何客户端表权限。
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: v8-frontend-events
3
- description: Microi 前端 V8 事件与客户端能力指南。用于编写浏览器端字段、按钮、列表事件,或使用 V8.EventName、V8.Form、V8.Print 蓝牙打印(佳博 GP-M322、ZICOX CC4、TSPL、CPCL、ESC/POS、BLE、SPP)、扫码、弹窗、表单联动和界面交互。
2
+ name: v8-frontend-events
3
+ description: Microi 前端 V8 事件与客户端能力指南。用于编写浏览器端字段、按钮、列表事件,或使用 V8.EventName、V8.Form、V8.Print 蓝牙打印(佳博 GP-M322、ZICOX CC4、TSPL、CPCL、ESC/POS、BLE、SPP)、扫码、弹窗、表单联动和界面交互。
4
4
  ---
5
5
 
6
6
  > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
@@ -10,18 +10,18 @@ description: Microi 前端 V8 事件与客户端能力指南。用于编写浏
10
10
  你正在为 Microi 吾码平台编写 **前端 V8 事件** 代码。前端事件运行在浏览器,通过 `V8.EventName` 区分事件类型,可访问表单/列表/弹窗等丰富的客户端 API。
11
11
 
12
12
  > **表单生命周期事件**(InFormV8、SubmitFormV8、SubmitBeforeServerV8、SubmitAfterServerV8、OutFormV8、DataFilterV8)见 `v8-table-event/SKILL.md`。
13
- > **菜单按钮事件**(MoreBtns/FormBtns 等)见 `v8-menu-buttons/SKILL.md`。
14
- > 本文重点是 **字段事件、按钮事件、列表事件、模板引擎、其它前端钩子**。
15
-
13
+ > **菜单按钮事件**(MoreBtns/FormBtns 等)见 `v8-menu-buttons/SKILL.md`。
14
+ > 本文重点是 **字段事件、按钮事件、列表事件、模板引擎、其它前端钩子**。
15
+
16
16
  <!-- microi-progressive:begin -->
17
17
  <!-- microi-progressive:chunk id=v8-frontend-events-000 sha256=df2662a9a006d35d989d7ff7316890ffff2c08e422d0e88033f44cdd40210c88 -->
18
- ## 能力路由
19
-
20
- - 查询前端 V8 全部上下文、导航、表单、列表、网络、引擎与工具入口时,读取 `../v8-utilities/references/client-api-index.md`。
21
- - 需求包含“蓝牙打印、标签打印、TSC/TSPL、CPCL、ESC/POS、小票打印、佳博/GP-M322、ZICOX/芝柯/CC4、BLE/SPP”时,必须先读取 `references/bluetooth-print.md`;需要完整指令签名、型号转换范围、编码或位图参数时,再读取 `references/bluetooth-print-api.md`。
22
- - 浏览器模板打印、PDF/纸张模板、`mic_print`、`PageObj`、`PrintObj` 使用 `print-engine/SKILL.md`,不要与直接蓝牙指令混为一套 API。
23
- - 扫码使用 `V8.Method.ScanCode`,结果从 Promise/回调取得;`V8.ScanCodeRes` 只作兼容结果槽,详见客户端 API 索引。
24
- - 登录后的敏感操作使用 `V8.Identity.Verify` 完成 Passkey/严格人脸交互;前端只取得一次性 Ticket,后端接口引擎必须重算 `ActionHash` 并原子消费,不能把前端成功当作授权。
18
+ ## 能力路由
19
+
20
+ - 查询前端 V8 全部上下文、导航、表单、列表、网络、引擎与工具入口时,读取 `../v8-utilities/references/client-api-index.md`。
21
+ - 需求包含“蓝牙打印、标签打印、TSC/TSPL、CPCL、ESC/POS、小票打印、佳博/GP-M322、ZICOX/芝柯/CC4、BLE/SPP”时,必须先读取 `references/bluetooth-print.md`;需要完整指令签名、型号转换范围、编码或位图参数时,再读取 `references/bluetooth-print-api.md`。
22
+ - 浏览器模板打印、PDF/纸张模板、`mic_print`、`PageObj`、`PrintObj` 使用 `print-engine/SKILL.md`,不要与直接蓝牙指令混为一套 API。
23
+ - 扫码使用 `V8.Method.ScanCode`,结果从 Promise/回调取得;`V8.ScanCodeRes` 只作兼容结果槽,详见客户端 API 索引。
24
+ - 登录后的敏感操作使用 `V8.Identity.Verify` 完成 Passkey/严格人脸交互;前端只取得一次性 Ticket,后端接口引擎必须重算 `ActionHash` 并原子消费,不能把前端成功当作授权。
25
25
 
26
26
  <!-- /microi-progressive:chunk -->
27
27
  <!-- microi-progressive:chunk id=v8-frontend-events-001 sha256=a9f8e1aed64db4b57ff762eb557c0d764b5f703a722dc080d273c4111afe234f -->
@@ -133,22 +133,22 @@ V8.ConfirmTips('确认审核通过?', function() {
133
133
  });
134
134
  ```
135
135
 
136
- ### V8BtnLimit — 按钮显隐(V8CodeShow)
136
+ ### V8BtnLimit — 按钮显隐(V8CodeShow)
137
137
 
138
138
  ```javascript
139
139
  // 推荐:直接 return boolean
140
140
  return V8.Form.Status === '待审核' && V8.CurrentUser.RoleName.indexOf('审批员') !== -1;
141
141
 
142
142
  // 兼容旧写法:V8.Result = true/false
143
- // V8.Result = V8.Form.Status === '待审核';
144
- ```
145
-
146
- `V8CodeShow` 与点击事件使用同一套前端 V8 能力,允许直接使用 `await`。平台所有
147
- 按钮入口(列表按钮、表单顶部按钮、更多按钮和子表打开的嵌套表单按钮)都必须走
148
- 异步执行器并等待结果后再决定显隐;不得在某一层退回同步 `new Function`,否则同一段
149
- 代码在列表可用、进入嵌套表单后会报 `await is only valid in async functions`。回归测试
150
- 至少覆盖“主表详情 → 定制子表 → 子记录详情”链路中的含 `await` 显隐代码。
151
-
143
+ // V8.Result = V8.Form.Status === '待审核';
144
+ ```
145
+
146
+ `V8CodeShow` 与点击事件使用同一套前端 V8 能力,允许直接使用 `await`。平台所有
147
+ 按钮入口(列表按钮、表单顶部按钮、更多按钮和子表打开的嵌套表单按钮)都必须走
148
+ 异步执行器并等待结果后再决定显隐;不得在某一层退回同步 `new Function`,否则同一段
149
+ 代码在列表可用、进入嵌套表单后会报 `await is only valid in async functions`。回归测试
150
+ 至少覆盖“主表详情 → 定制子表 → 子记录详情”链路中的含 `await` 显隐代码。
151
+
152
152
  <!-- /microi-progressive:chunk -->
153
153
  <!-- microi-progressive:chunk id=v8-frontend-events-003 sha256=68aab95ab02bfca93b69eaea1c188650cb7ef13f8566bee81a63c660a4437512 -->
154
154
  ## 模板引擎事件
@@ -1,135 +1,135 @@
1
- # V8.Print TSC、CPCL 适配与 ESC/POS 源码 API
2
-
3
- 本表直接按 `Microi.Client/src/utils/ble/tsc.js`、`esc.js`、
4
- `printer-compatibility.js` 与编码文件整理。方法名
5
- (包括历史拼写)必须与源码完全一致,不能根据打印机手册自行改名。
6
-
7
- ## 目录
8
-
9
- - [构建器与编码](#构建器与编码)
10
- - [TSC/TSPL 的 28 个方法](#tsctspl-的-28-个方法)
11
- - [ZICOX CC4 的 CPCL 映射](#zicox-cc4-的-cpcl-映射)
12
- - [ESC/POS 的 25 个方法](#escpos-的-25-个方法)
13
- - [参数与组合规则](#参数与组合规则)
14
-
15
- ## 构建器与编码
16
-
17
- ```javascript
18
- var tsc = V8.Print.createNew();
19
- var esc = V8.Print.createNewESC();
20
- ```
21
-
22
- 两个构建器都把指令累积到普通字节数组,`getData()` 返回该数组。TSC 返回值还带不可枚举
23
- 协议/操作元数据:普通遍历与 GP-M322 字节值不变,CC4 发送前据此生成 CPCL。不要复制或
24
- 序列化 TSC 数组后再交给 `prepareSend`。TSC 的全部文本命令、
25
- ESC 的 `setText` 和二维码内容通过本地 `TextEncoder('gb18030', {
26
- NONSTANDARD_allowLegacyEncoding: true })` 编码;映射表来自同目录的
27
- `encoding-indexes.js`,不需要网络请求。
28
-
29
- ## TSC/TSPL 的 28 个方法
30
-
31
- | 方法 | 当前生成的指令/作用 |
32
- |---|---|
33
- | `init()` | 空操作,历史兼容入口 |
34
- | `addCommand(content)` | 以 GB18030 追加原始 TSC 文本;只用于固定可信命令 |
35
- | `setSize(width,height)` | `SIZE width mm,height mm` |
36
- | `setSpeed(speed)` | `SPEED speed` |
37
- | `setDensity(density)` | `DENSITY density` |
38
- | `setGap(gap)` | `GAP gap mm,0 mm` |
39
- | `setBline(bline)` | `BLINE bline mm,0 mm`,黑标纸 |
40
- | `setCountry(country)` | `COUNTRY country` |
41
- | `setCodepage(codepage)` | `CODEPAGE codepage` |
42
- | `setCls()` | `CLS`,清除图像缓冲区 |
43
- | `setFeed(feed)` | `FEED feed`,向前走纸 |
44
- | `setBackFeed(backup)` | `BACKFEED backup`,回拉 |
45
- | `setDirection(direction)` | `DIRECTION direction` |
46
- | `setReference(x,y)` | `REFERENCE x,y`,坐标原点 |
47
- | `setFromfeed()` | 注意源码拼写;实际生成 `FORMFEED` |
48
- | `setHome()` | `HOME`,定位下一张标签 |
49
- | `setSound(level,interval)` | `SOUND level,interval` |
50
- | `setLimitfeed(limit)` | `LIMITFEED limit` |
51
- | `setBar(x,y,width,height)` | `BAR` 线条 |
52
- | `setBox(x1,y1,x2,y2,thickness)` | `BOX` 方框 |
53
- | `setErase(x,y,width,height)` | `ERASE` 清除区域 |
54
- | `setReverse(x,y,width,height)` | `REVERSE` 区域反相 |
55
- | `setText(x,y,font,xScale,yScale,text)` | `TEXT`;旋转值在源码中固定为 `0` |
56
- | `setQR(x,y,level,width,mode,content)` | `QRCODE`;旋转值固定为 `0` |
57
- | `setBarCode(x,y,type,height,readable,narrow,wide,content)` | `BARCODE`;旋转值固定为 `0` |
58
- | `setBitmap(x,y,mode,imageData)` | 生成 TSC `BITMAP` 二进制数据 |
59
- | `setPagePrint()` | `PRINT 1,1` |
60
- | `getData()` | 返回当前字节数组 |
61
-
62
- 最小顺序通常是 `setSize` → `setGap`/`setBline` → `setCls` → 内容 →
63
- `setPagePrint` → `getData`。字体名、条码类型、纸张传感器、速度和浓度由打印机固件决定,
64
- 构建器不验证范围。
65
-
66
- ## ZICOX CC4 的 CPCL 映射
67
-
68
- | TSC 方法 | CC4 CPCL 结果 |
69
- |---|---|
70
- | `setSize(w,h)` | 203 dpi 下按 `8 dots/mm` 生成页宽/页高 |
71
- | `setSpeed` / `setDensity` | `SPEED` / `CONTRAST`,钳制到当前安全范围 |
72
- | `setGap` / `setBline` | `GAP-SENSE` / `BAR-SENSE` |
73
- | `setFeed` / `setBackFeed` | `POSTFEED` / `PREFEED` |
74
- | `setDirection(0/1)` | `ZPROTATE` / `ZPROTATE180` |
75
- | `setReference` | 转换坐标时叠加参考点 |
76
- | `setBar` / `setBox` / `setReverse` | `LINE` / `BOX` / `INVERSE-LINE` |
77
- | `setText` | `SETMAG` + `T`,字体名按 16/24/32 档映射 |
78
- | `setBarCode` | `BARCODE`,可选 `BARCODE-TEXT` |
79
- | `setQR` | 厂家 SDK 格式 `BARCODE QR ...` + 数据 + `ENDQR` |
80
- | `setBitmap` | `CG` + 原始单色位图字节 |
81
- | `setPagePrint` | 最终统一补 `FORM` + `PRINT`,每份必须恰好一次 |
82
-
83
- `init`、`setCls` 不输出。`addCommand`、`setCountry`、`setCodepage`、`setFromfeed`、
84
- `setHome`、`setSound`、`setLimitfeed`、`setErase` 与未知方法会抛错,并且适配发生在分包前,
85
- 所以失败时不得写入任何一包。该白名单只表达当前有证据的等价转换,不代表 CC4 固件不具备
86
- 其它 CPCL 能力。
87
-
88
- `createNewESC()` 的数组标记为 ESC/POS,CC4 直接原样发送,不进入 CPCL 转换。
89
-
90
- ## ESC/POS 的 25 个方法
91
-
92
- | 方法 | 当前生成的指令/作用 |
93
- |---|---|
94
- | `init()` | ESC `@` 初始化 |
95
- | `setText(content)` | 以 GB18030 追加文字 |
96
- | `setFontSize(n)` | GS `! n` |
97
- | `bold(n)` | ESC `E n` |
98
- | `setUnderline(n)` | ESC `- n` |
99
- | `setUnderline2(n)` | FS `- n` |
100
- | `setSelectSizeOfModuleForQRCode(n)` | 设置二维码模块尺寸,源码钳制到 1–15 |
101
- | `setSelectErrorCorrectionLevelForQRCode(n)` | 设置二维码纠错值,源码不验证范围 |
102
- | `setStoreQRCodeData(content)` | 以 GB18030 暂存二维码内容 |
103
- | `setPrintQRCode()` | 输出已暂存二维码 |
104
- | `setHorTab()` | 水平 Tab |
105
- | `setAbsolutePrintPosition(where)` | 设置绝对横向位置 |
106
- | `setRelativePrintPositon(where)` | 设置相对横向位置;`Positon` 是现有公开拼写 |
107
- | `setSelectJustification(which)` | 对齐:常见值 0 左、1 中、2 右 |
108
- | `space(n)` | 设置水平制表位置 |
109
- | `setLeftMargin(n)` | 设置左边距 |
110
- | `textMarginRight(n)` | 设置字符右间距 |
111
- | `rowSpace(n)` | 设置行间距 |
112
- | `setPrintingAreaWidth(width)` | 设置打印区域宽度 |
113
- | `setSound(n,t)` | 蜂鸣器;大于 9 钳制为 9,小于 0 改为 1,0 会原样保留 |
114
- | `setBitmap(imageData)` | 生成 ESC/POS 光栅位图数据 |
115
- | `setPrint()` | 换行/打印当前行 |
116
- | `setPrintAndFeed(feed)` | 打印并走纸指定单位 |
117
- | `setPrintAndFeedRow(row)` | 打印并走纸指定行数 |
118
- | `getData()` | 返回当前字节数组 |
119
-
120
- ESC/POS 二维码需要按顺序调用尺寸、纠错、`setStoreQRCodeData`、
121
- `setPrintQRCode`。源码中虽保留条码类型数组,但没有公开 ESC/POS 条码方法,不能虚构
122
- `setBarCode`;条码需求应先确认型号并扩展实现。
123
-
124
- ## 参数与组合规则
125
-
126
- - `setBitmap` 的参数是 ImageData 风格对象:`width`、`height`、RGBA `data`。它不是图片
127
- URL、Base64 或 DOM `<img>`;调用前先在 Canvas 得到 `getImageData()`。
128
- - 当前位图算法按透明/非透明像素进行非常简单的黑白映射,不做通用抖动和灰度阈值处理;
129
- 大图先缩放、二值化,逐型号验证方向、颜色和内存。
130
- - TSC `setText`、`setQR`、`setBarCode` 把值放入带双引号的协议字段。移除双引号、CR/LF、
131
- NUL 和控制字符,限制长度;不要让接口返回值直达 `addCommand`。
132
- - ESC 参数最终作为单字节或低/高字节写入,负数、浮点数、超范围值可能截断或生成无效命令。
133
- 坐标、宽度、走纸、字号和蜂鸣器参数应先转为目标机型允许的整数。
134
- - GB18030 只解决字节编码,不能替代打印机代码页、中文字库和字体配置。二维码通常比文字
135
- 字库更能稳定承载 Unicode 业务标识,但仍受打印机二维码命令实现限制。
1
+ # V8.Print TSC、CPCL 适配与 ESC/POS 源码 API
2
+
3
+ 本表直接按 `Microi.Client/src/utils/ble/tsc.js`、`esc.js`、
4
+ `printer-compatibility.js` 与编码文件整理。方法名
5
+ (包括历史拼写)必须与源码完全一致,不能根据打印机手册自行改名。
6
+
7
+ ## 目录
8
+
9
+ - [构建器与编码](#构建器与编码)
10
+ - [TSC/TSPL 的 28 个方法](#tsctspl-的-28-个方法)
11
+ - [ZICOX CC4 的 CPCL 映射](#zicox-cc4-的-cpcl-映射)
12
+ - [ESC/POS 的 25 个方法](#escpos-的-25-个方法)
13
+ - [参数与组合规则](#参数与组合规则)
14
+
15
+ ## 构建器与编码
16
+
17
+ ```javascript
18
+ var tsc = V8.Print.createNew();
19
+ var esc = V8.Print.createNewESC();
20
+ ```
21
+
22
+ 两个构建器都把指令累积到普通字节数组,`getData()` 返回该数组。TSC 返回值还带不可枚举
23
+ 协议/操作元数据:普通遍历与 GP-M322 字节值不变,CC4 发送前据此生成 CPCL。不要复制或
24
+ 序列化 TSC 数组后再交给 `prepareSend`。TSC 的全部文本命令、
25
+ ESC 的 `setText` 和二维码内容通过本地 `TextEncoder('gb18030', {
26
+ NONSTANDARD_allowLegacyEncoding: true })` 编码;映射表来自同目录的
27
+ `encoding-indexes.js`,不需要网络请求。
28
+
29
+ ## TSC/TSPL 的 28 个方法
30
+
31
+ | 方法 | 当前生成的指令/作用 |
32
+ |---|---|
33
+ | `init()` | 空操作,历史兼容入口 |
34
+ | `addCommand(content)` | 以 GB18030 追加原始 TSC 文本;只用于固定可信命令 |
35
+ | `setSize(width,height)` | `SIZE width mm,height mm` |
36
+ | `setSpeed(speed)` | `SPEED speed` |
37
+ | `setDensity(density)` | `DENSITY density` |
38
+ | `setGap(gap)` | `GAP gap mm,0 mm` |
39
+ | `setBline(bline)` | `BLINE bline mm,0 mm`,黑标纸 |
40
+ | `setCountry(country)` | `COUNTRY country` |
41
+ | `setCodepage(codepage)` | `CODEPAGE codepage` |
42
+ | `setCls()` | `CLS`,清除图像缓冲区 |
43
+ | `setFeed(feed)` | `FEED feed`,向前走纸 |
44
+ | `setBackFeed(backup)` | `BACKFEED backup`,回拉 |
45
+ | `setDirection(direction)` | `DIRECTION direction` |
46
+ | `setReference(x,y)` | `REFERENCE x,y`,坐标原点 |
47
+ | `setFromfeed()` | 注意源码拼写;实际生成 `FORMFEED` |
48
+ | `setHome()` | `HOME`,定位下一张标签 |
49
+ | `setSound(level,interval)` | `SOUND level,interval` |
50
+ | `setLimitfeed(limit)` | `LIMITFEED limit` |
51
+ | `setBar(x,y,width,height)` | `BAR` 线条 |
52
+ | `setBox(x1,y1,x2,y2,thickness)` | `BOX` 方框 |
53
+ | `setErase(x,y,width,height)` | `ERASE` 清除区域 |
54
+ | `setReverse(x,y,width,height)` | `REVERSE` 区域反相 |
55
+ | `setText(x,y,font,xScale,yScale,text)` | `TEXT`;旋转值在源码中固定为 `0` |
56
+ | `setQR(x,y,level,width,mode,content)` | `QRCODE`;旋转值固定为 `0` |
57
+ | `setBarCode(x,y,type,height,readable,narrow,wide,content)` | `BARCODE`;旋转值固定为 `0` |
58
+ | `setBitmap(x,y,mode,imageData)` | 生成 TSC `BITMAP` 二进制数据 |
59
+ | `setPagePrint()` | `PRINT 1,1` |
60
+ | `getData()` | 返回当前字节数组 |
61
+
62
+ 最小顺序通常是 `setSize` → `setGap`/`setBline` → `setCls` → 内容 →
63
+ `setPagePrint` → `getData`。字体名、条码类型、纸张传感器、速度和浓度由打印机固件决定,
64
+ 构建器不验证范围。
65
+
66
+ ## ZICOX CC4 的 CPCL 映射
67
+
68
+ | TSC 方法 | CC4 CPCL 结果 |
69
+ |---|---|
70
+ | `setSize(w,h)` | 203 dpi 下按 `8 dots/mm` 生成页宽/页高 |
71
+ | `setSpeed` / `setDensity` | `SPEED` / `CONTRAST`,钳制到当前安全范围 |
72
+ | `setGap` / `setBline` | `GAP-SENSE` / `BAR-SENSE` |
73
+ | `setFeed` / `setBackFeed` | `POSTFEED` / `PREFEED` |
74
+ | `setDirection(0/1)` | `ZPROTATE` / `ZPROTATE180` |
75
+ | `setReference` | 转换坐标时叠加参考点 |
76
+ | `setBar` / `setBox` / `setReverse` | `LINE` / `BOX` / `INVERSE-LINE` |
77
+ | `setText` | `SETMAG` + `T`,字体名按 16/24/32 档映射 |
78
+ | `setBarCode` | `BARCODE`,可选 `BARCODE-TEXT` |
79
+ | `setQR` | 厂家 SDK 格式 `BARCODE QR ...` + 数据 + `ENDQR` |
80
+ | `setBitmap` | `CG` + 原始单色位图字节 |
81
+ | `setPagePrint` | 最终统一补 `FORM` + `PRINT`,每份必须恰好一次 |
82
+
83
+ `init`、`setCls` 不输出。`addCommand`、`setCountry`、`setCodepage`、`setFromfeed`、
84
+ `setHome`、`setSound`、`setLimitfeed`、`setErase` 与未知方法会抛错,并且适配发生在分包前,
85
+ 所以失败时不得写入任何一包。该白名单只表达当前有证据的等价转换,不代表 CC4 固件不具备
86
+ 其它 CPCL 能力。
87
+
88
+ `createNewESC()` 的数组标记为 ESC/POS,CC4 直接原样发送,不进入 CPCL 转换。
89
+
90
+ ## ESC/POS 的 25 个方法
91
+
92
+ | 方法 | 当前生成的指令/作用 |
93
+ |---|---|
94
+ | `init()` | ESC `@` 初始化 |
95
+ | `setText(content)` | 以 GB18030 追加文字 |
96
+ | `setFontSize(n)` | GS `! n` |
97
+ | `bold(n)` | ESC `E n` |
98
+ | `setUnderline(n)` | ESC `- n` |
99
+ | `setUnderline2(n)` | FS `- n` |
100
+ | `setSelectSizeOfModuleForQRCode(n)` | 设置二维码模块尺寸,源码钳制到 1–15 |
101
+ | `setSelectErrorCorrectionLevelForQRCode(n)` | 设置二维码纠错值,源码不验证范围 |
102
+ | `setStoreQRCodeData(content)` | 以 GB18030 暂存二维码内容 |
103
+ | `setPrintQRCode()` | 输出已暂存二维码 |
104
+ | `setHorTab()` | 水平 Tab |
105
+ | `setAbsolutePrintPosition(where)` | 设置绝对横向位置 |
106
+ | `setRelativePrintPositon(where)` | 设置相对横向位置;`Positon` 是现有公开拼写 |
107
+ | `setSelectJustification(which)` | 对齐:常见值 0 左、1 中、2 右 |
108
+ | `space(n)` | 设置水平制表位置 |
109
+ | `setLeftMargin(n)` | 设置左边距 |
110
+ | `textMarginRight(n)` | 设置字符右间距 |
111
+ | `rowSpace(n)` | 设置行间距 |
112
+ | `setPrintingAreaWidth(width)` | 设置打印区域宽度 |
113
+ | `setSound(n,t)` | 蜂鸣器;大于 9 钳制为 9,小于 0 改为 1,0 会原样保留 |
114
+ | `setBitmap(imageData)` | 生成 ESC/POS 光栅位图数据 |
115
+ | `setPrint()` | 换行/打印当前行 |
116
+ | `setPrintAndFeed(feed)` | 打印并走纸指定单位 |
117
+ | `setPrintAndFeedRow(row)` | 打印并走纸指定行数 |
118
+ | `getData()` | 返回当前字节数组 |
119
+
120
+ ESC/POS 二维码需要按顺序调用尺寸、纠错、`setStoreQRCodeData`、
121
+ `setPrintQRCode`。源码中虽保留条码类型数组,但没有公开 ESC/POS 条码方法,不能虚构
122
+ `setBarCode`;条码需求应先确认型号并扩展实现。
123
+
124
+ ## 参数与组合规则
125
+
126
+ - `setBitmap` 的参数是 ImageData 风格对象:`width`、`height`、RGBA `data`。它不是图片
127
+ URL、Base64 或 DOM `<img>`;调用前先在 Canvas 得到 `getImageData()`。
128
+ - 当前位图算法按透明/非透明像素进行非常简单的黑白映射,不做通用抖动和灰度阈值处理;
129
+ 大图先缩放、二值化,逐型号验证方向、颜色和内存。
130
+ - TSC `setText`、`setQR`、`setBarCode` 把值放入带双引号的协议字段。移除双引号、CR/LF、
131
+ NUL 和控制字符,限制长度;不要让接口返回值直达 `addCommand`。
132
+ - ESC 参数最终作为单字节或低/高字节写入,负数、浮点数、超范围值可能截断或生成无效命令。
133
+ 坐标、宽度、走纸、字号和蜂鸣器参数应先转为目标机型允许的整数。
134
+ - GB18030 只解决字节编码,不能替代打印机代码页、中文字库和字体配置。二维码通常比文字
135
+ 字库更能稳定承载 Unicode 业务标识,但仍受打印机二维码命令实现限制。