yidaconnector 2026.6.11

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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +383 -0
  3. package/bin/yida.js +670 -0
  4. package/lib/app/form-navigation.js +58 -0
  5. package/lib/app/get-schema.js +538 -0
  6. package/lib/auth/auth.js +294 -0
  7. package/lib/auth/cdp-browser-login.js +390 -0
  8. package/lib/auth/codex-login.js +71 -0
  9. package/lib/auth/login.js +475 -0
  10. package/lib/auth/org.js +363 -0
  11. package/lib/auth/qr-login.js +1563 -0
  12. package/lib/core/chalk.js +384 -0
  13. package/lib/core/check-update.js +82 -0
  14. package/lib/core/cli-error.js +39 -0
  15. package/lib/core/command-manifest.js +106 -0
  16. package/lib/core/env-cmd.js +545 -0
  17. package/lib/core/env-manager.js +601 -0
  18. package/lib/core/env.js +287 -0
  19. package/lib/core/i18n.js +177 -0
  20. package/lib/core/locales/ar.js +805 -0
  21. package/lib/core/locales/de.js +805 -0
  22. package/lib/core/locales/en.js +1623 -0
  23. package/lib/core/locales/es.js +805 -0
  24. package/lib/core/locales/fr.js +805 -0
  25. package/lib/core/locales/hi.js +805 -0
  26. package/lib/core/locales/ja.js +1197 -0
  27. package/lib/core/locales/ko.js +807 -0
  28. package/lib/core/locales/pt.js +805 -0
  29. package/lib/core/locales/vi.js +805 -0
  30. package/lib/core/locales/zh-HK.js +1233 -0
  31. package/lib/core/locales/zh.js +1584 -0
  32. package/lib/core/query-data.js +781 -0
  33. package/lib/core/redact.js +100 -0
  34. package/lib/core/utils.js +799 -0
  35. package/lib/core/yida-client.js +117 -0
  36. package/package.json +94 -0
  37. package/project/config.json +4 -0
  38. package/project/pages/src/demo-birthday-game.oyd.jsx +832 -0
  39. package/project/pages/src/demo-chip-insight.oyd.jsx +983 -0
  40. package/project/pages/src/demo-compat-smoke.oyd.jsx +58 -0
  41. package/project/pages/src/demo-crm-batch-entry.oyd.jsx +805 -0
  42. package/project/pages/src/demo-crm-dashboard.oyd.jsx +677 -0
  43. package/project/pages/src/demo-future-vision-2026.oyd.jsx +1102 -0
  44. package/project/pages/src/demo-ppt.oyd.jsx +1192 -0
  45. package/project/pages/src/demo-salary-calculator.oyd.jsx +904 -0
  46. package/project/pages/src/yidaconnector-knowledge-doc.oyd.jsx +1714 -0
  47. package/project/prd/demo-birthday-game.md +39 -0
  48. package/project/prd/demo-crm.md +463 -0
  49. package/project/prd/demo-dingtalk-ai-solution-center.md +425 -0
  50. package/project/prd/demo-future-vision-2026.md +78 -0
  51. package/project/prd/demo-salary-calculator.md +101 -0
  52. package/scripts/build-skills-package.js +406 -0
  53. package/scripts/check-syntax.js +59 -0
  54. package/scripts/demo-dws.sh +106 -0
  55. package/scripts/e2e-real/cleanup.js +67 -0
  56. package/scripts/e2e-real/fixtures/form-fields.json +18 -0
  57. package/scripts/e2e-real/full-runner.js +1566 -0
  58. package/scripts/e2e-real/runner.js +293 -0
  59. package/scripts/e2e-real/skill-coverage.js +115 -0
  60. package/scripts/generate-command-docs.js +109 -0
  61. package/scripts/nightly-smoke.js +134 -0
  62. package/scripts/postinstall.js +545 -0
  63. package/scripts/solution-center-runner.js +368 -0
  64. package/scripts/validate-ci.sh +50 -0
  65. package/scripts/validate-command-manifest.js +119 -0
  66. package/scripts/validate-package-size.js +78 -0
  67. package/scripts/validate-skills.js +247 -0
  68. package/scripts/validate-structure.js +66 -0
  69. package/yida-skills/SKILL.md +163 -0
  70. package/yida-skills/references/yida-api.md +1309 -0
  71. package/yida-skills/skills/large-file-write/SKILL.md +91 -0
  72. package/yida-skills/skills/large-file-write/references/write-patterns.md +149 -0
  73. package/yida-skills/skills/large-file-write/scripts/write.js +157 -0
  74. package/yida-skills/skills/yida-data-management/SKILL.md +252 -0
  75. package/yida-skills/skills/yida-data-management/references/api-matrix.md +49 -0
  76. package/yida-skills/skills/yida-data-management/references/data-format-guide.md +159 -0
  77. package/yida-skills/skills/yida-data-management/references/verified-endpoints.md +62 -0
  78. package/yida-skills/skills/yida-login/SKILL.md +159 -0
  79. package/yida-skills/skills/yida-logout/SKILL.md +67 -0
@@ -0,0 +1,1309 @@
1
+ # 宜搭跨应用 JS API
2
+
3
+ 调用方式:`this.utils.yida.<函数名>(params)`
4
+
5
+ 所有接口返回 Promise,统一使用 `.then()` 和 `.catch()` 处理结果和异常。
6
+
7
+ ---
8
+
9
+ ## 目录
10
+
11
+ - [表单数作类 API](#表单操作类-api)
12
+ - [saveFormData](#saveformdata) - 新建表单实例
13
+ - [updateFormData](#updateformdata) - 更新表单组件值
14
+ - [searchFormDataIds](#searchformdataids) - 搜索表单实例 ID 列表
15
+ - [getFormComponentDefinationList](#getformcomponentdefinationlist) - 获取表单定义
16
+ - [deleteFormData](#deleteformdata) - 删除表单实例
17
+ - [getFormDataById](#getformdatabyid) - 查询表单实例详情
18
+ - [searchFormDatas](#searchformdatas) - 搜索表单实例详情列表
19
+ - [流程操作类 API](#流程操作类-api)
20
+ - [startProcessInstance](#startprocessinstance) - 流程发起
21
+ - [updateProcessInstance](#updateprocessinstance) - 流程实例更新
22
+ - [deleteProcessInstance](#deleteprocessinstance) - 删除流程实例
23
+ - [getProcessInstances](#getprocessinstances) - 获取流程实例详情列表
24
+ - [getProcessInstanceIds](#getprocessinstanceids) - 搜索流程实例 ID 列表
25
+ - [getProcessInstanceById](#getprocessinstancebyid) - 获取流程实例详情
26
+ - [表单设计类 API](#表单设计类-api)
27
+ - [saveFormSchemaInfo](#saveformschemainfo) - 创建空白表单
28
+ - [getFormSchema](#getformschema) - 获取表单 Schema
29
+ - [saveFormSchema](#saveformschema) - 保存表单 Schema
30
+ - [updateFormConfig](#updateformconfig) - 更新表单配置
31
+ - [工具类 API](#工具类-api)
32
+ - [dialog](#dialog) - 对话框
33
+ - [formatter](#formatter) - 格式化工具
34
+ - [getDateTimeRange](#getdatetimerange) - 获取日期时间范围
35
+ - [getLocale](#getlocale) - 获取语言环境
36
+ - [getLoginUserId](#getloginuserid) - 获取登录用户 ID
37
+ - [getLoginUserName](#getloginusername) - 获取登录用户名称
38
+ - [isMobile](#ismobile) - 判断是否移动端
39
+ - [isSubmissionPage](#issubmissionpage) - 判断是否提交页面
40
+ - [isViewPage](#isviewpage) - 判断是否查看页面
41
+ - [loadScript](#loadscript) - 动态加载脚本
42
+ - [loadStyleSheet](#loadstylesheet) - 动态加载样式表
43
+ - [openPage](#openpage) - 打开新页面
44
+ - [router.push](#router.push) - 页面路由跳转工具
45
+ - [previewImage](#previewimage) - 图片预览
46
+ - [toast](#toast) - 信息提醒
47
+
48
+ ---
49
+
50
+ ## 表单操作类 API
51
+
52
+ ### saveFormData
53
+
54
+ **描述**:新建表单实例
55
+
56
+ **参数**:
57
+
58
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
59
+ | :--- | :--- | :--- | :--- | :--- |
60
+ | formUuid | String | 是 | 表单ID | `FORM-XXX` |
61
+ | appType | String | 是 | 应用 ID | `APP_XXX` |
62
+ | formDataJson | String | 是 | 表单数据(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
63
+
64
+ **formDataJson 示例**:
65
+
66
+ > 日期组件写入值必须是 13 位毫秒时间戳,例如 `1516636800000`;不要传 `"2024-01-30"` 这类日期字符串。日期区间组件传毫秒时间戳数组。
67
+
68
+ ```json
69
+ {
70
+ "textField_jcr0069m": "danhang",
71
+ "textareaField_jcr0069n": "duohang",
72
+ "numberField_jcr0069o": 1,
73
+ "radioField_jcr0069p": "选项一",
74
+ "selectField_jcr0069q": "选项一",
75
+ "checkboxField_jcr0069r": [
76
+ "选项二",
77
+ "选项三"
78
+ ],
79
+ "multiSelectField_jcr0069s": [
80
+ "选项二",
81
+ "选项三"
82
+ ],
83
+ "dateField_jcr0069t": 1516636800000,
84
+ "cascadeDate_jcr0069u": [
85
+ "1514736000000",
86
+ "1517328000000"
87
+ ],
88
+ "employeeField_jcr0069x": [
89
+ "xxxxx"
90
+ ],
91
+ "citySelectField_jcr0069y": [
92
+ "110000",
93
+ "110100",
94
+ "110101"
95
+ ],
96
+ "departmentField_jcr0069z": 1123456,
97
+ "cascadeSelectField_jcr006a0": [
98
+ "part",
99
+ "part_b"
100
+ ],
101
+ "attachmentField_jna1lvyb": [
102
+ {
103
+ "downloadUrl": "https://www.aliwork.com/fileHandle?appType=default_tianshu_app&fileName=edd07ca9-1d2e-44b5-98fe-c1e16202f90d.txt&instId=&type=download",
104
+ "name": "test.txt",
105
+ "previewUrl": "https://www.aliwork.com/inst/preview?appType=default_tianshu_app&fileName=test.txt&fileSize=4&downloadUrl=edd07ca9-1d2e-44b5-98fe-c1e16202f90d.txt",
106
+ "url": "https://www.aliwork.com/fileHandle?appType=default_tianshu_app&fileName=edd07ca9-1d2e-44b5-98fe-c1e16202f90d.txt&instId=&type=download",
107
+ "ext": "txt"
108
+ }
109
+ ],
110
+ "tableField_jcr006a1": [
111
+ {
112
+ "cascadeDate_jcr006aa": [
113
+ "1514736000000",
114
+ "1517328000000"
115
+ ],
116
+ "cascadeSelectField_jcr006ae": [
117
+ "product",
118
+ "product_a"
119
+ ],
120
+ "checkboxField_jcr006a7": [
121
+ "选项一",
122
+ "选项二",
123
+ "选项三"
124
+ ],
125
+ "citySelectField_jcr006ac": [
126
+ "120000",
127
+ "120100",
128
+ "120102"
129
+ ],
130
+ "dateField_jcr006a9": 1517328000000,
131
+ "departmentField_jcr006ad": ["1123456"],
132
+ "employeeField_jcr006ab": [
133
+ "yyyyy",
134
+ "xxxxx"
135
+ ],
136
+ "multiSelectField_jcr006a8": [
137
+ "选项一",
138
+ "选项二",
139
+ "选项三"
140
+ ],
141
+ "numberField_jcr006a4": 2,
142
+ "radioField_jcr006a5": "选项二",
143
+ "selectField_jcr006a6": "选项三",
144
+ "textField_jcr006a2": "子表单下单行",
145
+ "textareaField_jcr006a3": "子表单下多行"
146
+ }
147
+ ]
148
+ }
149
+ ```
150
+
151
+ **返回值**:
152
+
153
+ | 字段 | 类型 | 描述 |
154
+ | :--- | :--- | :--- |
155
+ | success | Boolean | 请求是否成功 |
156
+ | result | String | 实例ID |
157
+ | errorMsg | String | 错误信息 |
158
+ | errorCode | String | 错误码 |
159
+
160
+ **返回值示例**:
161
+
162
+ ```json
163
+ {
164
+ "result": "FINST-XXX",
165
+ "success": true
166
+ }
167
+ ```
168
+
169
+ **请求示例**:
170
+
171
+ ```javascript
172
+ this.utils.yida.saveFormData({
173
+ formUuid: 'FORM-XXX',
174
+ appType: pageConfig.appType,
175
+ formDataJson: JSON.stringify({
176
+ textField_m1g4dcpy: '单行文本',
177
+ textareaField_m1g4dcpz: '多行文本',
178
+ }),
179
+ }).then((res) => {
180
+ console.log('新建结果', res);
181
+ }).catch(({ message }) => {
182
+ this.utils.toast({ title: message, type: 'error' });
183
+ });
184
+ ```
185
+
186
+ ---
187
+
188
+ ### updateFormData
189
+
190
+ **描述**:更新表单中指定组件值
191
+
192
+ **后端 API 路径**:`POST /dingtalk/web/{appType}/v1/form/updateFormData.json`
193
+
194
+ > ⚠️ **注意**:请勿使用错误路径 `/query/form/updateFormData.json`,该路径会返回错误。
195
+
196
+ **参数**:
197
+
198
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
199
+ | :--- | :--- | :--- | :--- | :--- |
200
+ | formInstId | String | 是 | 表单实例ID | `FINST-xxx` |
201
+ | updateFormDataJson | String | 是 | 需要更新的表单数据(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
202
+ | useLatestVersion | String | 否 | 是否使用最新版本 | `y` |
203
+
204
+ **请求示例**:
205
+
206
+ ```javascript
207
+ this.utils.yida.updateFormData({
208
+ formInstId: 'FINST-xxx',
209
+ updateFormDataJson: JSON.stringify({
210
+ textField_m1g4dcpy: '单行文本',
211
+ textareaField_m1g4dcpz: '多行文本',
212
+ }),
213
+ useLatestVersion: 'y',
214
+ }).then((res) => {
215
+ console.log('更新成功');
216
+ }).catch(({ message }) => {
217
+ this.utils.toast({ title: message, type: 'error' });
218
+ });
219
+ ```
220
+
221
+ ---
222
+
223
+ ### searchFormDataIds
224
+
225
+ **描述**:根据条件搜索表单实例 ID 列表
226
+
227
+ **参数**:
228
+
229
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
230
+ | :--- | :--- | :--- | :--- | :--- |
231
+ | formUuid | String | 是 | 表单ID | `FORM-XXX` |
232
+ | currentPage | Number | 否 | 当前页,默认 1 | `1` |
233
+ | pageSize | Number | 否 | 每页记录数,默认 10,**最大 100,超过 100 会报错** | `10` |
234
+ | searchFieldJson | String | 否 | 根据表单内组件值查询(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
235
+
236
+ **请求示例**:
237
+
238
+ ```javascript
239
+ this.utils.yida.searchFormDataIds({
240
+ formUuid: 'FORM-XXX',
241
+ currentPage: 1,
242
+ pageSize: 10,
243
+ searchFieldJson: JSON.stringify({
244
+ textField_m1g4dcpy: '单行文本',
245
+ }),
246
+ }).then((res) => {
247
+ console.log('请求结果', res);
248
+ }).catch(({ message }) => {
249
+ this.utils.toast({ title: message, type: 'error' });
250
+ });
251
+ ```
252
+
253
+ ---
254
+
255
+ ### getFormComponentDefinationList
256
+
257
+ **描述**:获取表单定义
258
+
259
+ **参数**:
260
+
261
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
262
+ | :--- | :--- | :--- | :--- | :--- |
263
+ | formUuid | String | 是 | 表单ID | `FORM-XXX` |
264
+ | version | String | 否 | 版本号 | `""` |
265
+
266
+ **请求示例**:
267
+
268
+ ```javascript
269
+ this.utils.yida.getFormComponentDefinationList({
270
+ formUuid: 'FORM-XXX',
271
+ version: '',
272
+ }).then((res) => {
273
+ console.log('请求结果', res);
274
+ }).catch(({ message }) => {
275
+ this.utils.toast({ title: message, type: 'error' });
276
+ });
277
+ ```
278
+
279
+ ---
280
+
281
+ ### deleteFormData
282
+
283
+ **描述**:删除表单实例
284
+
285
+ **参数**:
286
+
287
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
288
+ | :--- | :--- | :--- | :--- | :--- |
289
+ | formUuid | String | 是 | 表单ID | `FORM-XXX` |
290
+
291
+ **请求示例**:
292
+
293
+ ```javascript
294
+ this.utils.yida.deleteFormData({
295
+ formUuid: 'FORM-XXX',
296
+ }).then((res) => {
297
+ console.log('请求结果', res);
298
+ }).catch(({ message }) => {
299
+ this.utils.toast({ title: message, type: 'error' });
300
+ });
301
+ ```
302
+
303
+ ---
304
+
305
+ ### getFormDataById
306
+
307
+ **描述**:根据表单实例 ID 查询表单实例详情
308
+
309
+ **参数**:
310
+
311
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
312
+ | :--- | :--- | :--- | :--- | :--- |
313
+ | formInstId | String | 是 | 表单实例ID | `FINST-xxxx` |
314
+
315
+ **请求示例**:
316
+
317
+ ```javascript
318
+ this.utils.yida.getFormDataById({
319
+ formInstId: 'FINST-xxxx',
320
+ }).then((res) => {
321
+ console.log('请求结果', res);
322
+ }).catch(({ message }) => {
323
+ this.utils.toast({ title: message, type: 'error' });
324
+ });
325
+ ```
326
+
327
+ ---
328
+
329
+ ### searchFormDatas
330
+
331
+ **描述**:根据条件搜索表单实例详情列表
332
+
333
+ **参数**:
334
+
335
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
336
+ | :--- | :--- | :--- | :--- | :--- |
337
+ | formUuid | String | 是 | 表单ID | `FORM-XXX` |
338
+ | searchFieldJson | String | 否 | 根据表单内组件值查询(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
339
+ | currentPage | Number | 否 | 当前页,默认 1 | `1` |
340
+ | pageSize | Number | 否 | 每页记录数,默认 10,**最大 100,超过 100 会报错** | `10` |
341
+ | originatorId | String | 否 | 根据数据提交人工号查询 | `'2134'` |
342
+ | createFrom | String | 否 | 创建时间范围起始,格式 yyyy-MM-dd | `'2024-01-01'` |
343
+ | createTo | String | 否 | 创建时间范围结束,格式 yyyy-MM-dd | `'2024-02-01'` |
344
+ | modifiedFrom | String | 否 | 修改时间范围起始,格式 yyyy-MM-dd | `'2024-01-01'` |
345
+ | modifiedTo | String | 否 | 修改时间范围结束,格式 yyyy-MM-dd | `'2024-02-01'` |
346
+ | dynamicOrder | String | 否 | 指定排序字段 | `'{"numberField_1ac":"+"}'` |
347
+
348
+ **searchFieldJson 示例**:
349
+
350
+ > 日期查询也使用毫秒时间戳。`DateField` 区间查询传 `[开始毫秒时间戳, 结束毫秒时间戳]`。
351
+
352
+ ```json
353
+ {
354
+ "textField_jcr0069m": "danhang",
355
+ "textareaField_jcr0069n": "duohang",
356
+ "numberField_jcr0069o": ["1", "10"],
357
+ "radioField_jcr0069p": "选项一",
358
+ "selectField_jcr0069q": "选项一",
359
+ "checkboxField_jcr0069r": ["选项二"],
360
+ "multiSelectField_jcr0069s": ["选项二", "选项三"],
361
+ "dateField_jcr0069t": [1514736000000, 1517414399000],
362
+ "cascadeDate_jcr0069u": [
363
+ [1514736000000, 1517414399000],
364
+ [1514736000000, 1517414399000]
365
+ ],
366
+ "employeeField_jcr0069x": ["xxxxx"],
367
+ "citySelectField_jcr0069y": ["110000", "110100", "110101"],
368
+ "departmentField_jcr0069z": ["1123456"],
369
+ "cascadeSelectField_jcr006a0": ["part", "part_b"],
370
+ "tableField_jcr006a1": "子表单数据"
371
+ }
372
+ ```
373
+
374
+ **返回值**:
375
+
376
+ | 字段 | 类型 | 描述 |
377
+ | :--- | :--- | :--- |
378
+ | currentPage | Number | 当前页 |
379
+ | totalCount | Number | 符合条件的实例总数 |
380
+ | data | Array | 实例详情列表 |
381
+
382
+ > ⚠️ **已知问题:返回结构不一致**
383
+ >
384
+ > 宜搭 API 在不同场景下会返回两种结构,**必须使用兼容写法**读取数据:
385
+ > - **直接结构**(常见):`{ success, data: [...], totalCount, currentPage }`
386
+ > - **嵌套结构**(部分场景):`{ success, content: { data: [...], totalCount, currentPage } }`
387
+ >
388
+ > 推荐的兼容写法:
389
+ > ```javascript
390
+ > var data = (res && res.data) || (res && res.content && res.content.data) || [];
391
+ > var total = (res && res.totalCount) || (res && res.content && res.content.totalCount) || 0;
392
+ > ```
393
+ >
394
+ > 使用 `yidaconnector data query form` CLI 命令时,工具已自动归一化为直接结构,无需手动兼容。
395
+
396
+ > ⚠️ **pageSize 上限**:`pageSize` 最大值为 **100**,超过 100 会导致宜搭 API 返回 HTTP 500 错误(错误信息为"参数校验失败pageSize")。推荐使用 `10`~`100` 之间的值。
397
+
398
+ > 📌 **appType 参数说明**:
399
+ > - **页面内部调用**(即在宜搭自定义页面的 JS 代码中调用 `this.utils.yida.searchFormDatas`):**不需要传 `appType`**,SDK 会自动从当前页面上下文中获取。
400
+ > - **外部 HTTP 直接调用**(如通过 `yidaconnector data query form` CLI 或服务端脚本):**必须传 `appType`**,即应用的唯一标识(可在宜搭应用 URL 中找到,格式如 `APP_XXXXXXXX`)。
401
+
402
+ **请求示例**:
403
+
404
+ ```javascript
405
+ this.utils.yida.searchFormDatas({
406
+ formUuid: 'FORM-XXX',
407
+ searchFieldJson: '',
408
+ currentPage: 1,
409
+ pageSize: 10,
410
+ originatorId: '',
411
+ createFrom: '2024-01-01',
412
+ createTo: '2024-02-01',
413
+ modifiedFrom: '2024-01-01',
414
+ modifiedTo: '2024-02-01',
415
+ dynamicOrder: '',
416
+ }).then((res) => {
417
+ // 兼容两种返回结构
418
+ var data = (res && res.data) || (res && res.content && res.content.data) || [];
419
+ var total = (res && res.totalCount) || (res && res.content && res.content.totalCount) || 0;
420
+ console.log('数据列表', data, '总数', total);
421
+ }).catch(({ message }) => {
422
+ this.utils.toast({ title: message, type: 'error' });
423
+ });
424
+ ```
425
+
426
+ **返回值示例(data 字段)**:
427
+
428
+ ```json
429
+ {
430
+ "gmtModified": "2018-01-24 11:22:01",
431
+ "formUuid": "FORM-XXX",
432
+ "formInstId": "FINST-xxx",
433
+ "formData": {
434
+ "numberField_jcr0069o": 1,
435
+ "multiSelectField_jcr0069s": ["选项三", "选项二"],
436
+ "textareaField_jcr0069n": "duohang",
437
+ "employeeField_jcr0069x": ["xxxx"],
438
+ "departmentField_jcr0069z": "xxxx",
439
+ "cascadeDate_jcr0069u": ["1514736000000", "1517328000000"],
440
+ "cascadeSelectField_jcr006a0": ["part", "part_b"],
441
+ "tableField_jcr006a1": [
442
+ {
443
+ "departmentField_jcr006ad": "xxxx",
444
+ "cascadeDate_jcr006aa": ["1514736000000", "1517328000000"],
445
+ "selectField_jcr006a6": "选项三",
446
+ "citySelectField_jcr006ac": ["天津", "天津市", "河东区"],
447
+ "radioField_jcr006a5": "选项二",
448
+ "employeeField_jcr006ab": ["xxxxxx", "yyyyyy"],
449
+ "dateField_jcr006a9": 1517328000000,
450
+ "textField_jcr006a2": "子表单下单行",
451
+ "textareaField_jcr006a3": "子表单下多行",
452
+ "cascadeSelectField_jcr006ae": ["product", "product_a"],
453
+ "numberField_jcr006a4": 2,
454
+ "checkboxField_jcr006a7": ["选项一", "选项三", "选项二"],
455
+ "multiSelectField_jcr006a8": ["选项一", "选项三", "选项二"]
456
+ }
457
+ ],
458
+ "selectField_jcr0069q": "选项一",
459
+ "citySelectField_jcr0069y": ["北京", "北京市", "东城区"],
460
+ "checkboxField_jcr0069r": ["选项三", "选项二"],
461
+ "textField_jcr0069m": "danhang",
462
+ "radioField_jcr0069p": "选项一",
463
+ "dateField_jcr0069t": 1516636800000
464
+ },
465
+ "originator": {
466
+ "name": {
467
+ "pureEn_US": "userEnglishName",
468
+ "en_US": "userEnglishName",
469
+ "zh_CN": "userName",
470
+ "type": "i18n"
471
+ },
472
+ "userId": "xxxx"
473
+ }
474
+ }
475
+ ```
476
+
477
+ ---
478
+
479
+ ## 流程操作类 API
480
+
481
+ ### startProcessInstance
482
+
483
+ **描述**:流程发起
484
+
485
+ **参数**:
486
+
487
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
488
+ | :--- | :--- | :--- | :--- | :--- |
489
+ | formUuid | String | 是 | 表单ID | `FORM-XXX` |
490
+ | processCode | String | 是 | 流程编码 | `TPROC--xxx` |
491
+ | deptId | String | 否 | 部门ID | `''` |
492
+ | formDataJson | String | 是 | 表单数据(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
493
+
494
+ **请求示例**:
495
+
496
+ ```javascript
497
+ this.utils.yida.startProcessInstance({
498
+ formUuid: 'FORM-XXX',
499
+ processCode: 'TPROC--xxx',
500
+ deptId: '',
501
+ formDataJson: JSON.stringify({
502
+ textField_xxx: '单行文本',
503
+ textareaField_xxx: '多行文本',
504
+ }),
505
+ }).then((res) => {
506
+ console.log('请求结果', res);
507
+ }).catch(({ message }) => {
508
+ this.utils.toast({ title: message, type: 'error' });
509
+ });
510
+ ```
511
+
512
+ ---
513
+
514
+ ### updateProcessInstance
515
+
516
+ **描述**:流程实例更新
517
+
518
+ **参数**:
519
+
520
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
521
+ | :--- | :--- | :--- | :--- | :--- |
522
+ | processInstanceId | String | 是 | 流程实例ID | `f30233fb-xxx-9ee530` |
523
+ | updateFormDataJson | String | 是 | 需要更新的表单数据(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
524
+
525
+ **请求示例**:
526
+
527
+ ```javascript
528
+ this.utils.yida.updateProcessInstance({
529
+ processInstanceId: 'f30233fb-xxx-9ee530',
530
+ updateFormDataJson: JSON.stringify({
531
+ textField_xxx: '单行文本',
532
+ textareaField_xxx: '多行文本',
533
+ }),
534
+ }).then((res) => {
535
+ console.log('请求结果', res);
536
+ }).catch(({ message }) => {
537
+ this.utils.toast({ title: message, type: 'error' });
538
+ });
539
+ ```
540
+
541
+ ---
542
+
543
+ ### deleteProcessInstance
544
+
545
+ **描述**:删除流程实例
546
+
547
+ **参数**:
548
+
549
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
550
+ | :--- | :--- | :--- | :--- | :--- |
551
+ | processInstanceId | String | 是 | 流程实例ID | `f30233fb-xxx-9ee530` |
552
+
553
+ **请求示例**:
554
+
555
+ ```javascript
556
+ this.utils.yida.deleteProcessInstance({
557
+ processInstanceId: 'f30233fb-xxx-9ee530',
558
+ }).then((res) => {
559
+ console.log('请求结果', res);
560
+ }).catch(({ message }) => {
561
+ this.utils.toast({ title: message, type: 'error' });
562
+ });
563
+ ```
564
+
565
+ ---
566
+
567
+ ### getProcessInstances
568
+
569
+ **描述**:根据搜索条件获取流程实例详情列表
570
+
571
+ **参数**:
572
+
573
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
574
+ | :--- | :--- | :--- | :--- | :--- |
575
+ | formUuid | String | 否 | 表单ID | `FORM-XXX` |
576
+ | taskId | String | 否 | 任务ID | `'2199132092'` |
577
+ | instanceStatus | String | 否 | 实例状态 | `'RUNNING'` |
578
+ | approvedResult | String | 否 | 流程审批结果 | `'agree'` |
579
+ | currentPage | Number | 否 | 当前页,默认 1 | `1` |
580
+ | pageSize | Number | 否 | 每页记录数,默认 10,**最大 100,超过 100 会报错** | `10` |
581
+ | originatorId | String | 否 | 流程发起人工号 | `'2134'` |
582
+ | createFrom | String | 否 | 创建时间范围起始,格式 yyyy-MM-dd | `'2024-01-01'` |
583
+ | createTo | String | 否 | 创建时间范围结束,格式 yyyy-MM-dd | `'2024-02-01'` |
584
+ | modifiedFrom | String | 否 | 修改时间范围起始,格式 yyyy-MM-dd | `'2024-01-01'` |
585
+ | modifiedTo | String | 否 | 修改时间范围结束,格式 yyyy-MM-dd | `'2024-02-01'` |
586
+ | searchFieldJson | String | 否 | 根据表单内组件值查询(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
587
+
588
+ **请求示例**:
589
+
590
+ ```javascript
591
+ this.utils.yida.getProcessInstances({
592
+ formUuid: 'FORM-XXX',
593
+ taskId: '2199132092',
594
+ instanceStatus: 'RUNNING',
595
+ approvedResult: 'agree',
596
+ currentPage: 1,
597
+ pageSize: 10,
598
+ originatorId: '2134',
599
+ createFrom: '2024-01-01',
600
+ createTo: '2024-02-01',
601
+ modifiedFrom: '2024-01-01',
602
+ modifiedTo: '2024-02-01',
603
+ searchFieldJson: JSON.stringify({
604
+ textField_xxx: '单行文本',
605
+ }),
606
+ }).then((res) => {
607
+ console.log('请求结果', res);
608
+ }).catch(({ message }) => {
609
+ this.utils.toast({ title: message, type: 'error' });
610
+ });
611
+ ```
612
+
613
+ ---
614
+
615
+ ### getProcessInstanceIds
616
+
617
+ **描述**:根据条件搜索流程实例 ID 列表
618
+
619
+ **参数**:
620
+
621
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
622
+ | :--- | :--- | :--- | :--- | :--- |
623
+ | formUuid | String | 否 | 表单ID | `FORM-XXX` |
624
+ | taskId | String | 否 | 任务ID | `'2199132092'` |
625
+ | instanceStatus | String | 否 | 实例状态 | `'RUNNING'` |
626
+ | approvedResult | String | 否 | 流程审批结果 | `'agree'` |
627
+ | currentPage | Number | 否 | 当前页,默认 1 | `1` |
628
+ | pageSize | Number | 否 | 每页记录数,默认 10,**最大 100,超过 100 会报错** | `10` |
629
+ | originatorId | String | 否 | 流程发起人工号 | `'2134'` |
630
+ | createFrom | String | 否 | 创建时间范围起始,格式 yyyy-MM-dd | `'2024-01-01'` |
631
+ | createTo | String | 否 | 创建时间范围结束,格式 yyyy-MM-dd | `'2024-02-01'` |
632
+ | modifiedFrom | String | 否 | 修改时间范围起始,格式 yyyy-MM-dd | `'2024-01-01'` |
633
+ | modifiedTo | String | 否 | 修改时间范围结束,格式 yyyy-MM-dd | `'2024-02-01'` |
634
+ | searchFieldJson | String | 否 | 根据表单内组件值查询(JSON字符串) | `JSON.stringify({ textField_xxx: '值' })` |
635
+
636
+ > ⚠️ **注意**:`pageSize` 最大值为 **100**,禁止设置超过 100 的值,否则接口会报错。
637
+
638
+ **请求示例**:
639
+
640
+ ```javascript
641
+ this.utils.yida.getProcessInstanceIds({
642
+ formUuid: 'FORM-XXX',
643
+ taskId: '2199132092',
644
+ instanceStatus: 'RUNNING',
645
+ approvedResult: 'agree',
646
+ currentPage: 1,
647
+ pageSize: 10,
648
+ originatorId: '2134',
649
+ createFrom: '2024-01-01',
650
+ createTo: '2024-02-01',
651
+ modifiedFrom: '2024-01-01',
652
+ modifiedTo: '2024-02-01',
653
+ searchFieldJson: JSON.stringify({
654
+ textField_xxx: '单行文本',
655
+ }),
656
+ }).then((res) => {
657
+ console.log('请求结果', res);
658
+ }).catch(({ message }) => {
659
+ this.utils.toast({ title: message, type: 'error' });
660
+ });
661
+ ```
662
+
663
+ ---
664
+
665
+ ### getProcessInstanceById
666
+
667
+ **描述**:根据实例 ID 获取流程实例详情
668
+
669
+ **参数**:
670
+
671
+ | 参数名 | 类型 | 是否必填 | 描述 | 示例 |
672
+ | :--- | :--- | :--- | :--- | :--- |
673
+ | processInstanceId | String | 是 | 流程实例ID | `f30233fb-xxx-530` |
674
+
675
+ **请求示例**:
676
+
677
+ ```javascript
678
+ this.utils.yida.getProcessInstanceById({
679
+ processInstanceId: 'f30233fb-xxx-530',
680
+ }).then((res) => {
681
+ console.log('请求结果', res);
682
+ }).catch(({ message }) => {
683
+ this.utils.toast({ title: message, type: 'error' });
684
+ });
685
+ ```
686
+
687
+
688
+ ---
689
+
690
+ ## 表单设计类 API
691
+
692
+ ### saveFormSchemaInfo(创建空白表单,create 模式)
693
+
694
+ - **地址**:`POST /dingtalk/web/{appType}/query/formdesign/saveFormSchemaInfo.json`
695
+ - **Content-Type**:`application/x-www-form-urlencoded`
696
+ - **参数**:
697
+
698
+ | 参数 | 类型 | 必填 | 说明 |
699
+ | --- | --- | --- | --- |
700
+ | `_csrf_token` | String | 是 | CSRF Token(由 yida-login 获取) |
701
+ | `formType` | String | 是 | 表单类型,固定 `receipt` |
702
+ | `title` | String (JSON) | 是 | 表单名称,i18n 格式:`{"zh_CN":"名称","en_US":"名称","type":"i18n"}` |
703
+
704
+ - **返回值**:
705
+
706
+ ```json
707
+ {
708
+ "content": { "formUuid": "FORM-XXX" },
709
+ "success": true
710
+ }
711
+ ```
712
+
713
+ ### getFormSchema(获取表单 Schema,update 模式)
714
+
715
+ - **地址**:`GET /alibaba/web/{appType}/_view/query/formdesign/getFormSchema.json`
716
+ - **参数**:
717
+
718
+ | 参数 | 类型 | 必填 | 说明 |
719
+ | --- | --- | --- | --- |
720
+ | `formUuid` | String | 是 | 表单 UUID |
721
+ | `schemaVersion` | String | 否 | Schema 版本,默认 `V5` |
722
+
723
+ - **返回值**:完整的表单 Schema JSON,包含 `pages` 数组,结构与 `saveFormSchema` 保存的格式一致。各字段的 `fieldId`(如 `textField_xxxxxxxx`)可从 Schema 中读取。
724
+
725
+ ### saveFormSchema(保存表单 Schema,两种模式共用)
726
+
727
+ - **地址**:`POST /dingtalk/web/{appType}/_view/query/formdesign/saveFormSchema.json`
728
+ - **Content-Type**:`application/x-www-form-urlencoded`
729
+ - **参数**:
730
+
731
+ | 参数 | 类型 | 必填 | 说明 |
732
+ | --- | --- | --- | --- |
733
+ | `_csrf_token` | String | 是 | CSRF Token(由 yida-login 获取) |
734
+ | `formUuid` | String | 是 | 表单 UUID |
735
+ | `content` | String (JSON) | 是 | 表单 Schema 内容(`schemaType: "superform"`) |
736
+ | `schemaVersion` | String | 是 | 固定 `V5` |
737
+ | `importSchema` | String | 是 | 固定 `"true"` |
738
+
739
+ - **返回值**:
740
+
741
+ ```json
742
+ { "success": true }
743
+ ```
744
+
745
+ ### updateFormConfig(更新表单配置)
746
+
747
+ - **地址**:`POST /dingtalk/web/{appType}/query/formdesign/updateFormConfig.json`
748
+ - **Content-Type**:`application/x-www-form-urlencoded`
749
+ - **参数**:
750
+
751
+ | 参数 | 类型 | 必填 | 说明 |
752
+ | --- | --- | --- | --- |
753
+ | `_csrf_token` | String | 是 | CSRF Token(由 yida-login 获取) |
754
+ | `formUuid` | String | 是 | 表单 UUID |
755
+ | `version` | Number | 是 | 版本号(新创建的表单从 1 开始) |
756
+ | `configType` | String | 是 | 固定 `MINI_RESOURCE` |
757
+ | `value` | Number | 是 | 固定 `0`(表单页面配置值) |
758
+
759
+ - **返回值**:
760
+
761
+ ```json
762
+ {
763
+ "success": true,
764
+ "traceId": null,
765
+ "throwable": null,
766
+ "errorCode": null,
767
+ "content": null,
768
+ "errorMsg": null
769
+ }
770
+ ```
771
+
772
+
773
+ ## 工具类 API
774
+
775
+ 宜搭提供了很多内置的工具类函数,帮助用户更好地实现一些常用功能。
776
+
777
+ ### dialog
778
+
779
+ **描述**:弹出对话框,用户需要手动关闭。底层采用 Fusion 组件实现,支持配置所有 Dialog 组件属性。
780
+
781
+ **参数**:
782
+
783
+ | 参数名 | 类型 | 默认值 | 说明 |
784
+ | :--- | :--- | :--- | :--- |
785
+ | type | String | `'alert'` | 对话框类型:`alert` / `confirm` / `show` |
786
+ | title | String | - | 对话框标题 |
787
+ | content | String \| ReactNode | - | 内容,可传入 HTML/JSX 实现复杂布局 |
788
+ | hasMask | Boolean | `true` | 是否有遮罩 |
789
+ | footer | Boolean | `true` | 是否有底部操作按钮 |
790
+ | footerAlign | String | `'right'` | 底部操作对齐方向:`left` / `center` / `right` |
791
+ | footerActions | Array | - | 底部操作类型和顺序,如 `['cancel', 'ok']` / `['ok']` / `['cancel']` |
792
+ | onOk | Function | - | 点击确定的回调函数 |
793
+ | onCancel | Function | - | 点击取消的回调函数 |
794
+
795
+ **请求示例**:
796
+
797
+ ```javascript
798
+ export function popDialog() {
799
+ this.utils.dialog({
800
+ type: 'confirm',
801
+ title: '确认操作',
802
+ content: '确定要执行此操作吗?',
803
+ onOk: () => {
804
+ console.log('点击了确定');
805
+ },
806
+ onCancel: () => {
807
+ console.log('点击了取消');
808
+ },
809
+ });
810
+ }
811
+
812
+ // 支持手动关闭对话框
813
+ export function closeDialog() {
814
+ const dialog = this.utils.dialog({
815
+ title: '处理中',
816
+ content: '请稍候...',
817
+ });
818
+
819
+ // 3秒后自动关闭
820
+ setTimeout(() => dialog.hide(), 3000);
821
+ }
822
+ ```
823
+
824
+ ---
825
+
826
+ ### formatter
827
+
828
+ **描述**:常用的格式化函数,支持日期、金额、手机号、银行卡号等格式转换。
829
+
830
+ **参数**:
831
+
832
+ | 参数名 | 类型 | 是否必填 | 说明 |
833
+ | :--- | :--- | :--- | :--- |
834
+ | type | String | 是 | 格式化类型:`date` / `money` / `cnmobile` / `card` |
835
+ | value | String \| Number \| Date | 是 | 待格式化的值 |
836
+ | format | String | 条件必填 | 日期格式模板(仅 type=date 时必填) |
837
+
838
+ **常用格式化类型**:
839
+
840
+ | 类型 | 示例 | 输出 |
841
+ | :--- | :--- | :--- |
842
+ | `date` | `formatter('date', new Date(), 'YYYY-MM-DD')` | `2022-01-29` |
843
+ | `date` | `formatter('date', new Date(), 'YYYY/MM/DD')` | `2022/01/29` |
844
+ | `date` | `formatter('date', new Date(), 'YYYY-MM-DD HH:mm:ss')` | `2022-01-29 13:01:02` |
845
+ | `money` | `formatter('money', '10000.99', ', ')` | `10, 000.99` |
846
+ | `cnmobile` | `formatter('cnmobile', '+8615652988282')` | `+86 1565 2988 282` |
847
+ | `card` | `formatter('card', '1565298828212233')` | `1565 2988 2821 2233` |
848
+
849
+ **请求示例**:
850
+
851
+ ```javascript
852
+ export function format() {
853
+ // 格式化日期
854
+ const date1 = this.utils.formatter('date', new Date(), 'YYYY-MM-DD');
855
+ const date2 = this.utils.formatter('date', new Date(), 'YYYY/MM/DD');
856
+ const dateTime = this.utils.formatter('date', new Date(), 'YYYY-MM-DD HH:mm:ss');
857
+
858
+ // 格式化金额
859
+ const money = this.utils.formatter('money', '10000.99', ', ');
860
+
861
+ // 格式化手机号
862
+ const phone = this.utils.formatter('cnmobile', '+8615652988282');
863
+
864
+ // 格式化银行卡号
865
+ const card = this.utils.formatter('card', '1565298828212233');
866
+ }
867
+ ```
868
+
869
+ ---
870
+
871
+ ### getDateTimeRange
872
+
873
+ **描述**:获取当前或指定日期的开始/结束区间时间戳。
874
+
875
+ **参数**:
876
+
877
+ | 参数名 | 类型 | 默认值 | 说明 |
878
+ | :--- | :--- | :--- | :--- |
879
+ | when | Number \| Date | `new Date()` | 指定日期,支持时间戳或 Date 对象 |
880
+ | type | String | `'day'` | 区间类型:`year` / `month` / `week` / `day` / `date` / `hour` / `minute` / `second` |
881
+
882
+ **返回值**:`[开始时间戳, 结束时间戳]` 数组
883
+
884
+ **请求示例**:
885
+
886
+ ```javascript
887
+ export function search() {
888
+ // 获取当天的开始和结束时间戳
889
+ const [dayStart, dayEnd] = this.utils.getDateTimeRange();
890
+ console.log(`当天范围: ${dayStart} ~ ${dayEnd}`);
891
+
892
+ // 获取当月的开始和结束时间戳
893
+ const [monthStart, monthEnd] = this.utils.getDateTimeRange(new Date(), 'month');
894
+ console.log(`当月范围: ${monthStart} ~ ${monthEnd}`);
895
+ }
896
+ ```
897
+
898
+ ---
899
+
900
+ ### getLocale
901
+
902
+ **描述**:获取当前页面的语言环境。
903
+
904
+ **返回值**:`String` - 语言代码,如 `zh_CN`、`en_US`
905
+
906
+ **请求示例**:
907
+
908
+ ```javascript
909
+ export function locale() {
910
+ const locale = this.utils.getLocale();
911
+ console.log(`当前语言: ${locale}`); // 输出:当前语言: zh_CN
912
+ }
913
+ ```
914
+
915
+ ---
916
+
917
+ ### getLoginUserId
918
+
919
+ **描述**:获取当前登录用户的 ID。
920
+
921
+ **返回值**:`String` - 用户 ID
922
+
923
+ **请求示例**:
924
+
925
+ ```javascript
926
+ export function getUserInfo() {
927
+ const userId = this.utils.getLoginUserId();
928
+ console.log(`用户ID: ${userId}`); // 输出:用户ID: 43314767738888
929
+ }
930
+ ```
931
+
932
+ ---
933
+
934
+ ### getLoginUserName
935
+
936
+ **描述**:获取当前登录用户的名称。
937
+
938
+ **返回值**:`String` - 用户名称
939
+
940
+ **请求示例**:
941
+
942
+ ```javascript
943
+ export function getUserInfo() {
944
+ const userName = this.utils.getLoginUserName();
945
+ console.log(`用户名: ${userName}`); // 输出:用户名: 韩火火
946
+ }
947
+ ```
948
+
949
+ ---
950
+
951
+ ### isMobile
952
+
953
+ **描述**:判断当前访问环境是否是移动端。
954
+
955
+ **返回值**:`Boolean` - `true` 表示移动端,`false` 表示 PC 端
956
+
957
+ **请求示例**:
958
+
959
+ ```javascript
960
+ export function someFunctionName() {
961
+ if (this.utils.isMobile()) {
962
+ console.log('当前是移动端');
963
+ } else {
964
+ console.log('当前是 PC 端');
965
+ }
966
+ }
967
+ ```
968
+
969
+ ---
970
+
971
+ ### isSubmissionPage
972
+
973
+ **描述**:判断当前页面是否是数据提交页面。
974
+
975
+ **返回值**:`Boolean`
976
+
977
+ **请求示例**:
978
+
979
+ ```javascript
980
+ export function someFunctionName() {
981
+ console.log('是否提交页面:', this.utils.isSubmissionPage());
982
+ }
983
+ ```
984
+
985
+ ---
986
+
987
+ ### isViewPage
988
+
989
+ **描述**:判断当前页面是否是数据查看页面。
990
+
991
+ **返回值**:`Boolean`
992
+
993
+ **请求示例**:
994
+
995
+ ```javascript
996
+ export function someFunctionName() {
997
+ console.log('是否查看页面:', this.utils.isViewPage());
998
+ }
999
+ ```
1000
+
1001
+ ---
1002
+
1003
+ ### loadScript
1004
+
1005
+ **描述**:动态加载远程 JavaScript 脚本。
1006
+
1007
+ **参数**:
1008
+
1009
+ | 参数名 | 类型 | 是否必填 | 说明 |
1010
+ | :--- | :--- | :--- | :--- |
1011
+ | url | String | 是 | 脚本 URL 地址 |
1012
+
1013
+ **返回值**:`Promise` - 加载完成后 resolve
1014
+
1015
+ **请求示例**:
1016
+
1017
+ ```javascript
1018
+ export function didMount() {
1019
+ this.utils.loadScript('https://g.alicdn.com/code/lib/qrcodejs/1.0.0/qrcode.min.js')
1020
+ .then(() => {
1021
+ const qrcode = new QRCode(document.getElementById('qrcode'), {
1022
+ text: 'https://www.aliwork.com',
1023
+ width: 128,
1024
+ height: 128,
1025
+ colorDark: '#000000',
1026
+ colorLight: '#ffffff',
1027
+ correctLevel: QRCode.CorrectLevel.H,
1028
+ });
1029
+ });
1030
+ }
1031
+ ```
1032
+
1033
+ **CDN 版本验证(loadScript 使用注意事项)**
1034
+
1035
+ 使用 `this.utils.loadScript(url)` 加载第三方库时,需注意以下要点:
1036
+
1037
+ **1. `loadScript` 只接受 URL 字符串参数**
1038
+
1039
+ ```javascript
1040
+ // ✅ 正确:直接传 URL 字符串
1041
+ this.utils.loadScript('https://g.alicdn.com/code/lib/echarts/5.5.0/echarts.min.js')
1042
+
1043
+ // ❌ 错误:不支持对象形式
1044
+ this.utils.loadScript({ src: '...', type: 'css' })
1045
+ ```
1046
+
1047
+ **2. `g.alicdn.com` CDN 版本必须验证**
1048
+
1049
+ `g.alicdn.com` 是阿里 CDN 镜像,不是所有 npm 版本都有镜像。使用前**必须通过 `curl` 验证版本是否存在**:
1050
+
1051
+ ```bash
1052
+ # 验证 CDN 上是否存在该版本(200 = 存在,404 = 不存在)
1053
+ curl -sI 'https://g.alicdn.com/code/lib/echarts/5.5.0/echarts.min.js' | head -1
1054
+ ```
1055
+
1056
+ **已验证可用的常用库版本**:
1057
+
1058
+ | 库 | 可用版本 | CDN URL |
1059
+ | --- | --- | --- |
1060
+ | ECharts | 5.5.0 | `https://g.alicdn.com/code/lib/echarts/5.5.0/echarts.min.js` |
1061
+ | QRCode.js | 1.0.0 | `https://g.alicdn.com/code/lib/qrcodejs/1.0.0/qrcode.min.js` |
1062
+ | QRCode | 1.5.1 | `https://g.alicdn.com/code/lib/qrcode/1.5.1/qrcode.min.js` |
1063
+
1064
+ > ⚠️ **典型踩坑**:ECharts 5.5.1 在 `g.alicdn.com` 上不存在(404),必须使用 5.5.0。AI 生成代码时容易使用最新版本号,但 CDN 镜像可能未同步,务必先验证。
1065
+
1066
+ ---
1067
+
1068
+ ### loadStyleSheet
1069
+
1070
+ **描述**:动态加载远程 CSS 样式表,在 `<head>` 中插入 `<link rel="stylesheet" href="...">` 标签。适用于加载图标库、第三方组件样式等 CSS 文件。
1071
+
1072
+ > ⚠️ **重要**:加载 CSS 文件必须使用 `loadStyleSheet`,**不能**使用 `loadScript`。
1073
+ > - `loadScript(url)` → 插入 `<script>` 标签,**仅用于 JS 脚本**
1074
+ > - `loadStyleSheet(url)` → 插入 `<link rel="stylesheet">` 标签,**仅用于 CSS 文件**
1075
+
1076
+ **参数**:
1077
+
1078
+ | 参数名 | 类型 | 是否必填 | 说明 |
1079
+ | :--- | :--- | :--- | :--- |
1080
+ | url | String | 是 | CSS 文件的完整 URL 地址 |
1081
+
1082
+ **返回值**:`Promise` - 样式表加载完成后 resolve
1083
+
1084
+ **场景一:加载 iconfont 图标库**
1085
+
1086
+ 在 [iconfont.cn](https://www.iconfont.cn) 创建项目并收藏图标后,生成在线 CSS 链接,然后在 `didMount` 中加载:
1087
+
1088
+ ```javascript
1089
+ export function didMount() {
1090
+ // 从 iconfont.cn 项目「查看在线链接」中复制,格式如下
1091
+ this.utils.loadStyleSheet('https://at.alicdn.com/t/c/font_XXXXX_YYYYY.css');
1092
+ }
1093
+
1094
+ export function renderJsx() {
1095
+ return (
1096
+ <div>
1097
+ {/* 类名格式:iconfont icon-<图标名> */}
1098
+ <i className="iconfont icon-home" style={{ fontSize: '24px', color: '#1677FF' }}></i>
1099
+ <i className="iconfont icon-setting" style={{ fontSize: '24px', color: '#86909C' }}></i>
1100
+ </div>
1101
+ );
1102
+ }
1103
+ ```
1104
+
1105
+ **场景二:加载第三方组件 CSS(如 react-cropper)**
1106
+
1107
+ 当使用 `loadScript` 加载第三方 JS 组件库时,若该库有对应的 CSS 文件,需同时用 `loadStyleSheet` 加载:
1108
+
1109
+ ```javascript
1110
+ export function didMount() {
1111
+ // 先加载 CSS 样式
1112
+ this.utils.loadStyleSheet('https://g.alicdn.com/yida-platform/react-cropper/1.0.0/css/react-cropper.css');
1113
+ // 再加载 JS 脚本
1114
+ this.utils.loadScript('https://g.alicdn.com/yida-platform/react-cropper/1.0.0/js/react-cropper.js')
1115
+ .then(() => {
1116
+ console.log('react-cropper 加载完成');
1117
+ });
1118
+ }
1119
+ ```
1120
+
1121
+ ---
1122
+
1123
+ ### openPage
1124
+
1125
+ **描述**:打开新页面。在钉钉环境下会使用钉钉 API 打开,体验更友好。
1126
+
1127
+ ### router.push
1128
+
1129
+ **描述**:页面路由跳转工具,用于在宜搭应用内进行页面跳转。
1130
+
1131
+ #### 参数说明
1132
+
1133
+ | 参数位置 | 参数名 | 类型 | 必填 | 说明 |
1134
+ | :------- | :----- | :--- | :--- | :--- |
1135
+ | 参数 1 | `target` | String | 是 | 跳转目标:同应用内的页面 ID(如 `FORM-XXX`)或完整 URL |
1136
+ | 参数 2 | `params` | Object | 否 | 携带的跳转参数对象,默认 `{}` |
1137
+ | 参数 3 | `newTab` | Boolean | 否 | 是否新开标签页,`true` 新开,`false` 当前页跳转,默认 `false` |
1138
+ | 参数 4 | `isExternal` | Boolean | 否 | 是否是外部网址,仅当参数 1 为完整 URL 时需要传 `true` |
1139
+
1140
+ #### 使用场景与示例
1141
+
1142
+ **场景一:跳转同应用内的表单页或自定义页(推荐)**
1143
+
1144
+ 当跳转目标与当前页面属于同一个宜搭应用时,直接传页面 ID 即可,无需手拼 URL。
1145
+
1146
+ ```javascript
1147
+ // ✅ 正确:同应用内跳转,传页面 ID
1148
+ this.utils.router.push('FORM-XXX', {}, false);
1149
+
1150
+ // ✅ 正确:带参数跳转
1151
+ this.utils.router.push('FORM-XXX', { id: '123', type: 'edit' }, false);
1152
+
1153
+ // ✅ 正确:跳转到自定义页(PAGE-XXX)
1154
+ this.utils.router.push('PAGE-XXX', { mode: 'view' }, false);
1155
+
1156
+ // ✅ 正确:新标签页打开
1157
+ this.utils.router.push('FORM-XXX', {}, true);
1158
+ ```
1159
+
1160
+ **场景二:跳转外部网址**
1161
+
1162
+ 跳转到宜搭应用外部的网址时,必须传第四个参数 `isExternal = true`。
1163
+
1164
+ ```javascript
1165
+ // ✅ 正确:跳转外部网址,必须传第四个参数 true
1166
+ this.utils.router.push('https://www.example.com', {}, false, true);
1167
+
1168
+ // ❌ 错误:跳转外部网址但未传第四个参数,会导致跳转失败
1169
+ this.utils.router.push('https://www.example.com', {}, false);
1170
+ ```
1171
+
1172
+ #### 最佳实践
1173
+
1174
+ 1. **同应用内跳转优先使用页面 ID**:不要手拼完整 URL,直接使用 `FORM-XXX` 或 `PAGE-XXX`,让系统自动处理路由。
1175
+
1176
+ 2. **参数传递**:需要传递参数时,通过第二个参数 `params` 对象传递,目标页面可通过 `this.state.urlParams` 获取。
1177
+
1178
+ ```javascript
1179
+ // 跳转时传参
1180
+ this.utils.router.push('FORM-XXX', { orderId: '123', action: 'edit' }, false);
1181
+
1182
+ // 目标页面获取参数
1183
+ export function didMount() {
1184
+ const orderId = this.state.urlParams.orderId; // '123'
1185
+ const action = this.state.urlParams.action; // 'edit'
1186
+ }
1187
+ ```
1188
+
1189
+ 3. **是否新开标签页**:
1190
+ - 管理系统内部页面切换,优先使用 `false`(当前页跳转),避免打开过多标签页
1191
+ - 跳转到外部系统或需要保留当前页面状态时,使用 `true`(新标签页打开)
1192
+
1193
+ #### 常见错误
1194
+
1195
+ ```javascript
1196
+ // ❌ 错误:跳转外部网址未传第四个参数
1197
+ this.utils.router.push('https://example.com', {}, false);
1198
+
1199
+ // ✅ 正确:跳转外部网址必须传 isExternal = true
1200
+ this.utils.router.push('https://example.com', {}, false, true);
1201
+
1202
+ // ❌ 错误:同应用内跳转却手拼了完整 URL(容易出错,不推荐)
1203
+ this.utils.router.push('https://www.aliwork.com/APP_XXX/workbench/FORM-XXX', {}, false, true);
1204
+
1205
+ // ✅ 正确:同应用内跳转直接传页面 ID
1206
+ this.utils.router.push('FORM-XXX', {}, false);
1207
+ ```
1208
+
1209
+ #### ⚠️ 重要提醒:禁止手拼宜搭 URL
1210
+
1211
+ **`aliwork.com` 是宜搭平台的域名,同应用内跳转永远不要手拼完整 URL!**
1212
+
1213
+ ```javascript
1214
+ // ❌ 绝对禁止:手拼宜搭 URL(包括 submission、workbench 等路径)
1215
+ this.utils.router.push('https://www.aliwork.com/APP_XXX/submission/FORM-XXX');
1216
+ this.utils.router.push('https://www.aliwork.com/APP_XXX/workbench/FORM-XXX');
1217
+
1218
+ // ✅ 正确:直接传页面 ID,系统自动处理路由
1219
+ this.utils.router.push('FORM-XXX', {}, false);
1220
+ ```
1221
+
1222
+ **判断标准**:
1223
+ - 如果 URL 包含 `aliwork.com` → 这是宜搭应用内页面,**必须**使用页面 ID(`FORM-XXX` 或 `PAGE-XXX`)
1224
+ - 如果 URL 是其他域名(如 `example.com`)→ 这是外部网址,需要传第四个参数 `true`
1225
+
1226
+ ---
1227
+
1228
+ ### previewImage
1229
+
1230
+ **描述**:图片预览,支持手势缩放、滑动切换。
1231
+
1232
+ **参数**:
1233
+
1234
+ | 参数名 | 类型 | 是否必填 | 说明 |
1235
+ | :--- | :--- | :--- | :--- |
1236
+ | current | String | 是 | 当前预览图片的 URL |
1237
+ | urls | Array | 否 | 图片 URL 列表(多图预览时使用) |
1238
+
1239
+ **请求示例**:
1240
+
1241
+ ```javascript
1242
+ export function previewImg() {
1243
+ // 单图预览
1244
+ this.utils.previewImage({
1245
+ current: 'https://img.alicdn.com/tfs/TB1xxx.png',
1246
+ });
1247
+
1248
+ // 多图预览
1249
+ this.utils.previewImage({
1250
+ current: 'https://img.alicdn.com/tfs/TB1xxx.png',
1251
+ urls: [
1252
+ 'https://img.alicdn.com/tfs/TB1xxx.png',
1253
+ 'https://img.alicdn.com/tfs/TB2xxx.png',
1254
+ 'https://img.alicdn.com/tfs/TB3xxx.png',
1255
+ ],
1256
+ });
1257
+ }
1258
+ ```
1259
+
1260
+ ---
1261
+
1262
+ ### toast
1263
+
1264
+ **描述**:信息提醒,比 Dialog 更轻量,自动消失。
1265
+
1266
+ **参数**:
1267
+
1268
+ | 参数名 | 类型 | 默认值 | 说明 |
1269
+ | :--- | :--- | :--- | :--- |
1270
+ | type | String | `'notice'` | 类型:`success` / `warning` / `error` / `notice` / `help` / `loading` |
1271
+ | title | String | - | 提示内容 |
1272
+ | size | String | `'medium'` | 尺寸:`medium` / `large` |
1273
+ | duration | Number | - | 显示时长(毫秒),`loading` 类型时无效 |
1274
+
1275
+ **返回值**:`Function` - 关闭方法(`loading` 类型时返回)
1276
+
1277
+ **请求示例**:
1278
+
1279
+ ```javascript
1280
+ export function popToast() {
1281
+ // 成功提示
1282
+ this.utils.toast({
1283
+ title: '操作成功',
1284
+ type: 'success',
1285
+ size: 'large',
1286
+ });
1287
+ }
1288
+
1289
+ // loading 提示(需手动关闭)
1290
+ export function showLoadingToast() {
1291
+ const close = this.utils.toast({
1292
+ title: '加载中...',
1293
+ type: 'loading',
1294
+ size: 'large',
1295
+ });
1296
+
1297
+ // 3秒后关闭
1298
+ setTimeout(close, 3000);
1299
+ }
1300
+
1301
+ // 错误提示
1302
+ export function showError() {
1303
+ this.utils.toast({
1304
+ title: '操作失败,请重试',
1305
+ type: 'error',
1306
+ duration: 3000,
1307
+ });
1308
+ }
1309
+ ```