@microi.net/cli 4.6.2
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/LICENSE +21 -0
- package/README.md +66 -0
- package/dist/mcp-codex-stdio-adapter.js +189 -0
- package/dist/mcp-server.js +972 -0
- package/dist/mcp-trae-windows-launcher.cmd +21 -0
- package/dist/microi-cli-mcp.js +7 -0
- package/dist/microi-cli.js +1645 -0
- package/dist/microi-skills.meta.json +335 -0
- package/dist/microi.skills/.microi-skills-version.json +6 -0
- package/dist/microi.skills/README.md +276 -0
- package/dist/microi.skills/ai-engine/SKILL.md +140 -0
- package/dist/microi.skills/ai-engine/agents/openai.yaml +4 -0
- package/dist/microi.skills/app-store/SKILL.md +105 -0
- package/dist/microi.skills/app-store/agents/openai.yaml +4 -0
- package/dist/microi.skills/business-blueprint/SKILL.md +184 -0
- package/dist/microi.skills/datasource-engine/SKILL.md +89 -0
- package/dist/microi.skills/datasource-engine/agents/openai.yaml +4 -0
- package/dist/microi.skills/dos-orm/SKILL.md +76 -0
- package/dist/microi.skills/dos-orm/references/api-reference.md +229 -0
- package/dist/microi.skills/job-engine/SKILL.md +141 -0
- package/dist/microi.skills/job-engine/agents/openai.yaml +4 -0
- package/dist/microi.skills/message-notification/SKILL.md +113 -0
- package/dist/microi.skills/message-notification/agents/openai.yaml +6 -0
- package/dist/microi.skills/message-notification/references/contracts.md +99 -0
- package/dist/microi.skills/microi-ai-app-auth.js +651 -0
- package/dist/microi.skills/microi-ai-application/SKILL.md +80 -0
- package/dist/microi.skills/microi-ai-application/agents/openai.yaml +4 -0
- package/dist/microi.skills/microi-ai-application/references/frontend-baseline.md +164 -0
- package/dist/microi.skills/microi-client-frontend/SKILL.md +562 -0
- package/dist/microi.skills/microi-datasource-mapping/SKILL.md +108 -0
- package/dist/microi.skills/microi-db-schema/SKILL.md +170 -0
- package/dist/microi.skills/microi-db-schema/agents/openai.yaml +4 -0
- package/dist/microi.skills/microi-db-schema/references/core-tables.md +695 -0
- package/dist/microi.skills/microi-db-schema/references/form-component-options.md +256 -0
- package/dist/microi.skills/microi-db-schema/references/schema-overview.md +203 -0
- package/dist/microi.skills/microi-db-schema/references/schema.md +647 -0
- package/dist/microi.skills/microi-db-schema/references/table-catalog.md +1607 -0
- package/dist/microi.skills/microi-deployment/SKILL.md +117 -0
- package/dist/microi.skills/microi-deployment/references/deployment-matrix.md +94 -0
- package/dist/microi.skills/microi-docs-coverage/SKILL.md +91 -0
- package/dist/microi.skills/microi-docs-coverage/references/capability-map.md +65 -0
- package/dist/microi.skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +887 -0
- package/dist/microi.skills/microi-form-engine/SKILL.md +159 -0
- package/dist/microi.skills/microi-form-engine/references/component-catalog.md +116 -0
- package/dist/microi.skills/microi-form-engine/references/data-source-events.md +117 -0
- package/dist/microi.skills/microi-form-layout/SKILL.md +373 -0
- package/dist/microi.skills/microi-frontend-sdk/SKILL.md +304 -0
- package/dist/microi.skills/microi-left-right-layout/SKILL.md +132 -0
- package/dist/microi.skills/microi-microservice/SKILL.md +115 -0
- package/dist/microi.skills/microi-microservice/references/runtime-delivery.md +145 -0
- package/dist/microi.skills/microi-mobile-app-quality/SKILL.md +436 -0
- package/dist/microi.skills/microi-solution-quotation/SKILL.md +76 -0
- package/dist/microi.skills/microi-solution-quotation/agents/openai.yaml +4 -0
- package/dist/microi.skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -0
- package/dist/microi.skills/microi-system-delivery/SKILL.md +446 -0
- package/dist/microi.skills/microi-ui/SKILL.md +321 -0
- package/dist/microi.skills/microi-uniapp-frontend/SKILL.md +483 -0
- package/dist/microi.skills/microi.v8.js +1758 -0
- package/dist/microi.skills/module-engine/SKILL.md +131 -0
- package/dist/microi.skills/module-engine/references/module-config.md +174 -0
- package/dist/microi.skills/page-engine/SKILL.md +397 -0
- package/dist/microi.skills/performance-testing/SKILL.md +207 -0
- package/dist/microi.skills/playwright-e2e/SKILL.md +769 -0
- package/dist/microi.skills/print-engine/SKILL.md +237 -0
- package/dist/microi.skills/production-readonly-audit/SKILL.md +39 -0
- package/dist/microi.skills/report-engine/SKILL.md +69 -0
- package/dist/microi.skills/report-engine/agents/openai.yaml +4 -0
- package/dist/microi.skills/search-engine/SKILL.md +73 -0
- package/dist/microi.skills/search-engine/agents/openai.yaml +4 -0
- package/dist/microi.skills/spider-engine/SKILL.md +188 -0
- package/dist/microi.skills/translate-engine/SKILL.md +91 -0
- package/dist/microi.skills/translate-engine/agents/openai.yaml +4 -0
- package/dist/microi.skills/ui-design/SKILL.md +1575 -0
- package/dist/microi.skills/ui-design/assets/pattern-showcase/app.js +54 -0
- package/dist/microi.skills/ui-design/assets/pattern-showcase/index.html +163 -0
- package/dist/microi.skills/ui-design/assets/pattern-showcase/styles.css +311 -0
- package/dist/microi.skills/ui-design/assets/templates/MCI-DESIGN.md +98 -0
- package/dist/microi.skills/ui-design/references/design-pattern-library.md +171 -0
- package/dist/microi.skills/ui-design/references/mci-design-contract.md +84 -0
- package/dist/microi.skills/ui-design/references/motion-and-media.md +71 -0
- package/dist/microi.skills/ui-design/references/product-flow-recipes.md +94 -0
- package/dist/microi.skills/uniapp-mall-assets/SKILL.md +105 -0
- package/dist/microi.skills/v8-api-config/SKILL.md +272 -0
- package/dist/microi.skills/v8-cache-pattern/SKILL.md +286 -0
- package/dist/microi.skills/v8-crud-api/SKILL.md +398 -0
- package/dist/microi.skills/v8-debugging/SKILL.md +279 -0
- package/dist/microi.skills/v8-explorer-tree/SKILL.md +224 -0
- package/dist/microi.skills/v8-export-import/SKILL.md +590 -0
- package/dist/microi.skills/v8-file-upload/SKILL.md +497 -0
- package/dist/microi.skills/v8-formengine-http/SKILL.md +218 -0
- package/dist/microi.skills/v8-frontend-events/SKILL.md +349 -0
- package/dist/microi.skills/v8-frontend-events/references/bluetooth-print-api.md +107 -0
- package/dist/microi.skills/v8-frontend-events/references/bluetooth-print.md +185 -0
- package/dist/microi.skills/v8-http-integration/SKILL.md +379 -0
- package/dist/microi.skills/v8-image-processing/SKILL.md +187 -0
- package/dist/microi.skills/v8-image-processing/agents/openai.yaml +4 -0
- package/dist/microi.skills/v8-image-processing/references/api-reference.md +620 -0
- package/dist/microi.skills/v8-menu-buttons/SKILL.md +661 -0
- package/dist/microi.skills/v8-mongodb/SKILL.md +149 -0
- package/dist/microi.skills/v8-mq-mqtt/SKILL.md +227 -0
- package/dist/microi.skills/v8-saas-multi-tenant/SKILL.md +193 -0
- package/dist/microi.skills/v8-security/SKILL.md +417 -0
- package/dist/microi.skills/v8-sql-query/SKILL.md +290 -0
- package/dist/microi.skills/v8-table-event/SKILL.md +385 -0
- package/dist/microi.skills/v8-template-engine/SKILL.md +165 -0
- package/dist/microi.skills/v8-utilities/SKILL.md +79 -0
- package/dist/microi.skills/v8-utilities/references/client-api-index.md +136 -0
- package/dist/microi.skills/v8-utilities/references/platform-http-routes.md +80 -0
- package/dist/microi.skills/v8-utilities/references/server-api-index.md +129 -0
- package/dist/microi.skills/v8-workflow/SKILL.md +322 -0
- package/dist/microi.skills/workspace-conventions/SKILL.md +479 -0
- package/package.json +40 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: microi-frontend-sdk
|
|
3
|
+
description: Microi 前端 SDK 使用规范,适用于 Vue 3、uni-app、H5、PC 网站与 Microi.Client 扩展。用于创建或修改前端请求、登录态、Token 续签、终端会话、上传、文件 URL、ApiEngine、FormEngine 或应用启动代码。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Microi 前端 SDK
|
|
7
|
+
|
|
8
|
+
所有 Vue 3 前端项目都应使用 `microi.skills/microi.v8.js` 作为统一的 Microi 前端 SDK。新项目不要复制旧版 Vue2/Vuex 请求封装,也不要重新手写 token、上传、文件 URL、ApiEngine 或 FormEngine 层。
|
|
9
|
+
|
|
10
|
+
## 必须采用的模式
|
|
11
|
+
|
|
12
|
+
将 SDK 复制到项目源码目录,通常是:
|
|
13
|
+
|
|
14
|
+
- uni-app: `src/utils/microi.v8.js`
|
|
15
|
+
- PC Vue 3 网站: `src/utils/microi.v8.js`
|
|
16
|
+
- Microi.Client 扩展页面:如果已有平台请求层就复用;否则从本地工具模块引入 SDK。
|
|
17
|
+
|
|
18
|
+
在项目请求模块里只创建一个已配置实例:
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
import { createMicroiV8 } from './microi.v8.js';
|
|
22
|
+
|
|
23
|
+
export const V8 = createMicroiV8({
|
|
24
|
+
apiBase: config.apiBase,
|
|
25
|
+
fileServer: config.fileServer,
|
|
26
|
+
webBase: config.webBase,
|
|
27
|
+
osClient: config.osClient,
|
|
28
|
+
tokenKey: 'microi_token',
|
|
29
|
+
userKey: 'microi_user',
|
|
30
|
+
formQueryEngineKey: 'mall_form_query',
|
|
31
|
+
maxConcurrent: 8,
|
|
32
|
+
appendOsClientQuery: true,
|
|
33
|
+
onAuthExpired: () => {
|
|
34
|
+
V8.clearToken();
|
|
35
|
+
uni.reLaunch({ url: '/pages/login/login' });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
在 Vue 3 启动入口挂载:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
import { V8 } from './utils/request.js';
|
|
44
|
+
|
|
45
|
+
export function createApp() {
|
|
46
|
+
const app = createSSRApp(App);
|
|
47
|
+
V8.install(app);
|
|
48
|
+
return { app };
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
页面和业务接口模块应从项目请求模块导入已配置实例或薄封装函数,不要直接从标准 skill 文件导入。
|
|
53
|
+
|
|
54
|
+
## 必须委托 SDK 的能力
|
|
55
|
+
|
|
56
|
+
- `ApiEngine.Run`:直接调用 `/apiengine/{key}` 时使用 `V8.ApiEngine.Run(key, data)`。
|
|
57
|
+
- 旧版 `/api/ApiEngine/Run` 只有在老系统仍然需要时才使用 `V8.ApiEngine.RunLegacy(key, data)`。
|
|
58
|
+
- FormEngine CRUD 使用 `V8.FormEngine.*`,或使用 `formEngineGet` 这类项目薄封装。
|
|
59
|
+
- 上传使用 `V8.uploadFile`。
|
|
60
|
+
- 图片、头像、富文本图片、二维码、付款凭证、证件和私有文件使用 `V8.assetUrl`、`V8.resolveFileUrl` 或 `V8.resolveAvatarUrl`。
|
|
61
|
+
- Token 与用户缓存使用 `V8.getToken`、`V8.setToken`、`V8.clearToken`、`V8.getUser` 和 `V8.setUser`。
|
|
62
|
+
- 公有 HDFS 上的 AI 应用使用 `microi-ai-app-auth.js` 统一桥接登录:页面和只读演示保持匿名可见,首次持久化 `app_*` 操作弹出登录框,登录成功后携带 Token 重试。后端必须再次识别写代码并以 `V8.CurrentUser.Id` 覆盖 `ClientKey`、`ActorKey`、`UserId`,禁止只靠前端按钮判断。
|
|
63
|
+
- JavaScript 需要平台安全区数值时使用 `V8.getSafeArea`;CSS 仍使用 `env(safe-area-inset-*)`。
|
|
64
|
+
|
|
65
|
+
`Microi.Client` 主后台运行时已内置前后端同构的 `V8.Http.Get/Post/Patch` 及对应 Response 方法;表单事件、按钮 V8 等宿主前端新代码必须优先使用 `V8.Http`,旧 `V8.Post/Get` 仅作兼容保留,其参数和兼容规则以 `v8-http-integration/SKILL.md` 为准。独立项目使用本 SDK、且不在主后台 V8 宿主中时,才使用 SDK 自身的小写 `V8.get/post`、`ApiEngine`、`FormEngine`;不要把它们与宿主旧版大写 `V8.Post/Get` 混为一谈,也不要假设浏览器可以绕过第三方接口的 CORS。
|
|
66
|
+
|
|
67
|
+
## 登录与验证码封装
|
|
68
|
+
|
|
69
|
+
SDK 或项目请求模块必须提供登录所需的系统配置和验证码薄封装,不要让页面散落手写。
|
|
70
|
+
|
|
71
|
+
要求:
|
|
72
|
+
- 提供 `isEnabledFlag(value)` 或等价工具,统一判断 `Sys_Config.EnableCaptcha`。它必须把 `true`、`1`、`'true'`、`'1'` 识别为开启,把 `false`、`0`、`'false'`、`'0'`、空值识别为关闭。
|
|
73
|
+
- 提供 `getSysConfig()`,内部调用 `V8.GetSysConfig(true)` 或 `/api/DiyTable/GetSysConfig`,并保持当前租户 `OsClient` 一致。
|
|
74
|
+
- 提供 `getCaptcha()`,内部调用 `GET /api/Captcha/GetCaptcha`,`responseType:'arraybuffer'`,从响应头读取 `captchaid`,返回 `{ CaptchaId, ImageSrc }`。
|
|
75
|
+
- 提供账号登录封装时,只有在页面传入验证码时才追加 `_CaptchaId/_CaptchaValue`;不要在未开启验证码时提交空字段。
|
|
76
|
+
- PC Vue、UniApp H5、微信小程序和 App 的账号密码登录都必须使用同一套验证码判断和登录参数契约。
|
|
77
|
+
|
|
78
|
+
参考薄封装:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
export function isEnabledFlag(value) {
|
|
82
|
+
if (value === true || value === 1) return true;
|
|
83
|
+
if (typeof value === 'string') {
|
|
84
|
+
const text = value.trim().toLowerCase();
|
|
85
|
+
return text === '1' || text === 'true' || text === 'yes' || text === 'on';
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function getSysConfig() {
|
|
91
|
+
return await V8.GetSysConfig(true);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function login(account, pwd, captcha = {}) {
|
|
95
|
+
return V8.Login({
|
|
96
|
+
Account: account,
|
|
97
|
+
Pwd: pwd,
|
|
98
|
+
_CaptchaId: captcha.CaptchaId || undefined,
|
|
99
|
+
_CaptchaValue: captcha.CaptchaValue || undefined
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 请求头规则
|
|
105
|
+
|
|
106
|
+
SDK 的 `buildHeaders` 必须集中处理所有请求头,不能让页面、业务 wrapper 或上传逻辑各自拼接租户和鉴权头。
|
|
107
|
+
|
|
108
|
+
- `osclient` 必须作为唯一租户请求头键,值来自当前运行期租户,例如 `demo`。写入前删除已有 `OsClient` / `osclient` / 任意大小写变体。
|
|
109
|
+
- `Authorization` 写入前也必须删除已有 `Authorization` / `authorization` 变体。需要同时兼容平台 Token 时,可以保留单独的 `Token` 请求头,但它也必须先做大小写去重。
|
|
110
|
+
- 页面传入的 `headers` / `header` 要先合并,再统一去重;禁止 `headers.OsClient = ...` 和 `headers.osclient = ...` 同时存在。
|
|
111
|
+
- 小程序授权登录、账号登录、刷新 Token、FormEngine、ApiEngine、上传都必须走同一套去重逻辑。
|
|
112
|
+
- 验收时检查真实网络请求:不得出现 `osclient: demo, demo`、`Authorization: Bearer xxx, Bearer xxx` 这类逗号合并值。
|
|
113
|
+
|
|
114
|
+
## Token、当前登录用户与当前终端登录协议
|
|
115
|
+
|
|
116
|
+
Microi 后端不是只保存一个全局 Token。每个租户、每个 `sys_user` 在 Redis 中维护一份 `CurrentToken`,其中 `CurrentUser` 表示平台当前登录用户,`Tokens` 表示该用户的多个当前终端登录。每个终端项至少包含 `Token`、`ClientType`、`Did`、`IP`、`CreateTime`、`UpdateTime`;退出、管理员清除登录信息、同终端重新登录或 Token 轮换都会影响该列表。
|
|
117
|
+
|
|
118
|
+
登录必须同时标记终端类型和稳定设备 Id:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
const V8 = createMicroiV8({
|
|
122
|
+
apiBase,
|
|
123
|
+
osClient,
|
|
124
|
+
clientType: 'Mobile', // PC / Mobile / H5 / App / WxMiniProgram / VSCode / MCP
|
|
125
|
+
didKey: 'microi_did'
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const result = await V8.Login({
|
|
129
|
+
Account,
|
|
130
|
+
Pwd,
|
|
131
|
+
_ClientType: 'Mobile'
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- PC 后台传 `_ClientType:'PC'`,有效期读取 SaaS 引擎 `SessionAuthTimeout`,单位分钟,默认 20 分钟。
|
|
136
|
+
- VS Code 传 `_ClientType:'VSCode'`,优先读取 `VSCodeAccessTokenLifetime`,否则读取 `AccessTokenLifetime`,单位天,默认 30 天。
|
|
137
|
+
- MCP 传 `_ClientType:'MCP'`,优先读取 `McpAccessTokenLifetime`,否则读取 `AccessTokenLifetime`,单位天,默认 30 天。
|
|
138
|
+
- Mobile、H5、App、各类小程序及其它非 PC 终端读取 `AccessTokenLifetime`,单位天,默认 30 天。
|
|
139
|
+
- `did` 通过请求头发送,同一安装或浏览器配置必须稳定持久化;不要每次请求生成新值。标准 SDK 使用 `V8.getDid()` 自动生成和复用。
|
|
140
|
+
- Token 优先从响应头 `authorization` 读取,并立即覆盖本地旧 Token;兼容接口才从响应体读取。每个受保护请求都要接收响应头中的新 Token,因为后端可能在普通请求中自动轮换。
|
|
141
|
+
|
|
142
|
+
### 续签时机
|
|
143
|
+
|
|
144
|
+
不要把本地固定 15 分钟当作所有终端的有效期。读取 JWT 的 `exp` 与 `MicroiTokenIssuedAt`,在到期前按以下规则触发以旧换新:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
提前量 = lifetime / 10
|
|
148
|
+
最少提前 5 分钟
|
|
149
|
+
最多提前 1 天
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
因此默认 PC 20 分钟会在约第 15 分钟续签;默认移动端、VS Code 30 天会在到期前 1 天进入续签窗口。调用:
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
V8.startTokenMaintenance();
|
|
156
|
+
|
|
157
|
+
// UniApp/App/小程序每次回到前台
|
|
158
|
+
await V8.resumeAuthSession(false);
|
|
159
|
+
|
|
160
|
+
// 主动以旧换新
|
|
161
|
+
const result = await V8.refreshToken();
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- Web 同时监听 `visibilitychange`、`focus`、`pageshow`。浏览器可能休眠后台标签页并暂停 `setInterval`,恢复可见时必须立即检查,不能等下一个定时周期。
|
|
165
|
+
- UniApp/App/小程序在 `App.onShow` 调用 `resumeAuthSession(false)`。
|
|
166
|
+
- VS Code 在扩展激活后维护 Token,并在 `vscode.window.onDidChangeWindowState` 恢复焦点时立即检查。
|
|
167
|
+
- 多请求、多 Tab 续签必须 single-flight。PC 后台可使用 Web Locks;收到响应时,如果本地 Token 已被其它 Tab 更新,旧请求不得把旧 Token 覆盖回来或清掉新登录态。
|
|
168
|
+
- 调用 `/api/SysUser/RefreshToken` 时同时传旧 `authorization`、当前 `OsClient`、原终端 `_ClientType`,请求头继续传稳定 `did`。不要频繁无条件换新。
|
|
169
|
+
|
|
170
|
+
### 失效提示与租户边界
|
|
171
|
+
|
|
172
|
+
受保护接口返回 `Code=1001/1002`,或 RefreshToken 返回登录失效时,必须原样展示后端 `Msg`,禁止覆盖成固定“登录已过期”。后端会返回 `DataAppend` 诊断:
|
|
173
|
+
|
|
174
|
+
| `ReasonCode` | 处理方式 |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `JwtExpired` / `SessionExpired` | 展示已过期分钟、小时或天以及过期时间,然后清理当前终端会话并重新登录 |
|
|
177
|
+
| `TenantMismatch` | 提示 Token 所属租户与当前请求租户,切换租户或重新登录;禁止把该 Token 用于当前租户 |
|
|
178
|
+
| `TokenReplaced` | 先检查本地 Token 是否已被其它 Tab/并发请求更新;有新 Token 时重试一次,否则重新登录 |
|
|
179
|
+
| `SessionMissing` | 服务端登录态已退出、被管理员清除或缓存已重建;清理本地 Token 并重新登录 |
|
|
180
|
+
| `AuthVersionChanged` | 后端安全版本已升级,必须重新登录 |
|
|
181
|
+
| `MalformedToken` / `MissingClaims` | Token 无法继续使用,清理并重新登录 |
|
|
182
|
+
|
|
183
|
+
不要显示完整 Token、用户密码或密钥。日志只记录 `ReasonCode`、终端类型、脱敏 `did`、请求租户和 Token 租户。`TokenOsClient` 只用于提示和诊断,真正鉴权仍以服务端签名、租户和 Redis 当前终端列表为准。
|
|
184
|
+
|
|
185
|
+
### Token 验收
|
|
186
|
+
|
|
187
|
+
- PC、移动端、VS Code 分别登录,回读 JWT `ClientType`、`Did` 和有效期,确认命中对应 SaaS 配置。
|
|
188
|
+
- 模拟页面隐藏超过 PC 有效期后恢复,确认先执行续签;若已无法续签,提示精确显示过期时长。
|
|
189
|
+
- 使用 A 租户 Token 请求 B 租户,确认返回 `TenantMismatch`,提示同时包含 Token 租户与当前租户且不泄漏 Token。
|
|
190
|
+
- 同一旧 Token 并发调用两次 RefreshToken,确认复用同一新 Token,后续请求成功。
|
|
191
|
+
- 管理员调用 `ClearUserLoginInfo` 后,旧 Token 返回 `SessionMissing` 或等价明确原因,前端不再循环续签。
|
|
192
|
+
|
|
193
|
+
## 上传规则
|
|
194
|
+
|
|
195
|
+
`V8.uploadFile` 是 Microi 前端唯一允许的上传入口。SDK 实现必须:
|
|
196
|
+
|
|
197
|
+
- 使用 multipart 上传头。`uni.uploadFile` 或 `fetch(FormData)` 不得发送 `Content-Type: application/json`。
|
|
198
|
+
- 租户请求头只发送一个键:`osclient`。添加配置租户前,先移除传入的 `osclient` / `OsClient` 重复键。
|
|
199
|
+
- `formData` 中发送 `OsClient`;开启 `appendOsClientQuery` 时保留接口查询参数 `?OsClient=tenant`。
|
|
200
|
+
- 上传 `Path` 统一从 `options.path`、`formData.Path` 或 `formData.path` 归一化。
|
|
201
|
+
- 移动端上传路径必须是安全相对路径,例如 `mall/pay-proof` 或 `mall/member/avatar`。不要使用 `/mall/pay-proof`、完整 URL、磁盘路径、`..`、`:`、`//` 或 `~`。
|
|
202
|
+
- 项目薄封装要通过 `{ ...options, path: options.path || defaultPath }` 透传全部选项,避免丢失页面级 `headers`、`action`、`anonymous`、`file`、`formData` 和 `silentError`。
|
|
203
|
+
- H5 页面要保留 `uni.chooseImage` 返回的真实 `File` 对象(可用时为 `tempFiles[0].file`)。如果 H5 只返回 `tempFiles[0]` 或 `blob:` / `data:` 临时路径,也要继续传入,不要丢弃。调用 `V8.uploadFile(..., { file, preferFetch:true })`。SDK 必须识别 `File` / `Blob`、`file` / `raw` / `blob` / `originFileObj` 等常见嵌套字段,以及 `blob:` / `data:` 路径,然后优先使用 `fetch + FormData`,必要时在 `uni.uploadFile` 与 fetch 之间回退。
|
|
204
|
+
- 上传提交处理不得使用空 `catch`。要用 `body.Msg` / `error.message` 提示用户,记录错误便于诊断,并在 `finally` 中重置上传状态。
|
|
205
|
+
- 上传响应与普通请求一样可能通过 `Authorization` / `Token` 响应头轮换登录令牌;`fetch(FormData)` 和 `uni.uploadFile` 成功回调都必须先接收新 Token,再发起后续接口。
|
|
206
|
+
|
|
207
|
+
当上传突然报 `移动端文件上传路径不合法!` 时,先检查实际 multipart 表单字段和请求头。在 Microi 移动端/会员 Token 流程中,后端会在 HDFS 上传前校验 `Path`;错误的 `Content-Type` 会导致后端读不到表单字段,并表现为路径错误。
|
|
208
|
+
|
|
209
|
+
## 项目封装规则
|
|
210
|
+
|
|
211
|
+
面向业务页面的函数名要保持稳定。如果已有项目导出 `callEngine`、`formEngineGet`、`getImageUrl`、`parseImages` 或 `uploadFile`,保留这些导出,内部委托给 `V8`。这样既能统一 SDK,又能避免大面积改页面。
|
|
212
|
+
|
|
213
|
+
正确写法:
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
export function callEngine(key, params = {}, options = {}) {
|
|
217
|
+
return V8.ApiEngine.Run(key, params, { checkCode: true, ...options });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function getImageUrl(value) {
|
|
221
|
+
return V8.assetUrl(value);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
避免写法:
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
uni.request({ url: apiBase + '/apiengine/' + key, header: { Token: token } });
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## 仅支持 Vue 3
|
|
232
|
+
|
|
233
|
+
新的 Microi 前端工作只支持 Vue 3。不要把 Vue2、Vuex、`Vue.prototype` 或 Vue2/uni-app 条件编译加入 `microi.v8.js`。状态管理属于项目本身,通常使用 Pinia 或本地组合函数;SDK 只负责平台访问、请求、鉴权、上传、资源 URL 和小工具。
|
|
234
|
+
|
|
235
|
+
## Key-Value 枚举的跨端约定(强制)
|
|
236
|
+
|
|
237
|
+
- PC、UniApp、小程序和 Web 页面遇到简单枚举时,应从字段元数据或业务接口返回的公开 `{Key,Value}` 选项获取数据源;`Value` 只负责展示,`Key` 才能进入表单值、URL、缓存键和接口筛选参数。
|
|
238
|
+
- 不得把中文 `Value` 当作查询条件,也不得在各端复制维护互相漂移的中文/英文映射。若业务接口已返回选项投影,优先直接消费;本地常量只能作为接口暂时不可用时的同 Key 兜底。
|
|
239
|
+
- 页面 URL 需要保存筛选状态时写入稳定英文 Key,返回页面后按 Key 恢复选中项;切换语言只替换 Value,不得改变 URL 和数据库值。
|
|
240
|
+
- 兼容历史数据时,客户端可以短期识别旧 Value,但提交和新 URL 必须立即归一为 Key;长期迁移由服务端完成并回读验证。
|
|
241
|
+
|
|
242
|
+
## 界面层独立
|
|
243
|
+
|
|
244
|
+
SDK 不得导入 Element Plus、uni-ui、uView、TDesign、FirstUI、Pinia、Vue Router 或 axios。界面反馈通过可配置适配器提供:
|
|
245
|
+
|
|
246
|
+
- `toast(message)`
|
|
247
|
+
- `confirm(message)`
|
|
248
|
+
- `onAuthExpired(body, V8)`
|
|
249
|
+
- optional `requestAdapter(options)`
|
|
250
|
+
|
|
251
|
+
这样同一个 SDK 才能同时用于 uni-app、PC 网站、后台扩展页面和文档演示。
|
|
252
|
+
|
|
253
|
+
## 验证
|
|
254
|
+
|
|
255
|
+
将项目改为使用 SDK 后:
|
|
256
|
+
|
|
257
|
+
- 运行相关构建或类型检查。
|
|
258
|
+
- 至少测试一次需要登录的 ApiEngine 调用和一次匿名调用。
|
|
259
|
+
- 用 `assetUrl` 测试一个图片或上传 JSON 字段。
|
|
260
|
+
- 如果任务涉及鉴权,测试 Token 过期行为。
|
|
261
|
+
- 对 uni-app H5,同时验证移动视口和 PC 浏览器手机壳下 SDK 正常工作。
|
|
262
|
+
|
|
263
|
+
### 复盘:生产构建被 `.env.local` 的 localhost 地址污染
|
|
264
|
+
|
|
265
|
+
- 触发场景:本地开发通过 `.env.local` 指向 `localhost` API,发布后的官网仍请求开发者电脑的 loopback 地址,线上出现 `Failed to fetch`。
|
|
266
|
+
- 根因:Vite 会在所有模式加载 `.env.local`;它不是仅开发模式文件。若生产模式没有更高优先级配置,loopback 地址会被编译进正式产物。
|
|
267
|
+
- 通用规则:本地 API 只写入 `.env.development.local`;生产项目必须提供 `.env.production`。独立官网还要在统一 ApiBase 解析层拒绝“生产构建或非本地域名 + localhost/127.0.0.1/::1”,并安全回退到明确的正式 API。
|
|
268
|
+
- 自动化检查:生产构建后扫描 JS 产物不得包含本地 ApiBase,并在正式域名上下文断言接口请求 origin 等于配置的生产 API;本地 `npm run dev` 仍应命中开发 API。
|
|
269
|
+
|
|
270
|
+
## 搭配 MCI-UI
|
|
271
|
+
|
|
272
|
+
SDK 负责平台能力,MCI-UI 负责产品界面。新的 Microi Vue3 项目应同时使用:
|
|
273
|
+
|
|
274
|
+
- `microi.skills/microi.v8.js`:请求、Token、上传、文件 URL、ApiEngine/FormEngine。
|
|
275
|
+
- `Microi.UI/src/theme`:`--mci-*` 设计变量。
|
|
276
|
+
- `Microi.UI/src/uniapp`:移动端/UniApp 组件。
|
|
277
|
+
- `Microi.UI/src/web`:PC 官网和响应式网站组件。
|
|
278
|
+
|
|
279
|
+
不要在 SDK 内解决界面状态、骨架屏、富文本间距或安全区布局。这一层应使用 MCI-UI 组件处理。
|
|
280
|
+
|
|
281
|
+
## MicroApp 宿主 Token 同步
|
|
282
|
+
|
|
283
|
+
Vue3 前端微服务通过 `window.microApp.getData()` 接收主平台上下文时,不能只把 `token` 放进普通配置对象后假设请求会自动携带。标准 `microi.v8.js` 必须支持 `config.token`,且 `getToken()` 要优先读取运行时 token,再回退到 `storage[tokenKey]`。微服务必须复用同一个 V8 客户端实例,不能在每次按钮点击时重新 `createMicroiV8()`。
|
|
284
|
+
|
|
285
|
+
`getData()` 中的 Token 是宿主传入的快照,只能用于首次引导或宿主确实下发了不同值时更新;不能在每次 `configureMicroiV8()` 时用旧快照覆盖 SDK 已从响应头取得的新 Token。推荐同时配置 `onTokenChanged`,把新 Token 与发起请求所用的旧 Token 回传宿主,宿主通过 `DiyCommon.ApplyAuthorizationToken(newToken, requestToken)` 接力并防止多标签页旧响应回写:
|
|
286
|
+
|
|
287
|
+
```js
|
|
288
|
+
const microiV8 = V8; // 模块级单例
|
|
289
|
+
let appliedHostToken = '';
|
|
290
|
+
|
|
291
|
+
microiV8.configure({
|
|
292
|
+
apiBase: ctx.apiBase,
|
|
293
|
+
osClient: ctx.osClient,
|
|
294
|
+
onTokenChanged: (token, requestToken) => {
|
|
295
|
+
window.microApp?.dispatch?.({ type: 'micro-app:token', data: { token, requestToken } });
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
if (ctx.token && ctx.token !== appliedHostToken) {
|
|
299
|
+
appliedHostToken = ctx.token;
|
|
300
|
+
microiV8.setToken(ctx.token);
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
普通 `request`、浏览器 `fetch(FormData)` 上传和 `uni.uploadFile` 都必须读取响应头的新 Token。验收时必须连续执行至少两个需要登录态的请求(前一个允许发生 Token 轮换),确认后一个仍返回 `Code=1`;不能只看页面首屏渲染成功。
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: microi-left-right-layout
|
|
3
|
+
description: Microi 吾码模块引擎“树形+表格/表单”左右结构配置规范。用于通过 MCP、模块引擎或源码配置 `diy_LeftJoinRightView`,把项目、分类、组织等主数据作为左树,并用主外键过滤右侧列表;覆盖字段语义、初始化 V8、移动端自适应、幂等写入和回读验收。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Microi 左右树表配置规范
|
|
7
|
+
|
|
8
|
+
当需求是“左侧按项目/分类导航,右侧显示该节点的数据列表或表单”时,使用模块组件 `/diy/left-right/LeftTreeJoinRightForm`,配置表为 `diy_LeftJoinRightView`。不要为每个业务菜单复制定制 Vue 页面。
|
|
9
|
+
|
|
10
|
+
## 适用与禁用场景
|
|
11
|
+
|
|
12
|
+
- 适用:项目及其成品、用料、请购、提料、锁料、文档,分类及商品,组织及人员。
|
|
13
|
+
- 左侧必须是稳定的主数据;右侧必须能通过明确的主外键过滤。
|
|
14
|
+
- 左右两边没有关联字段、左侧仅是装饰性筛选,或数据量极大却没有分页/搜索方案时,不应直接套用。
|
|
15
|
+
|
|
16
|
+
## 模块配置
|
|
17
|
+
|
|
18
|
+
目标 `sys_menu` 必须配置:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"ComponentName": "树形+表格",
|
|
23
|
+
"ComponentPath": "/diy/left-right/LeftTreeJoinRightForm"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
同一菜单只能有一条有效的 `diy_LeftJoinRightView` 配置。创建前先按 `GuanlianCD Like 菜单Id` 回读并复用,禁止重复插入。
|
|
28
|
+
|
|
29
|
+
## `diy_LeftJoinRightView` 字段
|
|
30
|
+
|
|
31
|
+
| 字段 | 必填 | 含义与写法 |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| `GuanlianCD` | 是 | 当前右侧业务菜单链,JSON 数组;末级必须是当前 `sys_menu.Id`。 |
|
|
34
|
+
| `ShuxingGLCD` | 是 | 左侧主数据菜单链,JSON 数组;末级对应左表模块。 |
|
|
35
|
+
| `GuanlianBD` | 是 | 左侧主表名,例如 `xiangmuguanli`。 |
|
|
36
|
+
| `FubiaoGLZD` | 是 | 左表参与关联的字段,通常为 `Id`。 |
|
|
37
|
+
| `ZibiaoGLZD` | 右表格必填 | 右表外键,例如 `XiangmuID`、`ProjectId`、`Guid`。必须以实时表结构为准。 |
|
|
38
|
+
| `GuanlianPPLJ` | 右表格必填 | 匹配操作符,普通主外键使用 `=`。 |
|
|
39
|
+
| `ZuobianZSZJ` | 是 | 左侧组件,通常为 `树形控件`。 |
|
|
40
|
+
| `YoubianZSZJ` | 是 | `表格`、`表单` 或 `表单/表格`。 |
|
|
41
|
+
| `ShuxianSZDM` | 是 | 左树显示字段,必须与初始化结果的属性名一致。 |
|
|
42
|
+
| `ChushiHDM` | 是 | 初始化 V8。必须读取 `V8.Form._PageIndex/_PageSize/inputText`,最终返回 `Data` 和 `DataCount`。 |
|
|
43
|
+
| `ZuoyouXSZB` | 否 | 24 栅格比例,例如 `6/18`、`4/20`,中间 `/` 必须保留。 |
|
|
44
|
+
| `ShubiaoT` | 否 | 左树标题,例如 `项目目录`。 |
|
|
45
|
+
| `ShumoHSS` | 否 | 模糊搜索开关。 |
|
|
46
|
+
| `ShuxiaLSS` | 否 | 搜索字段下拉开关。 |
|
|
47
|
+
| `ShusouSAN` | 否 | 搜索按钮开关。 |
|
|
48
|
+
| `ShushuaX` | 否 | 刷新按钮开关。 |
|
|
49
|
+
| `ShudingJXZ` | 否 | 是否允许新增顶级树节点。 |
|
|
50
|
+
| `ShuxinZ`、`ShubianJ`、`ShushanC` | 否 | 树节点新增、编辑、删除开关。只在业务允许时开启。 |
|
|
51
|
+
| `ShujieDDJSJ` | 否 | 节点点击 V8;可读取 `V8.Form`,异步结果写入 `V8.Result`。 |
|
|
52
|
+
| `YincangBSF` | 否 | 节点命中该字段时隐藏右侧区域。 |
|
|
53
|
+
| `TanchuangLX`、`TanchuangDX` | 否 | 树节点维护弹窗类型和尺寸。 |
|
|
54
|
+
| `LanjiaZ`、`LanjiaZDM` | 否 | 懒加载开关和代码;大树优先使用。 |
|
|
55
|
+
|
|
56
|
+
## 初始化 V8 与分页契约
|
|
57
|
+
|
|
58
|
+
左树按数据表对待,默认每页 20 条,允许 10/20/50/100 条切换。无论当前只有多少数据,都不能用 `_PageSize:500` 一次拉完整主表。搜索时把页码重置为 1,并在服务端按关键字过滤后返回真实总数。
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
var form = V8.Form || {};
|
|
62
|
+
var pageIndex = Math.max(1, parseInt(form._PageIndex || 1, 10));
|
|
63
|
+
var pageSize = Math.min(100, Math.max(1, parseInt(form._PageSize || 20, 10)));
|
|
64
|
+
var keyword = String(form.inputText || '').trim();
|
|
65
|
+
var query = {
|
|
66
|
+
_SelectFields: ['Id', 'Code', 'Name'],
|
|
67
|
+
_OrderBy: 'CreateTime',
|
|
68
|
+
_OrderByType: 'DESC',
|
|
69
|
+
_PageIndex: pageIndex,
|
|
70
|
+
_PageSize: pageSize
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (keyword) {
|
|
74
|
+
query._Where = [
|
|
75
|
+
['Code', 'Like', keyword],
|
|
76
|
+
['OR', 'Name', 'Like', keyword]
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var result = await V8.FormEngine.GetTableData('xiangmuguanli', query);
|
|
81
|
+
|
|
82
|
+
if (result.Code !== 1) {
|
|
83
|
+
V8.Result = result;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
V8.Result = {
|
|
88
|
+
Code: 1,
|
|
89
|
+
Data: (result.Data || []).map(function (item) {
|
|
90
|
+
return {
|
|
91
|
+
Id: item.Id,
|
|
92
|
+
TreeTitle: [item.Code, item.Name].filter(Boolean).join(' '),
|
|
93
|
+
Code: item.Code,
|
|
94
|
+
Name: item.Name
|
|
95
|
+
};
|
|
96
|
+
}),
|
|
97
|
+
DataCount: Number(result.DataCount || 0),
|
|
98
|
+
PageIndex: pageIndex,
|
|
99
|
+
PageSize: pageSize
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
对应配置为 `ShuxianSZDM=TreeTitle`、`FubiaoGLZD=Id`。右侧新增时,组件会通过 `ParentDataAppend` 把父节点、父键和 `ZibiaoGLZD` 传给表格;业务字段仍需由表单事件兜底校验。
|
|
104
|
+
|
|
105
|
+
加载请求期间必须显示明确的“正在加载项目...”状态,不能先渲染“暂无数据”;多次搜索或翻页并发返回时,只应用最后一次请求,防止旧结果覆盖新页。
|
|
106
|
+
|
|
107
|
+
## MCP 实施顺序
|
|
108
|
+
|
|
109
|
+
1. 调用实时 Schema/模块查询,确认左右表、菜单 Id、主键、外键和已有配置。
|
|
110
|
+
2. 读取一个已正常运行的左右结构作为基线,只复用结构,不复制租户或业务字段。
|
|
111
|
+
3. 按当前菜单回读 `diy_LeftJoinRightView`;有记录则更新,无记录才新增。
|
|
112
|
+
4. 更新模块 `ComponentName`、`ComponentPath`,随后回读模块和配置行。
|
|
113
|
+
5. 验证“全部”、单节点切换、右表筛选、右侧新增自动关联、刷新和搜索。
|
|
114
|
+
|
|
115
|
+
## 移动端要求
|
|
116
|
+
|
|
117
|
+
- `<=767px` 时不在列表上方直接堆放左树。右侧业务列表占满宽度,顶部显示当前项目和“项目目录”按钮。
|
|
118
|
+
- 点击“项目目录”后,从左向右打开全高抽屉;推荐宽度 `88%`,保留一段遮罩用于快速关闭。抽屉必须支持关闭按钮、点击遮罩和 Esc 关闭。
|
|
119
|
+
- 左树在抽屉内独立滚动,搜索、分页和每页条数选择都必须可操作;关闭抽屉后右表筛选状态不得丢失。
|
|
120
|
+
- 右表与页面使用正常纵向滚动,禁止祖先容器 `overflow:hidden` 截断内容。
|
|
121
|
+
- 右侧卡片、表格 Tab、列表卡片在移动端必须使用 `height:auto` 和 `overflow:visible`;底部操作栏不得盖住最后一条数据。
|
|
122
|
+
- 至少验收桌面 1440x900、手机 390x844;在手机上分别滚动左树和整页到末尾。
|
|
123
|
+
|
|
124
|
+
## 验收清单
|
|
125
|
+
|
|
126
|
+
- 当前菜单只匹配一条配置,模块路径正确。
|
|
127
|
+
- 左树标题无 `undefined`、`{}`、空白重复项。
|
|
128
|
+
- 点击“全部”清空右侧外键条件;点击节点只显示该节点数据。
|
|
129
|
+
- 右侧新增数据自动写入正确外键,切换节点后不会串数据。
|
|
130
|
+
- 普通用户不出现仅管理员可用的“页面配置”。
|
|
131
|
+
- 桌面左树每页默认 20 条,可翻页并切换 10/20/50/100;加载时不出现错误的空状态。
|
|
132
|
+
- 手机初始不显示树,抽屉打开/节点选择自动关闭/遮罩关闭均正常;列表与操作区可滚动到底,无横向挤压和固定高度裁切。
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: microi-microservice
|
|
3
|
+
description: Microi 前端微服务 MicroService 开发与交付指南。用于创建、读取、修改、构建、发布或修复 Vue3 微应用,维护 microi.routes.json,绑定 sys_menu,使用 V8.OpenAppDialog,或通过 MCP 管理 Web、UniApp、MicroService 应用源码和运行时。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Microi 前端微服务
|
|
7
|
+
|
|
8
|
+
这里的 MicroService 是运行在吾码主站中的前端微应用,不是 .NET/Java 后端微服务。
|
|
9
|
+
它适合复杂租户页面、多页面应用、完整表格/上传/步骤交互和独立版本交付;业务事务、
|
|
10
|
+
权限和最终校验仍放接口引擎或可信后端。
|
|
11
|
+
|
|
12
|
+
完整数据模型、文件/路由协议和宿主通信见 `references/runtime-delivery.md`。
|
|
13
|
+
|
|
14
|
+
## 何时使用
|
|
15
|
+
|
|
16
|
+
| 需求 | 选择 |
|
|
17
|
+
|---|---|
|
|
18
|
+
| 简单确认 | `V8.ConfirmTips` |
|
|
19
|
+
| 标准单表新增/编辑/查看 | FormEngine / `V8.OpenAnyForm` |
|
|
20
|
+
| 主前端已注册组件 | `V8.OpenDialog` |
|
|
21
|
+
| 3 个以上字段、联动、上传、表格、Tab、步骤条、代码编辑 | MicroService + `V8.OpenAppDialog` |
|
|
22
|
+
| 独立菜单、多页面、AI 在线编辑、本地 Vite、独立发布 | MicroService |
|
|
23
|
+
|
|
24
|
+
## 默认发现顺序
|
|
25
|
+
|
|
26
|
+
开始写代码前:
|
|
27
|
+
|
|
28
|
+
1. `microi_list_applications` 盘点当前租户全部 Web、UniApp、MicroService 和文件清单。
|
|
29
|
+
2. `microi_get_application_context` 默认只读取元数据、文件哈希、运行时和页面;需要少量正文时显式开启内容读取。
|
|
30
|
+
3. 单个大文件按需使用 `microi_get_application_file`,不要为了查看清单把全量源码 Base64 拉入上下文。
|
|
31
|
+
4. 合适应用存在时在其中新增页面/路由,不创建“一页一个微服务”。
|
|
32
|
+
5. 没有合适应用时才脚手架/创建新 AppKey。
|
|
33
|
+
|
|
34
|
+
所有读写必须使用同一 MCP、ApiBase 和 OsClient。写操作先 dry-run,再按用户授权确认。
|
|
35
|
+
|
|
36
|
+
## 源码与产物分离
|
|
37
|
+
|
|
38
|
+
- `sys_microistore`:应用主数据。
|
|
39
|
+
- `mci_ai_app_file`:私有源码清单,内容在私有 HDFS。
|
|
40
|
+
- `mci_ai_app_version`:构建版本。
|
|
41
|
+
- `sys_microiservice`:已发布运行时。
|
|
42
|
+
- `sys_microiservice_page`:页面路由。
|
|
43
|
+
- 编译后的 HTML/JS/CSS/图片放公有 HDFS,源码不公开。
|
|
44
|
+
|
|
45
|
+
不能从 `sys_microiservice` 公有产物反推完整源码,也不把大 JS/CSS 长期塞数据库 JSON。
|
|
46
|
+
|
|
47
|
+
## 本地工程
|
|
48
|
+
|
|
49
|
+
新建和整体升级项目的通用前端架构遵守 `microi-ai-application`:默认使用 Vue 3 单文件组件、Composition API、Vite 和严格 TypeScript。本 Skill 继续负责 MicroService 特有的 Manifest、页面路由、宿主上下文、菜单绑定与发布协议。
|
|
50
|
+
|
|
51
|
+
项目至少有:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
.microi-micro-app.json
|
|
55
|
+
microi.routes.json
|
|
56
|
+
package.json
|
|
57
|
+
package-lock.json
|
|
58
|
+
tsconfig.json
|
|
59
|
+
vite.config.ts
|
|
60
|
+
index.html
|
|
61
|
+
src/
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
AppKey 稳定且只含安全字符。`microi.routes.json` 是页面事实源,删除/新增路由后由
|
|
65
|
+
发布流程同步 `sys_microiservice_page`,不要从 Vue 源码猜路由。
|
|
66
|
+
|
|
67
|
+
构建前遵守本地 OOM 保护;已有 dev server 可复用时不重复启动。独立 Vite 预览缺少
|
|
68
|
+
完整宿主 Token/OsClient/菜单/弹窗上下文,不能替代宿主验收。
|
|
69
|
+
|
|
70
|
+
## 发布
|
|
71
|
+
|
|
72
|
+
- 创建/更新元数据:`microi_create_microservice`。
|
|
73
|
+
- 同步私有源码:`microi_sync_microservice_source`。
|
|
74
|
+
- 真实编译目录优先 `microi_publish_application_directory_stream` 流式发布。
|
|
75
|
+
- 只有服务器不支持流式端点且产物很小时,才兼容 `microi_publish_microservice`。
|
|
76
|
+
- 正常发布支持最多 20,000 个文件、总计 20GB;逐文件从磁盘流入 HDFS,不生成整包 Buffer/Base64。几百 MB、1GB 级项目不得自动降级到旧 Base64 发布器。
|
|
77
|
+
- `StorageMode=db` 仅是显式的小型应急恢复模式,不是正常发布容量;当前最多 256 文件/5MB。超过该边界必须修复租户 HDFS/网关并恢复流式文件模式,不能调大数据库内联上限来承载大项目。
|
|
78
|
+
- 每次交付使用同一 `DeliveryBatchId`,并保存 `SourceManifestHash` 与 `RuntimeManifestHash`;源码同步、运行清单、页面切换和入口探测必须能关联到同一批次。
|
|
79
|
+
- 发布后用 `microi_get_application_context`、`microi_get_microservice` 回读。
|
|
80
|
+
- 回读成功还不等于页面可用:必须直接请求稳定入口、版本入口和清单内的 JS/CSS;入口 `502` 且运行时/清单存在时,优先检查 API 节点是否能通过租户 MinIO 内网端点读取公有桶对象。不要反复发布同一份产物掩盖存储读取故障。
|
|
81
|
+
- 服务器暂未部署修复且产物很小时,可把 `StorageMode=db` 与内联 `ContentBase64` 作为短期恢复手段;必须明确记录为临时方案。修复部署后重新流式发布到公有 HDFS,并恢复 `StorageMode=file`,禁止长期把大 JS/CSS 放在数据库 JSON。
|
|
82
|
+
- 子租户发布时,源码、版本资产、回读验签、页面与缓存全部绑定当前 Token 的 `OsClient`;禁止回退到主租户或宿主服务器默认租户。切换前必须由当前 API 节点通过该子租户 HDFS 配置读回每个版本文件并校验大小/SHA-256。
|
|
83
|
+
|
|
84
|
+
## 菜单与弹窗
|
|
85
|
+
|
|
86
|
+
菜单 `OpenType=MicroService` 时一次绑定 `MicroServiceId`、
|
|
87
|
+
`MicroServicePageId`、`MicroServiceRoutePath`、`MicroServiceKey`。
|
|
88
|
+
复杂弹窗用 `V8.OpenAppDialog`,业务参数放 `Data`,回调放顶层。
|
|
89
|
+
|
|
90
|
+
微服务内部禁止调用浏览器原生 `alert/confirm/prompt`。优先复用宿主 `Tips`/`V8.ConfirmTips`;需要由子应用自行承载时,使用 teleport 到 `body` 的品牌化可访问弹层,固定在当前视口正中央并高于宿主滚动内容。长列表只允许一次性加载后在前端内存搜索时,不得随着关键词重复请求服务器。
|
|
91
|
+
|
|
92
|
+
Token 只通过宿主上下文传递,不硬编码、不放 URL、不写日志。子应用回传成功/取消/
|
|
93
|
+
错误事件,宿主负责提示、关闭和刷新。
|
|
94
|
+
|
|
95
|
+
`sys_microiservice_page` 是友好路由的页面事实源,`sys_menu` 只负责导航和角色权限。
|
|
96
|
+
无需出现在导航中的按钮页/详情页应在页面元数据设置 `InternalOnly=true`,不创建伪隐藏菜单。
|
|
97
|
+
|
|
98
|
+
宿主必须提供 `--micro-app-available-width`、`--micro-app-available-height`、
|
|
99
|
+
`--micro-app-safe-area-bottom`,并用 `ResizeObserver`/`visualViewport` 同步 `host:resize`。
|
|
100
|
+
子应用根容器使用 `min-height: var(--micro-app-available-height, 100vh)`;`100vh` 只能作为脱离
|
|
101
|
+
吾码宿主独立预览时的回退值。不得直接写死 `min-height: 100vh`、`calc(100vh - 100px)` 等
|
|
102
|
+
只适配浏览器视口或某个主站布局的高度,否则嵌入 TagsView、弹窗或移动端时会被裁剪或产生双滚动。
|
|
103
|
+
|
|
104
|
+
加载/协议/运行时异常只由宿主兜底显示;子应用业务错误标记 `handled=true` 后宿主不得重复提示。
|
|
105
|
+
加载失败页至少显示 AppKey、PageKey、路由、版本、入口、HTTP 状态、发布状态、资产来源、挂载状态和安全原因码,并提供重试、返回与复制诊断。
|
|
106
|
+
|
|
107
|
+
## 验收
|
|
108
|
+
|
|
109
|
+
- 源码、构建文件、运行时、页面路由和菜单五层分别回读。
|
|
110
|
+
- 直接刷新友好路由与连续切换多个微应用不 404、白屏或实例名冲突。
|
|
111
|
+
- Dialog/Drawer 成功、取消、错误和关闭协议正确。
|
|
112
|
+
- 宿主 API 请求携带当前 Token/OsClient/菜单上下文,普通用户权限正确。
|
|
113
|
+
- 至少验证桌面和窄屏;上传、表格、滚动、弹窗底部操作不被截断。
|
|
114
|
+
- 长弹窗滚动到顶部/中部/底部后,错误提示和确认层仍位于当前视口中央;自动化监听到原生 JavaScript 对话框直接判失败。
|
|
115
|
+
- 本地构建、MCP 发布和真实浏览器验收分别说明,未执行的层不宣称通过。
|