weaver-e10-builder 1.6.0 → 1.6.5

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 (183) hide show
  1. package/dist/commands/actionflow.d.ts.map +1 -1
  2. package/dist/commands/actionflow.js +2 -0
  3. package/dist/commands/actionflow.js.map +1 -1
  4. package/dist/commands/check.d.ts.map +1 -1
  5. package/dist/commands/check.js +109 -51
  6. package/dist/commands/check.js.map +1 -1
  7. package/dist/commands/form-add-detail-table.js +3 -3
  8. package/dist/commands/form-add-detail-table.js.map +1 -1
  9. package/dist/commands/form-attachment-setting.d.ts +3 -0
  10. package/dist/commands/form-attachment-setting.d.ts.map +1 -0
  11. package/dist/commands/form-attachment-setting.js +422 -0
  12. package/dist/commands/form-attachment-setting.js.map +1 -0
  13. package/dist/commands/form-browser-definition.js +8 -8
  14. package/dist/commands/form-browser-definition.js.map +1 -1
  15. package/dist/commands/form-code.js +7 -7
  16. package/dist/commands/form-code.js.map +1 -1
  17. package/dist/commands/form-data.d.ts.map +1 -1
  18. package/dist/commands/form-data.js +50 -2
  19. package/dist/commands/form-data.js.map +1 -1
  20. package/dist/commands/form-ebuilder-scope.js +8 -8
  21. package/dist/commands/form-ebuilder-scope.js.map +1 -1
  22. package/dist/commands/form-engine-linkage.js +12 -12
  23. package/dist/commands/form-engine-linkage.js.map +1 -1
  24. package/dist/commands/form-field-linkage.d.ts +6 -1
  25. package/dist/commands/form-field-linkage.d.ts.map +1 -1
  26. package/dist/commands/form-field-linkage.js +138 -31
  27. package/dist/commands/form-field-linkage.js.map +1 -1
  28. package/dist/commands/form-layout-diff.js +1 -1
  29. package/dist/commands/form-layout-diff.js.map +1 -1
  30. package/dist/commands/form-layout-edit.js +1 -1
  31. package/dist/commands/form-layout-edit.js.map +1 -1
  32. package/dist/commands/form-layout-init-reviewed.js +1 -1
  33. package/dist/commands/form-layout-init-reviewed.js.map +1 -1
  34. package/dist/commands/form-layout-init.js +2 -2
  35. package/dist/commands/form-layout-init.js.map +1 -1
  36. package/dist/commands/form-layout-template-easy.js +1 -1
  37. package/dist/commands/form-layout-template-easy.js.map +1 -1
  38. package/dist/commands/form-layout.js +4 -4
  39. package/dist/commands/form-layout.js.map +1 -1
  40. package/dist/commands/form-view.d.ts.map +1 -1
  41. package/dist/commands/form-view.js +1 -2
  42. package/dist/commands/form-view.js.map +1 -1
  43. package/dist/commands/form.d.ts.map +1 -1
  44. package/dist/commands/form.js +50 -5
  45. package/dist/commands/form.js.map +1 -1
  46. package/dist/commands/project.d.ts.map +1 -1
  47. package/dist/commands/project.js +39 -6
  48. package/dist/commands/project.js.map +1 -1
  49. package/dist/commands/report-admin.js +1 -1
  50. package/dist/commands/report-admin.js.map +1 -1
  51. package/dist/commands/report-query.js +1 -1
  52. package/dist/commands/report-query.js.map +1 -1
  53. package/dist/commands/report.js +1 -1
  54. package/dist/commands/report.js.map +1 -1
  55. package/dist/commands/wf-form-layout-init-reviewed.d.ts +3 -0
  56. package/dist/commands/wf-form-layout-init-reviewed.d.ts.map +1 -0
  57. package/dist/commands/wf-form-layout-init-reviewed.js +71 -0
  58. package/dist/commands/wf-form-layout-init-reviewed.js.map +1 -0
  59. package/dist/commands/wf-form.d.ts +1 -0
  60. package/dist/commands/wf-form.d.ts.map +1 -1
  61. package/dist/commands/wf-form.js +16 -16
  62. package/dist/commands/wf-form.js.map +1 -1
  63. package/dist/commands/workflow-advanced.js +1 -1
  64. package/dist/commands/workflow-advanced.js.map +1 -1
  65. package/dist/commands/workflow-basic-info.js +4 -4
  66. package/dist/commands/workflow-basic-info.js.map +1 -1
  67. package/dist/commands/workflow.js +6 -6
  68. package/dist/commands/workflow.js.map +1 -1
  69. package/dist/index.js +22 -0
  70. package/dist/index.js.map +1 -1
  71. package/dist/services/actionflow/classified_protection_source.d.ts +10 -0
  72. package/dist/services/actionflow/classified_protection_source.d.ts.map +1 -0
  73. package/dist/services/actionflow/classified_protection_source.js +27 -0
  74. package/dist/services/actionflow/classified_protection_source.js.map +1 -0
  75. package/dist/services/actionflow/components/action_eb_add.d.ts.map +1 -1
  76. package/dist/services/actionflow/components/action_eb_add.js +4 -5
  77. package/dist/services/actionflow/components/action_eb_add.js.map +1 -1
  78. package/dist/services/actionflow/components/action_eb_update.d.ts.map +1 -1
  79. package/dist/services/actionflow/components/action_eb_update.js +13 -1
  80. package/dist/services/actionflow/components/action_eb_update.js.map +1 -1
  81. package/dist/services/actionflow/components/action_eb_update_compiler.d.ts +12 -0
  82. package/dist/services/actionflow/components/action_eb_update_compiler.d.ts.map +1 -1
  83. package/dist/services/actionflow/components/action_eb_update_compiler.js +88 -3
  84. package/dist/services/actionflow/components/action_eb_update_compiler.js.map +1 -1
  85. package/dist/services/actionflow/components/approve_create.d.ts.map +1 -1
  86. package/dist/services/actionflow/components/approve_create.js +6 -10
  87. package/dist/services/actionflow/components/approve_create.js.map +1 -1
  88. package/dist/services/actionflow/components/condition.d.ts.map +1 -1
  89. package/dist/services/actionflow/components/condition.js +3 -2
  90. package/dist/services/actionflow/components/condition.js.map +1 -1
  91. package/dist/services/actionflow/components/eb_get_data_by_id.d.ts.map +1 -1
  92. package/dist/services/actionflow/components/eb_get_data_by_id.js +9 -1
  93. package/dist/services/actionflow/components/eb_get_data_by_id.js.map +1 -1
  94. package/dist/services/actionflow/components/send_message.js +1 -1
  95. package/dist/services/actionflow/components/send_message.js.map +1 -1
  96. package/dist/services/actionflow/components/workflow_actions.d.ts.map +1 -1
  97. package/dist/services/actionflow/components/workflow_actions.js +20 -11
  98. package/dist/services/actionflow/components/workflow_actions.js.map +1 -1
  99. package/dist/services/actionflow/context_preflight.d.ts.map +1 -1
  100. package/dist/services/actionflow/context_preflight.js +9 -1
  101. package/dist/services/actionflow/context_preflight.js.map +1 -1
  102. package/dist/services/actionflow/design_client.d.ts +4 -0
  103. package/dist/services/actionflow/design_client.d.ts.map +1 -1
  104. package/dist/services/actionflow/design_client.js +65 -0
  105. package/dist/services/actionflow/design_client.js.map +1 -1
  106. package/dist/services/actionflow/form_source.d.ts +9 -2
  107. package/dist/services/actionflow/form_source.d.ts.map +1 -1
  108. package/dist/services/actionflow/form_source.js +21 -6
  109. package/dist/services/actionflow/form_source.js.map +1 -1
  110. package/dist/services/actionflow/formula_service.d.ts.map +1 -1
  111. package/dist/services/actionflow/formula_service.js +153 -37
  112. package/dist/services/actionflow/formula_service.js.map +1 -1
  113. package/dist/services/actionflow/preflight_service.d.ts +14 -3
  114. package/dist/services/actionflow/preflight_service.d.ts.map +1 -1
  115. package/dist/services/actionflow/preflight_service.js +276 -42
  116. package/dist/services/actionflow/preflight_service.js.map +1 -1
  117. package/dist/services/actionflow/workflow_compiler.d.ts.map +1 -1
  118. package/dist/services/actionflow/workflow_compiler.js +154 -23
  119. package/dist/services/actionflow/workflow_compiler.js.map +1 -1
  120. package/dist/services/form-attachment-settings.d.ts +110 -0
  121. package/dist/services/form-attachment-settings.d.ts.map +1 -0
  122. package/dist/services/form-attachment-settings.js +332 -0
  123. package/dist/services/form-attachment-settings.js.map +1 -0
  124. package/dist/services/form-attachment-upload.d.ts +30 -0
  125. package/dist/services/form-attachment-upload.d.ts.map +1 -0
  126. package/dist/services/form-attachment-upload.js +76 -0
  127. package/dist/services/form-attachment-upload.js.map +1 -0
  128. package/dist/services/form-data-openapi.d.ts +2 -0
  129. package/dist/services/form-data-openapi.d.ts.map +1 -1
  130. package/dist/services/form-data-openapi.js +1 -0
  131. package/dist/services/form-data-openapi.js.map +1 -1
  132. package/dist/services/workflow-layout-init-reviewed.d.ts +35 -0
  133. package/dist/services/workflow-layout-init-reviewed.d.ts.map +1 -0
  134. package/dist/services/workflow-layout-init-reviewed.js +120 -0
  135. package/dist/services/workflow-layout-init-reviewed.js.map +1 -0
  136. package/package.json +1 -1
  137. package/skill-docs/SKILL.md +163 -160
  138. package/skill-docs/_catalog.md +6 -4
  139. package/skill-docs/actionflows/SKILL.md +2 -0
  140. package/skill-docs/actionflows/references/components/ebuilder/ActionEbUpdate.md +2 -0
  141. package/skill-docs/actionflows/references/components/ebuilder/EventButton.md +1 -1
  142. package/skill-docs/actionflows/references/components/logic/Condition.md +2 -0
  143. package/skill-docs/actionflows/references/components/message/SendMessage.md +2 -2
  144. package/skill-docs/actionflows/references/components/workflow/ApproveCommit.md +17 -17
  145. package/skill-docs/actionflows/references/components/workflow/ApproveCreate.md +1 -1
  146. package/skill-docs/actionflows/references/components/workflow/ApproveSave.md +1 -1
  147. package/skill-docs/actionflows/references/components/workflow/ApproveSendBack.md +17 -17
  148. package/skill-docs/assets/sample/api/formApi.js +689 -510
  149. package/skill-docs/assets/sample/app/config.js +4 -0
  150. package/skill-docs/assets/sample/app/fields.js +25 -0
  151. package/skill-docs/assets/sample/entry.js +24 -22
  152. package/skill-docs/assets/sample/eslint.config.cjs +1 -0
  153. package/skill-docs/assets/sample/pages/Items.js +247 -0
  154. package/skill-docs/assets/sample/styles/prototypeStyles.js +137 -0
  155. package/skill-docs/references/coding/guide-edit-backfill.md +102 -150
  156. package/skill-docs/references/coding/guide-form-crud.md +195 -172
  157. package/skill-docs/references/coding/guide-html-to-react.md +250 -0
  158. package/skill-docs/references/coding/guide-page-code.md +194 -167
  159. package/skill-docs/references/coding/guide-page-export.md +27 -18
  160. package/skill-docs/references/coding/ref-compile-rules.md +7 -7
  161. package/skill-docs/references/common/map.md +2 -1
  162. package/skill-docs/references/common/ref-cli-commands.md +14 -6
  163. package/skill-docs/references/components/display-FilePreview.md +5 -4
  164. package/skill-docs/references/form/guide-browser-definition.md +73 -40
  165. package/skill-docs/references/form/guide-field-linkage.md +4 -1
  166. package/skill-docs/references/form/guide-form-attachment-setting.md +95 -0
  167. package/skill-docs/references/form/guide-form-data.md +22 -1
  168. package/skill-docs/references/form/layout/code-block/layout-css.md +41 -0
  169. package/skill-docs/references/form/layout/initialization.md +2 -0
  170. package/skill-docs/references/form/layout/layout-overview.md +8 -0
  171. package/skill-docs/references/form/layout/template/advanced.md +21 -0
  172. package/skill-docs/references/form/layout/template/easy.md +2 -0
  173. package/skill-docs/references/form/layout/template/flow.md +2 -0
  174. package/skill-docs/references/form/layout/template/template-guide.md +3 -1
  175. package/skill-docs/references/form/layout/workflow-layout.md +13 -1
  176. package/skill-docs/references/form/ref-form-fields.md +18 -4
  177. package/skill-docs/references/workflow/guide-workflow-odoc.md +1 -1
  178. package/skill-docs/assets/sample/config/config.js +0 -0
  179. package/skill-docs/assets/sample/config/configLoad.js +0 -0
  180. package/skill-docs/assets/sample/config/configLoad_default.js +0 -0
  181. package/skill-docs/assets/sample/config/config_default.js +0 -0
  182. package/skill-docs/assets/sample/memo.md +0 -0
  183. package/skill-docs/assets/sample/readme.js +0 -8
@@ -1,510 +1,689 @@
1
- import { appInfo } from '@weapp/utils';
2
- const { publicUrl } = appInfo('@weapp/ecodesdk');
3
- const API_BASE = `${publicUrl}/api/ebuilder/form/dataset`;
4
-
5
- /**
6
- * Fetches data with a timeout and retry mechanism.
7
- * @param {string} url - The URL to fetch.
8
- * @param {RequestInit} options - Fetch options.
9
- * @param {number} [timeoutMs=5000] - Timeout in milliseconds.
10
- * @param {number} [retries=3] - Number of retries.
11
- * @returns {Promise<Response>}
12
- */
13
- async function fetchWithRetry(url, options, timeoutMs = 5000, retries = 3) {
14
- let lastError;
15
-
16
- for (let i = 0; i <= retries; i++) {
17
- const controller = new AbortController();
18
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
19
-
20
- try {
21
- const response = await fetch(url, {
22
- ...options,
23
- signal: controller.signal,
24
- });
25
-
26
- clearTimeout(timeoutId);
27
- return response;
28
- } catch (error) {
29
- clearTimeout(timeoutId);
30
- lastError = error;
31
-
32
- // If it's the last attempt, throw the error
33
- if (i === retries) {
34
- throw new Error(`Request failed after ${retries + 1} attempts. Last error: ${lastError.message}`);
35
- }
36
-
37
- // Optional: Add exponential backoff or simple delay before retrying
38
- await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
39
- }
40
- }
41
-
42
- // This line should theoretically not be reached due to the throw above
43
- throw lastError;
44
- }
45
-
46
- /**
47
- * 获取字段定义
48
- * @param {string} objId
49
- * @param {string} userId
50
- * @returns {Promise<Array>}
51
- */
52
- export async function getFields(objId, userId) {
53
- const response = await fetchWithRetry(`${API_BASE}/v1/getFields`, {
54
- method: 'POST',
55
- headers: { 'Content-Type': 'application/json' },
56
- body: JSON.stringify({
57
- userid: userId,
58
- objId: objId,
59
- tenantKey: TENANTKEY,
60
- }),
61
- });
62
-
63
- const result = await response.json();
64
-
65
- if (result.message.code !== '0') {
66
- throw new Error(`获取字段失败: ${result.message.msg}`);
67
- }
68
-
69
- // 按 number 排序,保持表单原始顺序
70
- return result.data.mainFields.sort((a, b) => a.number - b.number);
71
- }
72
-
73
- /**
74
- * 获取所有数据
75
- * @param {string} objId
76
- * @param {string} userId
77
- * @returns {Promise<Array>}
78
- */
79
- const TENANTKEY = TEAMS.currentTenant.tenantKey
80
- export async function getAllData(objId, userId) {
81
- const response = await fetchWithRetry(`${API_BASE}/v2/getAllData?tenantkey=${TENANTKEY}`, {
82
- method: 'POST',
83
- headers: { 'Content-Type': 'application/json' },
84
- body: JSON.stringify({
85
- userid: userId,
86
- datajson: {
87
- header: { objId: objId },
88
- },
89
- }),
90
- });
91
-
92
- const result = await response.json();
93
-
94
- if (result.message.code !== '0') {
95
- throw new Error(`获取数据失败: ${result.message.msg}`);
96
- }
97
-
98
- return result.data.datajson.datas || [];
99
- }
100
-
101
- // ==================== 数据解析函数 ====================
102
-
103
- /**
104
- * 解析单个字段的值
105
- * @param {any} value
106
- * @param {Object} fieldDef
107
- * @returns {Object} ParsedValue
108
- */
109
- export function parseFieldValue(value, fieldDef) {
110
- // 处理 undefined 或 null 值
111
- if (!value) {
112
- return { displayValue: '', rawValue: value };
113
- }
114
-
115
- // 处理数组类型(Select, RadioBox, CheckBox 等多选/单选)
116
- if (Array.isArray(value)) {
117
- if (value.length === 0) {
118
- return { displayValue: '', rawValue: [] };
119
- }
120
-
121
- // 提取选项名称列表
122
- const optionNames = value
123
- .map(v => v?.fieldOptionName || v?.fieldValue || '')
124
- .filter(v => v);
125
-
126
- const options = value.map(v => ({
127
- id: v?.fieldOptionId || '',
128
- name: v?.fieldOptionName || v?.fieldValue || '',
129
- }));
130
-
131
- return {
132
- displayValue: optionNames.join(', '),
133
- rawValue: value,
134
- options: options,
135
- };
136
- }
137
-
138
- // 处理普通对象
139
- const fieldType = fieldDef.fieldType;
140
-
141
- switch (fieldType) {
142
- case 'Employee':
143
- // 员工字段可能返回用户ID或姓名
144
- return {
145
- displayValue: value.fieldValue || '',
146
- rawValue: value,
147
- };
148
- case 'Date':
149
- // 日期格式化
150
- const dateValue = value.fieldValue;
151
- if (dateValue && dateValue.includes('-')) {
152
- return { displayValue: dateValue, rawValue: value };
153
- }
154
- return { displayValue: dateValue || '', rawValue: value };
155
- case 'Number':
156
- return {
157
- displayValue: value.fieldValue || '0',
158
- rawValue: value,
159
- };
160
- case 'Select':
161
- case 'RadioBox':
162
- return {
163
- displayValue: value.fieldOptionName || value.fieldValue || '',
164
- rawValue: value,
165
- };
166
- default:
167
- return {
168
- displayValue: value.fieldValue || '',
169
- rawValue: value,
170
- };
171
- }
172
- }
173
-
174
- // ==================== 数据格式转换函数 ====================
175
-
176
- /**
177
- * 将API返回的复杂数据结构转换为简单的键值对格式
178
- * @param {Array} dataRows
179
- * @param {Array} fields
180
- * @returns {Array<SimpleDataItem>}
181
- */
182
- export function transformToSimpleFormat(dataRows, fields) {
183
- if (!dataRows || !dataRows.length) return [];
184
- // Create a map for quick lookup: fieldId -> FieldDefinition
185
- const fieldMap = new Map();
186
- fields.forEach(field => {
187
- fieldMap.set(field.fieldId, field);
188
- });
189
-
190
- return dataRows.map(row => {
191
- const simpleItem = {};
192
-
193
- // Copy row-level id (data ID) to simple item
194
- if (row.id) {
195
- simpleItem.id = row.id;
196
- }
197
-
198
- // Process mainTable
199
- if (row.mainTable) {
200
- Object.entries(row.mainTable).forEach(([key, value]) => {
201
- // Handle the special 'id' field in mainTable
202
- if (key === 'id' && value && typeof value === 'object') {
203
- simpleItem.id = value.fieldValue || value.fieldOptionName || '';
204
- return;
205
- }
206
-
207
- let actualFieldId;
208
- let parsedValue;
209
-
210
- // Case 1: Value is an object/array containing fieldId (Standard dynamic form structure)
211
- if (value && typeof value === 'object') {
212
- if (Array.isArray(value)) {
213
- // For arrays (like RadioBox/Select), the fieldId is usually in the first item
214
- actualFieldId = value[0]?.fieldId;
215
- } else {
216
- // For objects (like TextArea, Number), the fieldId is directly on the object
217
- actualFieldId = value.fieldId;
218
- }
219
- }
220
- // Case 2: Value is a primitive (fallback)
221
- else {
222
- actualFieldId = key;
223
- }
224
-
225
- // Find the field definition using the extracted actualFieldId
226
- const fieldDef = actualFieldId ? fieldMap.get(actualFieldId) : undefined;
227
-
228
- // Determine the key: Use fieldId if available, otherwise fallback to original key
229
- const resultKey = fieldDef ? fieldDef.fieldId : key;
230
-
231
- // Parse the value using the correct field definition
232
- // Fallback definition if fieldDef is missing
233
- const fallbackDef = {
234
- id: 0,
235
- fieldId: actualFieldId || key,
236
- fieldName: resultKey,
237
- fieldType: 'String',
238
- fieldKey: 'Text',
239
- number: 0,
240
- multiSelect: false,
241
- objId: 0
242
- };
243
-
244
- parsedValue = parseFieldValue(value, fieldDef || fallbackDef);
245
-
246
- // Assign to result using the fieldId as the key
247
- let finalValue = parsedValue.displayValue;
248
-
249
- // 特殊类型统一返回 fieldOptionId(写入和组件回显需要的 ID)
250
- // Select/RadioBox/CheckBox → 选项ID, Employee → 人员ID, Department → 部门ID, FileComponent → 文件ID
251
- // 如需显示名称,配合 getFieldOptions 或从 uploadedFiles/selectedPerson 状态中获取
252
- const fieldType = fieldDef?.fieldType;
253
- const isIdType = fieldType === 'Select' || fieldType === 'RadioBox' || fieldType === 'CheckBox'
254
- || fieldType === 'Employee' || fieldType === 'Department' || fieldType === 'FileComponent';
255
-
256
- if (isIdType) {
257
- if (Array.isArray(value)) {
258
- const ids = value
259
- .map((v) => v?.fieldOptionId)
260
- .filter((id) => id !== undefined && id !== null && id !== '');
261
-
262
- finalValue = ids.length > 0 ? ids.join(',') : '';
263
- } else if (value && typeof value === 'object') {
264
- finalValue = value.fieldOptionId ? String(value.fieldOptionId) : '';
265
- }
266
- }
267
-
268
- simpleItem[actualFieldId] = finalValue;
269
- });
270
- }
271
-
272
- return simpleItem;
273
- });
274
- }
275
-
276
- /**
277
- * 获取转换后的简单格式数据
278
- * @param {string} objId
279
- * @param {string} userId
280
- * @returns {Promise<Array<SimpleDataItem>>}
281
- */
282
- export async function getSimpleData(objId, userId) {
283
- const [fields, dataRows] = await Promise.all([
284
- getFields(objId, userId),
285
- getAllData(objId, userId)
286
- ]);
287
- const result = transformToSimpleFormat(dataRows, fields);
288
- return result;
289
- }
290
-
291
- // ==================== ID → 名称映射(用于表格展示) ====================
292
-
293
- /**
294
- * 将 simpleData 中 Select/Employee/Department 等字段的 ID 替换为显示名称。
295
- * getSimpleData 返回的是 ID(用于写入),表格展示需要名称,用此函数转换。
296
- *
297
- * @param {Array<Object>} simpleData — getSimpleData 的返回值
298
- * @param {Object} optionsMap — { fieldId: [{valueKey, name}, ...] },valueKey→name 的映射表
299
- * @returns {Array<Object>} 字段值为显示名称的新数组
300
- *
301
- * 用法:
302
- * var [data, setData] = useState([]);
303
- * useEffect(function () {
304
- * Promise.all([
305
- * getSimpleData(OBJ_ID, USER_ID),
306
- * getFieldOptions(F.status, FORM_ID),
307
- * ]).then(function ([rows, statusOpts]) {
308
- * setData(withDisplayNames(rows, { [F.status]: statusOpts }));
309
- * });
310
- * }, []);
311
- */
312
- export function withDisplayNames(simpleData, optionsMap) {
313
- return simpleData.map(function (row) {
314
- var displayRow = {};
315
- Object.keys(row).forEach(function (key) {
316
- var options = optionsMap[key];
317
- if (options && options.length) {
318
- var ids = (row[key] || '').split(',');
319
- displayRow[key] = ids.map(function (id) {
320
- var opt = options.find(function (o) { return o.valueKey === id; });
321
- return opt ? opt.name : id;
322
- }).join(', ');
323
- } else {
324
- displayRow[key] = row[key];
325
- }
326
- });
327
- return displayRow;
328
- });
329
- }
330
-
331
- // ==================== 保存表单数据 ====================
332
-
333
- /**
334
- * 保存表单数据
335
- * @param {string} objId
336
- * @param {Object} formData
337
- * @param {string} userId
338
- * @returns {Promise<Object>}
339
- */
340
- export async function saveFormData(objId, formData, userId) {
341
- const requestData = {
342
- userid: userId,
343
- datajson: {
344
- datas: {
345
- mainTable: formData,
346
- operationinfo: {
347
- doAction: 'n', // 新增操作
348
- optionNoFindIgnore: 'false'
349
- }
350
- },
351
- header: {
352
- objId: objId,
353
- tenantKey: TENANTKEY
354
- }
355
- }
356
- };
357
-
358
- const response = await fetchWithRetry(`${API_BASE}/v1/saveFormData`, {
359
- method: 'POST',
360
- headers: {
361
- 'Content-Type': 'application/json'
362
- },
363
- body: JSON.stringify(requestData),
364
- });
365
-
366
- const result = await response.json();
367
- if (result.data && result.data.isSuccess === false) {
368
- throw new Error('保存失败: ' + (result.data.msg || JSON.stringify(result.data)));
369
- }
370
- if (result.message && result.message.code !== '0') {
371
- throw new Error('保存失败: ' + (result.message.msg || JSON.stringify(result.message)));
372
- }
373
- return result;
374
- }
375
-
376
- // ==================== 更新表单数据 ====================
377
-
378
- /**
379
- * 更新表单数据
380
- * @param {string} objId
381
- * @param {Object} formData
382
- * @param {string} dataId - 数据ID
383
- * @param {string} userId
384
- * @returns {Promise<Object>}
385
- */
386
- export async function updateFormData(objId, formData, dataId, userId) {
387
- const requestData = {
388
- userid: userId,
389
- datajson: {
390
- datas: {
391
- mainTable: Object.assign({ id: dataId }, formData),
392
- operationinfo: {
393
- doAction: 'u',
394
- optionNoFindIgnore: 'false'
395
- }
396
- },
397
- header: {
398
- objId: objId,
399
- tenantKey: TENANTKEY
400
- }
401
- }
402
- };
403
-
404
- const response = await fetchWithRetry(`${API_BASE}/v1/saveFormData`, {
405
- method: 'POST',
406
- headers: {
407
- 'Content-Type': 'application/json'
408
- },
409
- body: JSON.stringify(requestData),
410
- });
411
-
412
- const result = await response.json();
413
- if (result.data && result.data.isSuccess === false) {
414
- throw new Error('更新失败: ' + (result.data.msg || JSON.stringify(result.data)));
415
- }
416
- if (result.message && result.message.code !== '0') {
417
- throw new Error('更新失败: ' + (result.message.msg || JSON.stringify(result.message)));
418
- }
419
- return result;
420
- }
421
-
422
- // ==================== 删除表单数据 ====================
423
-
424
- /**
425
- * 删除表单数据
426
- * @param {string} objId - 表单ID (objId)
427
- * @param {string|number} dataId - 数据ID
428
- * @param {string} userId - User ID
429
- * @returns {Promise<Object>}
430
- */
431
- export async function deleteFormData(objId, dataId, userId) {
432
- const requestData = {
433
- userid: userId,
434
- datajson: {
435
- header: {
436
- objId: objId
437
- },
438
- mainTable: {
439
- id: dataId
440
- },
441
- operationinfo: {
442
- fieldNoFindIgnore: 'false'
443
- }
444
- }
445
- };
446
-
447
- const response = await fetchWithRetry(`${API_BASE}/v2/deleteData`, {
448
- method: 'POST',
449
- headers: {
450
- 'Content-Type': 'application/json'
451
- },
452
- body: JSON.stringify(requestData),
453
- });
454
-
455
- const result = await response.json();
456
-
457
- if (result.message.code !== '0') {
458
- throw new Error(`删除数据失败: ${result.message.msg}`);
459
- }
460
-
461
- return result;
462
- }
463
-
464
- // ==================== 获取选项字段的具体选项值 ====================
465
- export async function getFieldOptions(fieldId, objId) {
466
- // 注意:第二个参数是 objId(表单对象 ID),与 getSimpleData/saveFormData 用的是同一个值
467
- const infoUrl = `${publicUrl}/api/ebuilder/form/obj/getInfo/${objId}`;
468
- const infoResponse = await fetchWithRetry(infoUrl, {
469
- method: 'GET',
470
- headers: { 'Content-Type': 'application/json' },
471
- });
472
- const infoResult = await infoResponse.json();
473
- if (infoResult.code !== 200 || !infoResult.status) {
474
- throw new Error(`获取表单信息失败: ${infoResult.msg || 'Unknown error'}`);
475
- }
476
- const formIdNew = infoResult.data?.formId;
477
-
478
- if (!formIdNew) {
479
- throw new Error('未能从表单信息中获取有效的 formId');
480
- }
481
-
482
- const url = `${publicUrl}/api/ebuilder/form/form/field/manage/getFormField`;
483
- const requestBody = {
484
- module: "ebuilderform",
485
- formTableField: {
486
- formField: {
487
- id: fieldId,
488
- form: {
489
- id: formIdNew // Use the dynamically fetched formId
490
- }
491
- }
492
- }
493
- };
494
- const response = await fetchWithRetry(url, {
495
- method: 'POST',
496
- headers: { 'Content-Type': 'application/json' },
497
- body: JSON.stringify(requestBody),
498
- });
499
-
500
- const result = await response.json();
501
- if (result.code !== 200 || !result.status) {
502
- throw new Error(`获取字段选项失败: ${result.msg || 'Unknown error'}`);
503
- }
504
-
505
- const options = result.data?.options || [];
506
- return options.map(option => ({
507
- valueKey: option.valueKey,
508
- name: option.name
509
- }));
510
- }
1
+ import { appInfo } from '@weapp/utils';
2
+
3
+ var SDK_INFO = appInfo('@weapp/ecodesdk');
4
+ var PUBLIC_URL = SDK_INFO.publicUrl;
5
+ var API_BASE = PUBLIC_URL + '/api/ebuilder/form/dataset';
6
+
7
+ function getTeams() {
8
+ if (typeof TEAMS !== 'undefined') return TEAMS;
9
+ if (typeof window !== 'undefined' && window.TEAMS) return window.TEAMS;
10
+ return {};
11
+ }
12
+
13
+ var TEAMS_OBJ = getTeams();
14
+ var USER_ID = (TEAMS_OBJ.currentUser && TEAMS_OBJ.currentUser.id) || '';
15
+ var TENANT_KEY = (TEAMS_OBJ.currentTenant && TEAMS_OBJ.currentTenant.tenantKey) || '';
16
+
17
+ var clients = {};
18
+
19
+ function headers(appId) {
20
+ var result = {
21
+ 'Content-Type': 'application/json',
22
+ 'Accept': 'application/json'
23
+ };
24
+ if (appId) result.ebbusinessid = String(appId);
25
+ return result;
26
+ }
27
+
28
+ function multipartHeaders(appId) {
29
+ var result = { 'Accept': 'application/json' };
30
+ if (appId) result.ebbusinessid = String(appId);
31
+ return result;
32
+ }
33
+
34
+ function parseResponse(res) {
35
+ return res.text().then(function (text) {
36
+ var data = {};
37
+ try {
38
+ data = text ? JSON.parse(text) : {};
39
+ } catch (e) {
40
+ throw new Error('接口返回不是 JSON(HTTP ' + res.status + ')');
41
+ }
42
+ if (!res.ok) {
43
+ throw new Error('请求失败(HTTP ' + res.status + ')' + (data && data.msg ? ':' + data.msg : ''));
44
+ }
45
+ return data;
46
+ });
47
+ }
48
+
49
+ function readRequest(url, options, retries) {
50
+ if (retries === undefined) retries = 1;
51
+ var timeout = 15000;
52
+
53
+ function attempt(n) {
54
+ var controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
55
+ var timer = null;
56
+ var opts = Object.assign({}, options);
57
+ if (controller) {
58
+ opts.signal = controller.signal;
59
+ timer = setTimeout(function () { controller.abort(); }, timeout);
60
+ }
61
+ return fetch(url, opts).then(function (res) {
62
+ if (timer) clearTimeout(timer);
63
+ return parseResponse(res);
64
+ }).catch(function (err) {
65
+ if (timer) clearTimeout(timer);
66
+ if (n < retries) {
67
+ return new Promise(function (resolve) {
68
+ setTimeout(function () { resolve(attempt(n + 1)); }, 500 * (n + 1));
69
+ });
70
+ }
71
+ throw err;
72
+ });
73
+ }
74
+
75
+ return attempt(0);
76
+ }
77
+
78
+ function writeRequest(url, body, appId) {
79
+ return fetch(url, {
80
+ method: 'POST',
81
+ headers: headers(appId),
82
+ body: JSON.stringify(body)
83
+ }).then(parseResponse);
84
+ }
85
+
86
+ function innerOf(res) {
87
+ return res && res.data && res.data.datajson ? res.data.datajson : null;
88
+ }
89
+
90
+ function assertOk(res, action) {
91
+ var message = res && res.message;
92
+ if (message && message.code !== undefined
93
+ && String(message.code) !== '0' && String(message.code) !== '200') {
94
+ throw new Error(action + '失败:' + (message.msg || String(message.code)));
95
+ }
96
+ var inner = innerOf(res);
97
+ if (inner && inner.status === false) {
98
+ throw new Error(action + '失败:' + (inner.message || '平台返回失败'));
99
+ }
100
+ if (res && res.code !== undefined
101
+ && String(res.code) !== '200' && String(res.code) !== '0') {
102
+ throw new Error(action + '失败:' + (res.msg || String(res.code)));
103
+ }
104
+ return res;
105
+ }
106
+
107
+ function textOf(cell) {
108
+ if (cell === undefined || cell === null) return '';
109
+ if (Array.isArray(cell)) {
110
+ return cell.map(textOf).filter(function (x) { return x !== ''; }).join(',');
111
+ }
112
+ if (typeof cell === 'object') {
113
+ if (cell.fieldOptionName) return String(cell.fieldOptionName);
114
+ if (cell.fieldTextValue) return String(cell.fieldTextValue);
115
+ if (cell.fieldValue !== undefined && cell.fieldValue !== null) return String(cell.fieldValue);
116
+ return '';
117
+ }
118
+ return String(cell);
119
+ }
120
+
121
+ function valueOf(cell) {
122
+ if (cell === undefined || cell === null) return '';
123
+ if (Array.isArray(cell)) {
124
+ return cell.map(valueOf).filter(function (x) { return x !== ''; }).join(',');
125
+ }
126
+ if (typeof cell === 'object') {
127
+ if (cell.fieldValue !== undefined && cell.fieldValue !== null) return String(cell.fieldValue);
128
+ if (cell.fieldOptionId !== undefined && cell.fieldOptionId !== null) return String(cell.fieldOptionId);
129
+ return '';
130
+ }
131
+ return String(cell);
132
+ }
133
+
134
+ function itemsOf(cell) {
135
+ if (cell === undefined || cell === null) return [];
136
+ var source = Array.isArray(cell) ? cell : [cell];
137
+ var result = [];
138
+ source.forEach(function (item) {
139
+ if (item === undefined || item === null || item === '') return;
140
+ if (typeof item !== 'object') {
141
+ result.push({ id: String(item), name: String(item) });
142
+ return;
143
+ }
144
+ var id = item.fieldOptionId;
145
+ if (id === undefined || id === null || id === '') id = item.fieldValue;
146
+ if (id === undefined || id === null || id === '') return;
147
+ var name = item.fieldOptionName || item.fieldTextValue || item.fieldValue || String(id);
148
+ result.push({ id: String(id), name: String(name) });
149
+ });
150
+ return result;
151
+ }
152
+
153
+ function idsOf(cell) {
154
+ return itemsOf(cell).map(function (item) { return item.id; }).join(',');
155
+ }
156
+
157
+ var ID_FIELD_TYPES = [
158
+ 'Select', 'RadioBox', 'CheckBox', 'Employee', 'Department',
159
+ 'FileComponent', 'Ebuilder', 'Browser', 'RelateBrowser'
160
+ ];
161
+
162
+ function isIdField(field) {
163
+ return ID_FIELD_TYPES.indexOf(field && field.fieldType) >= 0;
164
+ }
165
+
166
+ function normalizeWriteValue(value) {
167
+ if (!Array.isArray(value)) return value;
168
+ return value.map(function (item) {
169
+ if (item && typeof item === 'object') {
170
+ return String(item.id || item.valueKey || item.fieldOptionId || '');
171
+ }
172
+ return String(item);
173
+ }).filter(function (item) { return item !== ''; }).join(',');
174
+ }
175
+
176
+ function requestKeyOf(field) {
177
+ var id = String(field.id || '');
178
+ var name = String(field.name || '');
179
+ var dataKey = field.config && field.config.dataKey ? String(field.config.dataKey) : '';
180
+ if (name === id && dataKey) return dataKey;
181
+ return name || dataKey || id;
182
+ }
183
+
184
+ function cellMap(mainTable) {
185
+ var result = {};
186
+ Object.keys(mainTable || {}).forEach(function (key) {
187
+ var value = mainTable[key];
188
+ if (value === undefined || value === null) return;
189
+ var fieldId = '';
190
+ if (Array.isArray(value)) fieldId = value[0] && value[0].fieldId;
191
+ else if (typeof value === 'object') fieldId = value.fieldId;
192
+ else fieldId = key;
193
+ if (fieldId) result[String(fieldId)] = value;
194
+ });
195
+ return result;
196
+ }
197
+
198
+ function idOfCell(value) {
199
+ if (value && typeof value === 'object') {
200
+ return String(value.fieldValue || value.fieldOptionId || '');
201
+ }
202
+ if (value !== undefined && value !== null) return String(value);
203
+ return '';
204
+ }
205
+
206
+ function toFlatRow(row, fields, idFallback) {
207
+ var cells = cellMap(row);
208
+ var values = {};
209
+ var display = {};
210
+ var items = {};
211
+
212
+ fields.forEach(function (field) {
213
+ var cell = cells[String(field.fieldId)];
214
+ if (cell === undefined) return;
215
+ var idField = isIdField(field);
216
+ values[field.fieldId] = idField ? idsOf(cell) : valueOf(cell);
217
+ display[field.fieldId] = textOf(cell);
218
+ if (idField) items[field.fieldId] = itemsOf(cell);
219
+ });
220
+
221
+ var id = idOfCell(row && row.id);
222
+ if (!id && idFallback !== undefined && idFallback !== null) id = String(idFallback);
223
+ return {
224
+ id: id,
225
+ values: values,
226
+ display: display,
227
+ items: items,
228
+ raw: row
229
+ };
230
+ }
231
+
232
+ function toRow(raw, fields, detailMeta) {
233
+ var mainTable = raw && raw.mainTable ? raw.mainTable : {};
234
+ var result = toFlatRow(mainTable, fields, raw && raw.id);
235
+ var details = {};
236
+ var detailRows = {};
237
+
238
+ Object.keys(raw || {}).forEach(function (node) {
239
+ if (node.indexOf('detail') !== 0 || !Array.isArray(raw[node])) return;
240
+ details[node] = raw[node];
241
+ var def = detailMeta && detailMeta[node];
242
+ if (def && def.fields) {
243
+ detailRows[def.subFormId || node] = raw[node].map(function (line) {
244
+ return toFlatRow(line, def.fields);
245
+ });
246
+ }
247
+ });
248
+
249
+ result.details = details;
250
+ result.detailRows = detailRows;
251
+ result.raw = raw;
252
+ return result;
253
+ }
254
+
255
+ function totalOf(inner) {
256
+ if (!inner) return null;
257
+ var candidates = [inner.total, inner.totalCount, inner.recordCount];
258
+ if (inner.pageInfo) candidates.push(inner.pageInfo.total, inner.pageInfo.totalCount);
259
+ for (var i = 0; i < candidates.length; i++) {
260
+ if (candidates[i] !== undefined && candidates[i] !== null) return Number(candidates[i]);
261
+ }
262
+ return null;
263
+ }
264
+
265
+ function createClient(options) {
266
+ var state = {
267
+ objId: String(options.objId),
268
+ appId: options.appId ? String(options.appId) : '',
269
+ fieldsPromise: null,
270
+ formIdPromise: null,
271
+ dsFieldsPromise: null,
272
+ requestKeysPromise: null,
273
+ detailMetaPromise: null,
274
+ optionsCache: {}
275
+ };
276
+
277
+ function fields() {
278
+ if (!state.fieldsPromise) {
279
+ var body = { userid: USER_ID, objId: state.objId };
280
+ if (TENANT_KEY) body.tenantKey = TENANT_KEY;
281
+ state.fieldsPromise = readRequest(API_BASE + '/v1/getFields', {
282
+ method: 'POST',
283
+ headers: headers(state.appId),
284
+ body: JSON.stringify(body)
285
+ }).then(function (res) {
286
+ assertOk(res, '读取字段');
287
+ var mainFields = res.data && res.data.mainFields ? res.data.mainFields : [];
288
+ mainFields.sort(function (a, b) {
289
+ return (Number(a.number) || 0) - (Number(b.number) || 0);
290
+ });
291
+ return mainFields;
292
+ });
293
+ }
294
+ return state.fieldsPromise;
295
+ }
296
+
297
+ function formId() {
298
+ if (!state.formIdPromise) {
299
+ state.formIdPromise = readRequest(
300
+ PUBLIC_URL + '/api/ebuilder/form/obj/getInfo/' + encodeURIComponent(state.objId),
301
+ { method: 'GET', headers: headers(state.appId) }
302
+ ).then(function (res) {
303
+ if (!res || String(res.code) !== '200' || !res.status) {
304
+ throw new Error('读取表单信息失败:' + ((res && res.msg) || '未知错误'));
305
+ }
306
+ return res.data && res.data.formId;
307
+ });
308
+ }
309
+ return state.formIdPromise;
310
+ }
311
+
312
+ function loadOptions(fieldId) {
313
+ var key = String(fieldId);
314
+ if (state.optionsCache[key]) return Promise.resolve(state.optionsCache[key]);
315
+ return formId().then(function (id) {
316
+ if (!id) throw new Error('未读到表单 formId,无法读取字段选项');
317
+ var body = {
318
+ module: 'ebuilderform',
319
+ formTableField: {
320
+ formField: {
321
+ id: String(fieldId),
322
+ form: { id: id }
323
+ }
324
+ }
325
+ };
326
+ return readRequest(PUBLIC_URL + '/api/ebuilder/form/form/field/manage/getFormField', {
327
+ method: 'POST',
328
+ headers: headers(state.appId),
329
+ body: JSON.stringify(body)
330
+ });
331
+ }).then(function (res) {
332
+ assertOk(res, '读取字段选项');
333
+ var rawOptions = (res.data && res.data.options) || [];
334
+ var result = rawOptions.map(function (item) {
335
+ return {
336
+ id: String(item.valueKey),
337
+ valueKey: String(item.valueKey),
338
+ name: item.name
339
+ };
340
+ });
341
+ state.optionsCache[key] = result;
342
+ return result;
343
+ });
344
+ }
345
+
346
+ function dsFields() {
347
+ if (!state.dsFieldsPromise) {
348
+ var form = new FormData();
349
+ form.append('groupId', state.appId || state.objId);
350
+ form.append('sourceId', state.objId);
351
+ form.append('sourceType', 'FORM');
352
+ form.append('detailFieldsGroup', 'true');
353
+ form.append('enableMerge', 'true');
354
+ form.append('customParam', '{"terminal":""}');
355
+ form.append('params', '[]');
356
+ state.dsFieldsPromise = fetch(PUBLIC_URL + '/api/ebuilder/common/ds/fields', {
357
+ method: 'POST',
358
+ headers: multipartHeaders(state.appId),
359
+ body: form
360
+ }).then(parseResponse).then(function (res) {
361
+ assertOk(res, '读取字段定义');
362
+ return Array.isArray(res.data) ? res.data : [];
363
+ });
364
+ }
365
+ return state.dsFieldsPromise;
366
+ }
367
+
368
+ function requestKeys() {
369
+ if (!state.requestKeysPromise) {
370
+ state.requestKeysPromise = dsFields().then(function (groups) {
371
+ var map = {};
372
+ groups.forEach(function (group) {
373
+ (group.fields || []).forEach(function (field) {
374
+ if (field.isDetailtable) return;
375
+ map[String(field.id)] = requestKeyOf(field);
376
+ });
377
+ });
378
+ return map;
379
+ });
380
+ }
381
+ return state.requestKeysPromise;
382
+ }
383
+
384
+ function detailMeta() {
385
+ if (!state.detailMetaPromise) {
386
+ var url = API_BASE + '/v1/getTableMapping?objId=' + encodeURIComponent(state.objId) + '&reverse=false';
387
+ state.detailMetaPromise = Promise.all([
388
+ dsFields(),
389
+ readRequest(url, { method: 'GET', headers: headers(state.appId) })
390
+ ]).then(function (results) {
391
+ var groups = results[0];
392
+ var res = results[1];
393
+ assertOk(res, '读取明细映射');
394
+ var mapping = res.data || {};
395
+ var bySubForm = {};
396
+ groups.forEach(function (group) {
397
+ (group.fields || []).forEach(function (field) {
398
+ if (!field.isDetailtable) return;
399
+ bySubForm[String(field.id)] = {
400
+ subFormId: String(field.id),
401
+ fields: (field.fields || []).map(function (item) {
402
+ return {
403
+ fieldId: String(item.id),
404
+ fieldType: String(item.type || item.compType || ''),
405
+ fieldName: String(item.text || item.name || ''),
406
+ requestKey: requestKeyOf(item)
407
+ };
408
+ })
409
+ };
410
+ });
411
+ });
412
+ var nodes = {};
413
+ Object.keys(mapping).forEach(function (node) {
414
+ if (node === 'mainTable') return;
415
+ var def = bySubForm[String(mapping[node])];
416
+ if (def) nodes[node] = def;
417
+ });
418
+ return nodes;
419
+ });
420
+ }
421
+ return state.detailMetaPromise;
422
+ }
423
+
424
+ function optionId(fieldId, nameOrId) {
425
+ return loadOptions(fieldId).then(function (opts) {
426
+ var key = String(nameOrId);
427
+ var hit = null;
428
+ opts.forEach(function (item) {
429
+ if (!hit && (item.name === key || item.valueKey === key || item.id === key)) hit = item;
430
+ });
431
+ if (!hit) {
432
+ throw new Error('字段 ' + fieldId + ' 没有选项「' + nameOrId + '」,可选:'
433
+ + opts.map(function (item) { return item.name; }).join('、'));
434
+ }
435
+ return hit.valueKey;
436
+ });
437
+ }
438
+
439
+ function optionIds(fieldId, names) {
440
+ var list = Array.isArray(names) ? names : String(names || '').split(/[,,、]/);
441
+ return Promise.all(list.map(function (name) {
442
+ return optionId(fieldId, name);
443
+ })).then(function (ids) {
444
+ return ids.join(',');
445
+ });
446
+ }
447
+
448
+ function optionMap(fieldId) {
449
+ return loadOptions(fieldId).then(function (opts) {
450
+ var map = {};
451
+ opts.forEach(function (item) { map[item.name] = item.valueKey; });
452
+ return map;
453
+ });
454
+ }
455
+
456
+ function toRequestValues(values) {
457
+ return requestKeys().then(function (map) {
458
+ var result = {};
459
+ Object.keys(values || {}).forEach(function (key) {
460
+ var target = map[String(key)] || String(key);
461
+ result[target] = normalizeWriteValue(values[key]);
462
+ });
463
+ return result;
464
+ });
465
+ }
466
+
467
+ function toRequestDetails(details) {
468
+ if (!details) return Promise.resolve(null);
469
+ return detailMeta().then(function (nodes) {
470
+ var lookup = {};
471
+ Object.keys(nodes).forEach(function (node) {
472
+ lookup[node] = node;
473
+ if (nodes[node].subFormId) lookup[nodes[node].subFormId] = node;
474
+ });
475
+ var result = {};
476
+ Object.keys(details).forEach(function (key) {
477
+ var node = lookup[key];
478
+ if (!node) throw new Error('未找到明细节点或 subFormId:' + key);
479
+ var def = nodes[node];
480
+ if (!Array.isArray(details[key])) throw new Error('明细 ' + key + ' 必须是数组');
481
+ var map = {};
482
+ def.fields.forEach(function (field) { map[field.fieldId] = field.requestKey; });
483
+ result[node] = details[key].map(function (row) {
484
+ var out = {};
485
+ Object.keys(row || {}).forEach(function (fieldKey) {
486
+ out[map[String(fieldKey)] || String(fieldKey)] = normalizeWriteValue(row[fieldKey]);
487
+ });
488
+ return out;
489
+ });
490
+ });
491
+ return result;
492
+ });
493
+ }
494
+
495
+ function list(query) {
496
+ query = query || {};
497
+ var datajson = {
498
+ header: { objId: state.objId },
499
+ pageInfo: {
500
+ pageNo: String(query.page || 1),
501
+ pageSize: String(query.size || 1000)
502
+ }
503
+ };
504
+ if (TENANT_KEY) datajson.header.tenantKey = TENANT_KEY;
505
+ if (query.withDetail) datajson.operationinfo = { isReturnDetail: 'y' };
506
+
507
+ var url = API_BASE + '/v2/getAllData';
508
+ if (TENANT_KEY) url += '?tenantkey=' + encodeURIComponent(TENANT_KEY);
509
+
510
+ var request = Promise.resolve(null).then(function () {
511
+ return query.filter ? toRequestValues(query.filter) : null;
512
+ }).then(function (filter) {
513
+ if (filter) datajson.mainTable = filter;
514
+ return readRequest(url, {
515
+ method: 'POST',
516
+ headers: headers(state.appId),
517
+ body: JSON.stringify({ userid: USER_ID, datajson: datajson })
518
+ });
519
+ });
520
+
521
+ var detailPromise = query.withDetail ? detailMeta() : Promise.resolve(null);
522
+
523
+ return Promise.all([fields(), detailPromise, request]).then(function (results) {
524
+ var fieldList = results[0];
525
+ var detail = results[1];
526
+ var res = results[2];
527
+ assertOk(res, '读取数据');
528
+ var inner = innerOf(res) || {};
529
+ var datas = Array.isArray(inner.datas) ? inner.datas : [];
530
+ return {
531
+ rows: datas.map(function (raw) { return toRow(raw, fieldList, detail); }),
532
+ total: totalOf(inner),
533
+ raw: res
534
+ };
535
+ });
536
+ }
537
+
538
+ function get(dataId, query) {
539
+ query = query || {};
540
+ var operationinfo = { fieldNoFindIgnore: 'false' };
541
+ if (query.withDetail) operationinfo.isReturnDetail = 'y';
542
+ var datajson = {
543
+ header: { objId: state.objId },
544
+ mainTable: { id: String(dataId) },
545
+ operationinfo: operationinfo
546
+ };
547
+ if (TENANT_KEY) datajson.header.tenantKey = TENANT_KEY;
548
+
549
+ var detailPromise = query.withDetail ? detailMeta() : Promise.resolve(null);
550
+
551
+ return Promise.all([
552
+ fields(),
553
+ detailPromise,
554
+ readRequest(API_BASE + '/v2/getDataById', {
555
+ method: 'POST',
556
+ headers: headers(state.appId),
557
+ body: JSON.stringify({ userid: USER_ID, datajson: datajson })
558
+ })
559
+ ]).then(function (results) {
560
+ var fieldList = results[0];
561
+ var detail = results[1];
562
+ var res = results[2];
563
+ assertOk(res, '读取数据');
564
+ var inner = innerOf(res) || {};
565
+ var datas = Array.isArray(inner.datas) ? inner.datas : [];
566
+ return datas.length ? toRow(datas[0], fieldList, detail) : null;
567
+ });
568
+ }
569
+
570
+ function save(values, writeOptions) {
571
+ writeOptions = writeOptions || {};
572
+ return Promise.all([
573
+ toRequestValues(values),
574
+ toRequestDetails(writeOptions.details)
575
+ ]).then(function (results) {
576
+ var mainTable = results[0];
577
+ var details = results[1];
578
+ var data = { mainTable: mainTable };
579
+ if (details) {
580
+ Object.keys(details).forEach(function (key) {
581
+ data[key] = details[key];
582
+ });
583
+ }
584
+ var operationinfo = { fieldNoFindIgnore: 'false' };
585
+ if (writeOptions.triggerAction === true) operationinfo.doAction = 'true';
586
+
587
+ var datajson = { header: { objId: state.objId }, datas: [data], operationinfo: operationinfo };
588
+ if (TENANT_KEY) datajson.header.tenantKey = TENANT_KEY;
589
+
590
+ return writeRequest(API_BASE + '/v2/saveFormData', {
591
+ userid: USER_ID,
592
+ datajson: datajson
593
+ }, state.appId).then(function (res) {
594
+ assertOk(res, '保存数据');
595
+ var inner = innerOf(res) || {};
596
+ if (Array.isArray(inner.dataIds)) return String(inner.dataIds[0] || '');
597
+ return String(inner.dataIds || '');
598
+ });
599
+ });
600
+ }
601
+
602
+ function update(dataId, values, writeOptions) {
603
+ writeOptions = writeOptions || {};
604
+ return Promise.all([
605
+ toRequestValues(values),
606
+ toRequestDetails(writeOptions.details)
607
+ ]).then(function (results) {
608
+ var mainTable = results[0];
609
+ var details = results[1];
610
+ mainTable.id = String(dataId);
611
+
612
+ var data = { mainTable: mainTable };
613
+ if (details) {
614
+ Object.keys(details).forEach(function (key) {
615
+ data[key] = details[key];
616
+ });
617
+ }
618
+
619
+ var operationinfo = {
620
+ updateType: 'ids',
621
+ needAdd: 'false',
622
+ fieldNoFindIgnore: 'false'
623
+ };
624
+ if (writeOptions.detailMode === 'cover' && details) {
625
+ var operateType = {};
626
+ Object.keys(details).forEach(function (key) { operateType[key] = 'cover'; });
627
+ if (Object.keys(operateType).length) operationinfo.operateType = operateType;
628
+ }
629
+ if (writeOptions.triggerAction === true) operationinfo.doAction = 'true';
630
+
631
+ var datajson = { header: { objId: state.objId }, datas: [data], operationinfo: operationinfo };
632
+ if (TENANT_KEY) datajson.header.tenantKey = TENANT_KEY;
633
+
634
+ return writeRequest(API_BASE + '/v2/updateFormData', {
635
+ userid: USER_ID,
636
+ datajson: datajson
637
+ }, state.appId).then(function (res) {
638
+ assertOk(res, '更新数据');
639
+ return true;
640
+ });
641
+ });
642
+ }
643
+
644
+ function remove(dataId) {
645
+ var datajson = {
646
+ header: { objId: state.objId },
647
+ mainTable: { id: String(dataId) },
648
+ operationinfo: { fieldNoFindIgnore: 'false' }
649
+ };
650
+ if (TENANT_KEY) datajson.header.tenantKey = TENANT_KEY;
651
+
652
+ return writeRequest(API_BASE + '/v2/deleteData', {
653
+ userid: USER_ID,
654
+ datajson: datajson
655
+ }, state.appId).then(function (res) {
656
+ assertOk(res, '删除数据');
657
+ return true;
658
+ });
659
+ }
660
+
661
+ return {
662
+ objId: state.objId,
663
+ appId: state.appId,
664
+ fields: fields,
665
+ options: loadOptions,
666
+ optionId: optionId,
667
+ optionIds: optionIds,
668
+ optionMap: optionMap,
669
+ list: list,
670
+ get: get,
671
+ save: save,
672
+ update: update,
673
+ remove: remove
674
+ };
675
+ }
676
+
677
+ /**
678
+ * 取得某个表单的数据客户端。同一 objId + appId 只创建一次,字段和选项缓存会复用。
679
+ * 在模块顶层调用一次,不要放在组件 render 里。
680
+ */
681
+ export function formClient(input) {
682
+ var options = typeof input === 'string' ? { objId: input } : (input || {});
683
+ if (!options.objId) {
684
+ throw new Error('formClient 需要 objId,例如 formClient({ objId: OBJ_ID, appId: APP_ID })');
685
+ }
686
+ var key = String(options.objId) + '|' + String(options.appId || '');
687
+ if (!clients[key]) clients[key] = createClient(options);
688
+ return clients[key];
689
+ }