openyida 2026.7.23-1 → 2026.7.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/app/create-form.js +43 -378
- package/lib/app/generate-page.js +1 -42
- package/lib/app/services/form-compiler.js +4 -66
- package/lib/core/locales/en.js +0 -2
- package/lib/core/locales/zh.js +0 -2
- package/package.json +1 -1
- package/yida-skills/SKILL.md +0 -1
- package/yida-skills/skills/yida-app/SKILL.md +0 -1
- package/yida-skills/skills/yida-create-form-page/SKILL.md +0 -10
package/lib/app/create-form.js
CHANGED
|
@@ -95,11 +95,7 @@ function parseOpenOption(inputArgs) {
|
|
|
95
95
|
const OPTION_FIELD_TYPES = ['RadioField', 'SelectField', 'CheckboxField', 'MultiSelectField'];
|
|
96
96
|
|
|
97
97
|
function throwCreateFormError(message, code, details) {
|
|
98
|
-
throw
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function createCreateFormError(message, code, details) {
|
|
102
|
-
return new CliError(message, {
|
|
98
|
+
throw new CliError(message, {
|
|
103
99
|
code: code || 'CREATE_FORM_FAILED',
|
|
104
100
|
details,
|
|
105
101
|
});
|
|
@@ -214,28 +210,6 @@ const FIELD_TYPE_ALIAS = {
|
|
|
214
210
|
serialnumberfield: 'SerialNumberField',
|
|
215
211
|
};
|
|
216
212
|
|
|
217
|
-
const SUPPORTED_BUSINESS_FIELD_TYPES = [
|
|
218
|
-
'TextField',
|
|
219
|
-
'TextareaField',
|
|
220
|
-
'RadioField',
|
|
221
|
-
'SelectField',
|
|
222
|
-
'CheckboxField',
|
|
223
|
-
'MultiSelectField',
|
|
224
|
-
'NumberField',
|
|
225
|
-
'RateField',
|
|
226
|
-
'DateField',
|
|
227
|
-
'CascadeDateField',
|
|
228
|
-
'EmployeeField',
|
|
229
|
-
'DepartmentSelectField',
|
|
230
|
-
'CountrySelectField',
|
|
231
|
-
'AddressField',
|
|
232
|
-
'AttachmentField',
|
|
233
|
-
'ImageField',
|
|
234
|
-
'TableField',
|
|
235
|
-
'AssociationFormField',
|
|
236
|
-
'SerialNumberField',
|
|
237
|
-
];
|
|
238
|
-
|
|
239
213
|
const FORM_PRESENTATION_TYPE_ALIAS = {
|
|
240
214
|
Divider: 'Divider',
|
|
241
215
|
divider: 'Divider',
|
|
@@ -288,28 +262,11 @@ function normalizeComponentAlias(field) {
|
|
|
288
262
|
return String(rawAlias).trim();
|
|
289
263
|
}
|
|
290
264
|
|
|
291
|
-
function readFormDefinitionType(field) {
|
|
292
|
-
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
293
|
-
return '';
|
|
294
|
-
}
|
|
295
|
-
if (field.type !== undefined && field.type !== null && field.type !== '') {
|
|
296
|
-
return String(field.type).trim();
|
|
297
|
-
}
|
|
298
|
-
if (field.componentName !== undefined && field.componentName !== null && field.componentName !== '') {
|
|
299
|
-
return String(field.componentName).trim();
|
|
300
|
-
}
|
|
301
|
-
if (field.componentType !== undefined && field.componentType !== null && field.componentType !== '') {
|
|
302
|
-
return String(field.componentType).trim();
|
|
303
|
-
}
|
|
304
|
-
return '';
|
|
305
|
-
}
|
|
306
|
-
|
|
307
265
|
function normalizeFormDefinitionType(field) {
|
|
308
|
-
|
|
309
|
-
if (!rawType) {
|
|
266
|
+
if (!field || !field.type) {
|
|
310
267
|
return '';
|
|
311
268
|
}
|
|
312
|
-
return FORM_PRESENTATION_TYPE_ALIAS[
|
|
269
|
+
return FORM_PRESENTATION_TYPE_ALIAS[field.type] || FIELD_TYPE_ALIAS[field.type] || field.type;
|
|
313
270
|
}
|
|
314
271
|
|
|
315
272
|
function isFormPresentationComponent(componentName) {
|
|
@@ -320,194 +277,6 @@ function isFormPresentationDefinition(field) {
|
|
|
320
277
|
return isFormPresentationComponent(normalizeFormDefinitionType(field));
|
|
321
278
|
}
|
|
322
279
|
|
|
323
|
-
function isSupportedBusinessFieldType(componentName) {
|
|
324
|
-
return SUPPORTED_BUSINESS_FIELD_TYPES.indexOf(componentName) !== -1;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function getDefinitionDisplayName(field) {
|
|
328
|
-
if (!field || typeof field !== 'object') {
|
|
329
|
-
return '';
|
|
330
|
-
}
|
|
331
|
-
return field.label || field.title || readFormDefinitionType(field) || '';
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
function buildInvalidFieldDefinitionDetails(field, fieldPath, extra) {
|
|
335
|
-
const details = Object.assign({
|
|
336
|
-
path: fieldPath || 'fields',
|
|
337
|
-
label: field && typeof field === 'object' ? field.label : undefined,
|
|
338
|
-
title: field && typeof field === 'object' ? field.title : undefined,
|
|
339
|
-
type: readFormDefinitionType(field),
|
|
340
|
-
}, extra || {});
|
|
341
|
-
Object.keys(details).forEach(function (key) {
|
|
342
|
-
if (details[key] === undefined || details[key] === '') {
|
|
343
|
-
delete details[key];
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
return details;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function throwInvalidFieldDefinition(message, code, field, fieldPath, extra) {
|
|
350
|
-
throwCreateFormError(
|
|
351
|
-
message,
|
|
352
|
-
code || 'CREATE_FORM_INVALID_FIELD_DEFINITION',
|
|
353
|
-
buildInvalidFieldDefinitionDetails(field, fieldPath, extra)
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function validatePlainFieldObject(field, fieldPath) {
|
|
358
|
-
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
359
|
-
throwInvalidFieldDefinition(
|
|
360
|
-
'字段定义必须是对象: ' + fieldPath,
|
|
361
|
-
'CREATE_FORM_INVALID_FIELD_DEFINITION',
|
|
362
|
-
field,
|
|
363
|
-
fieldPath
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function validateContainerChildrenArray(field, fieldPath, componentName) {
|
|
369
|
-
if (field.children === undefined || field.children === null) {
|
|
370
|
-
return [];
|
|
371
|
-
}
|
|
372
|
-
if (!Array.isArray(field.children)) {
|
|
373
|
-
throwInvalidFieldDefinition(
|
|
374
|
-
componentName + '.children 必须是数组: ' + fieldPath,
|
|
375
|
-
'CREATE_FORM_INVALID_CONTAINER_CHILDREN',
|
|
376
|
-
field,
|
|
377
|
-
fieldPath,
|
|
378
|
-
{ componentName }
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
return field.children;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
function validateFieldDefinition(field, fieldPath, options) {
|
|
385
|
-
const validationOptions = options || {};
|
|
386
|
-
validatePlainFieldObject(field, fieldPath);
|
|
387
|
-
|
|
388
|
-
const componentName = normalizeFormDefinitionType(field);
|
|
389
|
-
if (!componentName) {
|
|
390
|
-
throwInvalidFieldDefinition(
|
|
391
|
-
'字段定义缺少 type/componentName/componentType: ' + fieldPath,
|
|
392
|
-
'CREATE_FORM_FIELD_TYPE_MISSING',
|
|
393
|
-
field,
|
|
394
|
-
fieldPath
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (isFormPresentationComponent(componentName)) {
|
|
399
|
-
if (validationOptions.disallowPresentation) {
|
|
400
|
-
throwInvalidFieldDefinition(
|
|
401
|
-
'TableField.children 不支持展示布局组件: ' + componentName,
|
|
402
|
-
'CREATE_FORM_TABLE_CHILD_PRESENTATION_UNSUPPORTED',
|
|
403
|
-
field,
|
|
404
|
-
fieldPath,
|
|
405
|
-
{ componentName }
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
if (componentName === 'Column' && !validationOptions.allowColumn) {
|
|
409
|
-
throwInvalidFieldDefinition(
|
|
410
|
-
'Column 只能作为 ColumnContainer.children 的 Column 对象使用: ' + fieldPath,
|
|
411
|
-
'CREATE_FORM_COLUMN_OUTSIDE_COLUMNS_LAYOUT',
|
|
412
|
-
field,
|
|
413
|
-
fieldPath,
|
|
414
|
-
{ componentName }
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
if (componentName === 'ColumnsLayout') {
|
|
418
|
-
validateColumnsLayoutDefinition(field, fieldPath);
|
|
419
|
-
} else if (componentName === 'PageSection') {
|
|
420
|
-
validateContainerChildrenArray(field, fieldPath, componentName).forEach(function (child, childIndex) {
|
|
421
|
-
validateFieldDefinition(child, fieldPath + '.children[' + childIndex + ']');
|
|
422
|
-
});
|
|
423
|
-
} else if (componentName === 'Column') {
|
|
424
|
-
validateContainerChildrenArray(field, fieldPath, componentName).forEach(function (child, childIndex) {
|
|
425
|
-
validateFieldDefinition(child, fieldPath + '.children[' + childIndex + ']');
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
return componentName;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (!isSupportedBusinessFieldType(componentName)) {
|
|
432
|
-
throwInvalidFieldDefinition(
|
|
433
|
-
'不支持的字段类型: ' + componentName,
|
|
434
|
-
'CREATE_FORM_UNSUPPORTED_FIELD_TYPE',
|
|
435
|
-
field,
|
|
436
|
-
fieldPath,
|
|
437
|
-
{ componentName }
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
if (componentName === 'TableField') {
|
|
442
|
-
validateTableFieldChildren(field, fieldPath, validationOptions);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return componentName;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function validateColumnsLayoutDefinition(field, fieldPath) {
|
|
449
|
-
const columns = validateContainerChildrenArray(field, fieldPath, 'ColumnsLayout');
|
|
450
|
-
columns.forEach(function (columnDefinition, columnIndex) {
|
|
451
|
-
const columnPath = fieldPath + '.children[' + columnIndex + ']';
|
|
452
|
-
if (Array.isArray(columnDefinition)) {
|
|
453
|
-
columnDefinition.forEach(function (child, childIndex) {
|
|
454
|
-
validateFieldDefinition(child, columnPath + '[' + childIndex + ']');
|
|
455
|
-
});
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
if (
|
|
459
|
-
columnDefinition &&
|
|
460
|
-
typeof columnDefinition === 'object' &&
|
|
461
|
-
!Array.isArray(columnDefinition) &&
|
|
462
|
-
normalizeFormDefinitionType(columnDefinition) === 'Column'
|
|
463
|
-
) {
|
|
464
|
-
validateFieldDefinition(columnDefinition, columnPath, { allowColumn: true });
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
|
-
throwInvalidFieldDefinition(
|
|
468
|
-
'ColumnContainer.children 只能包含二维字段数组或 Column 对象: ' + columnPath,
|
|
469
|
-
'CREATE_FORM_INVALID_COLUMNS_LAYOUT_CHILDREN',
|
|
470
|
-
columnDefinition,
|
|
471
|
-
columnPath,
|
|
472
|
-
{ componentName: normalizeFormDefinitionType(columnDefinition) || readFormDefinitionType(columnDefinition) }
|
|
473
|
-
);
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function validateTableFieldChildren(field, fieldPath, options) {
|
|
478
|
-
if (field.children === undefined || field.children === null) {
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
if (!Array.isArray(field.children)) {
|
|
482
|
-
throwInvalidFieldDefinition(
|
|
483
|
-
'TableField.children 必须是字段数组: ' + fieldPath,
|
|
484
|
-
'CREATE_FORM_INVALID_TABLE_CHILDREN',
|
|
485
|
-
field,
|
|
486
|
-
fieldPath,
|
|
487
|
-
{ componentName: 'TableField' }
|
|
488
|
-
);
|
|
489
|
-
}
|
|
490
|
-
field.children.forEach(function (child, childIndex) {
|
|
491
|
-
validateFieldDefinition(child, fieldPath + '.children[' + childIndex + ']', Object.assign({}, options, {
|
|
492
|
-
disallowPresentation: true,
|
|
493
|
-
}));
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
function validateFormFieldDefinitions(fields, rootPath) {
|
|
498
|
-
if (!Array.isArray(fields)) {
|
|
499
|
-
throwInvalidFieldDefinition(
|
|
500
|
-
'字段定义必须是数组',
|
|
501
|
-
'CREATE_FORM_INVALID_FIELD_DEFINITION',
|
|
502
|
-
null,
|
|
503
|
-
rootPath || 'fields'
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
fields.forEach(function (field, index) {
|
|
507
|
-
validateFieldDefinition(field, (rootPath || 'fields') + '[' + index + ']');
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
|
|
511
280
|
function normalizeI18nValue(value, fallback) {
|
|
512
281
|
if (value && typeof value === 'object') {
|
|
513
282
|
return value;
|
|
@@ -696,16 +465,7 @@ function buildFormNodeComponents(fields) {
|
|
|
696
465
|
// ── 生成字段组件 ─────────────────────────────────────
|
|
697
466
|
|
|
698
467
|
function buildFieldComponent(field) {
|
|
699
|
-
const componentName =
|
|
700
|
-
if (!isSupportedBusinessFieldType(componentName)) {
|
|
701
|
-
throwInvalidFieldDefinition(
|
|
702
|
-
componentName ? '不支持的字段类型: ' + componentName : '字段定义缺少 type/componentName/componentType',
|
|
703
|
-
componentName ? 'CREATE_FORM_UNSUPPORTED_FIELD_TYPE' : 'CREATE_FORM_FIELD_TYPE_MISSING',
|
|
704
|
-
field,
|
|
705
|
-
'field',
|
|
706
|
-
{ componentName }
|
|
707
|
-
);
|
|
708
|
-
}
|
|
468
|
+
const componentName = FIELD_TYPE_ALIAS[field.type] || field.type;
|
|
709
469
|
const fieldId = generateFieldId(componentName);
|
|
710
470
|
const nodeId = nextNodeId();
|
|
711
471
|
|
|
@@ -4076,14 +3836,20 @@ function ensureComponentsMapForComponent(schema, component) {
|
|
|
4076
3836
|
}
|
|
4077
3837
|
}
|
|
4078
3838
|
|
|
3839
|
+
function getDefinitionDisplayName(field) {
|
|
3840
|
+
if (!field || typeof field !== 'object') {
|
|
3841
|
+
return '';
|
|
3842
|
+
}
|
|
3843
|
+
return field.label || field.title || field.type || '';
|
|
3844
|
+
}
|
|
3845
|
+
|
|
4079
3846
|
function countDataFieldDefinitions(fields) {
|
|
4080
3847
|
let count = 0;
|
|
4081
3848
|
(fields || []).forEach(function (field) {
|
|
4082
3849
|
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
4083
3850
|
return;
|
|
4084
3851
|
}
|
|
4085
|
-
|
|
4086
|
-
if (isSupportedBusinessFieldType(componentName)) {
|
|
3852
|
+
if (!isFormPresentationDefinition(field)) {
|
|
4087
3853
|
count++;
|
|
4088
3854
|
}
|
|
4089
3855
|
if (Array.isArray(field.children)) {
|
|
@@ -4115,12 +3881,11 @@ function applyChangesToSchema(schema, changes) {
|
|
|
4115
3881
|
const actionDesc = t('create_form.action_label', changeIndex + 1, change.action);
|
|
4116
3882
|
|
|
4117
3883
|
if (change.action === 'add') {
|
|
4118
|
-
if (!change.field || !
|
|
3884
|
+
if (!change.field || !change.field.type || (!change.field.label && !change.field.title && !isFormPresentationDefinition(change.field))) {
|
|
4119
3885
|
warn(actionDesc + t('create_form.add_missing_field'));
|
|
4120
3886
|
return;
|
|
4121
3887
|
}
|
|
4122
3888
|
|
|
4123
|
-
validateFormFieldDefinitions([change.field], 'changes[' + changeIndex + '].field');
|
|
4124
3889
|
const newComponent = buildFormNodeComponent(change.field);
|
|
4125
3890
|
ensureComponentsMapForComponent(schema, newComponent);
|
|
4126
3891
|
const displayName = getDefinitionDisplayName(change.field);
|
|
@@ -4292,54 +4057,12 @@ function requireSchemaServerRevision(serverRevision, details) {
|
|
|
4292
4057
|
return serverRevision;
|
|
4293
4058
|
}
|
|
4294
4059
|
|
|
4295
|
-
function sanitizeFailureResult(result) {
|
|
4296
|
-
if (!result || typeof result !== 'object') {
|
|
4297
|
-
return result || null;
|
|
4298
|
-
}
|
|
4299
|
-
const sanitized = {};
|
|
4300
|
-
['success', 'errorMsg', 'errorCode', 'code', 'message', '__httpStatus', '__needLogin', '__csrfExpired'].forEach(function (key) {
|
|
4301
|
-
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
4302
|
-
sanitized[key] = result[key];
|
|
4303
|
-
}
|
|
4304
|
-
});
|
|
4305
|
-
return sanitized;
|
|
4306
|
-
}
|
|
4307
|
-
|
|
4308
|
-
function buildCreateFormPostCreateFailurePayload(context) {
|
|
4309
|
-
const errorObject = context && context.error;
|
|
4310
|
-
const payload = {
|
|
4311
|
-
success: false,
|
|
4312
|
-
appType: context.appType,
|
|
4313
|
-
formTitle: context.formTitle,
|
|
4314
|
-
formUuid: context.formUuid,
|
|
4315
|
-
stage: context.stage || 'postCreate',
|
|
4316
|
-
error: errorObject && errorObject.message ? errorObject.message : String(errorObject || 'request failed'),
|
|
4317
|
-
errorCode: errorObject && errorObject.code ? errorObject.code : (context.errorCode || 'CREATE_FORM_POST_CREATE_FAILED'),
|
|
4318
|
-
retryAdvice: t('create_form.create_post_failure_retry_advice', context.appType, context.formTitle),
|
|
4319
|
-
};
|
|
4320
|
-
if (context.fieldCount !== undefined) {
|
|
4321
|
-
payload.fieldCount = context.fieldCount;
|
|
4322
|
-
}
|
|
4323
|
-
return payload;
|
|
4324
|
-
}
|
|
4325
|
-
|
|
4326
|
-
function emitCreateFormPostCreateFailure(context) {
|
|
4327
|
-
const errorObject = context && context.error;
|
|
4328
|
-
if (errorObject && errorObject.__openyidaPostCreateFailureEmitted) {
|
|
4329
|
-
return;
|
|
4330
|
-
}
|
|
4331
|
-
console.log(JSON.stringify(buildCreateFormPostCreateFailurePayload(context)));
|
|
4332
|
-
if (errorObject && typeof errorObject === 'object') {
|
|
4333
|
-
errorObject.__openyidaPostCreateFailureEmitted = true;
|
|
4334
|
-
}
|
|
4335
|
-
}
|
|
4336
|
-
|
|
4337
4060
|
// ── 保存 Schema 并更新表单配置(create/update 共用)──
|
|
4338
4061
|
//
|
|
4339
4062
|
// 封装了 saveFormSchema + updateFormConfig 两步,以及各自的 302 自动重登录重试。
|
|
4340
4063
|
// 返回 { saveResult, configResult }。
|
|
4341
4064
|
|
|
4342
|
-
async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, version, stepOffset
|
|
4065
|
+
async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, version, stepOffset) {
|
|
4343
4066
|
const saveStep = stepOffset || 4;
|
|
4344
4067
|
const configStep = saveStep + 1;
|
|
4345
4068
|
|
|
@@ -4369,20 +4092,12 @@ async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, ver
|
|
|
4369
4092
|
if (saveResult && !saveResult.__needLogin) {
|
|
4370
4093
|
hint(t('common.response_detail', JSON.stringify(saveResult, null, 2)));
|
|
4371
4094
|
}
|
|
4372
|
-
|
|
4095
|
+
console.log(JSON.stringify({ success: false, formUuid: formUuid, error: saveErrorMsg }));
|
|
4096
|
+
throwCreateFormError(saveErrorMsg, 'CREATE_FORM_SAVE_SCHEMA_FAILED', {
|
|
4373
4097
|
appType,
|
|
4374
4098
|
formUuid,
|
|
4375
|
-
result:
|
|
4099
|
+
result: saveResult,
|
|
4376
4100
|
});
|
|
4377
|
-
if (failureContext) {
|
|
4378
|
-
emitCreateFormPostCreateFailure(Object.assign({}, failureContext, {
|
|
4379
|
-
stage: 'saveFormSchema',
|
|
4380
|
-
error: saveError,
|
|
4381
|
-
}));
|
|
4382
|
-
} else {
|
|
4383
|
-
console.log(JSON.stringify({ success: false, formUuid: formUuid, error: saveErrorMsg }));
|
|
4384
|
-
}
|
|
4385
|
-
throw saveError;
|
|
4386
4101
|
}
|
|
4387
4102
|
|
|
4388
4103
|
success(t('create_form.schema_saved'));
|
|
@@ -4412,7 +4127,6 @@ async function mainCreate(parsedArgs, authRef) {
|
|
|
4412
4127
|
|
|
4413
4128
|
step(2, t('create_form.step_read_fields', 2));
|
|
4414
4129
|
const { fields, columns, validations } = readFieldsDefinition(fieldsJsonOrFile);
|
|
4415
|
-
validateFormFieldDefinitions(fields);
|
|
4416
4130
|
const fieldCount = countDataFieldDefinitions(fields);
|
|
4417
4131
|
success(t('create_form.fields_loaded', fieldCount));
|
|
4418
4132
|
label('Columns:', String(columns));
|
|
@@ -4444,62 +4158,30 @@ async function mainCreate(parsedArgs, authRef) {
|
|
|
4444
4158
|
|
|
4445
4159
|
const formUuid = createResult.content.formUuid || createResult.content;
|
|
4446
4160
|
success(t('create_form.blank_created', formUuid));
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
);
|
|
4456
|
-
}, authRef);
|
|
4457
|
-
if (!shellSchemaResult || shellSchemaResult.success === false || shellSchemaResult.__needLogin || shellSchemaResult.__csrfExpired) {
|
|
4458
|
-
const schemaErrorMsg = shellSchemaResult
|
|
4459
|
-
? shellSchemaResult.errorMsg || shellSchemaResult.message || t('common.unknown_error')
|
|
4460
|
-
: t('common.request_failed');
|
|
4461
|
-
throwCreateFormError(schemaErrorMsg, 'CREATE_FORM_GET_SCHEMA_FAILED', {
|
|
4462
|
-
appType,
|
|
4463
|
-
formUuid,
|
|
4464
|
-
result: sanitizeFailureResult(shellSchemaResult),
|
|
4465
|
-
});
|
|
4466
|
-
}
|
|
4467
|
-
const serverRevision = extractSchemaServerRevision(shellSchemaResult);
|
|
4161
|
+
const shellSchemaResult = await requestWithAutoLogin(function (auth) {
|
|
4162
|
+
return sendGetRequest(
|
|
4163
|
+
auth.baseUrl,
|
|
4164
|
+
buildApiPath(appType, 'getFormSchema', { prefix: '_view', namespace: 'alibaba' }),
|
|
4165
|
+
{ formUuid: formUuid, schemaVersion: 'V5' }
|
|
4166
|
+
);
|
|
4167
|
+
}, authRef);
|
|
4168
|
+
const serverRevision = extractSchemaServerRevision(shellSchemaResult);
|
|
4468
4169
|
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4170
|
+
// Step 4 & 5: 生成 Schema 并保存,然后更新表单配置
|
|
4171
|
+
const corpId = resolveCorpId(authRef.authData);
|
|
4172
|
+
if (!corpId) {
|
|
4173
|
+
warn(t('create_form.no_corp_id_warning'));
|
|
4174
|
+
} else {
|
|
4175
|
+
info(t('create_form.corp_id_ok', corpId));
|
|
4176
|
+
}
|
|
4476
4177
|
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
info('已为创建表单写入 ' + appliedValidations.appliedRules.length + ' 条字段校验');
|
|
4483
|
-
}
|
|
4484
|
-
postCreateStage = 'saveSchemaAndUpdateConfig';
|
|
4485
|
-
const saveAndConfigResult = await saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, serverRevision, 4, {
|
|
4486
|
-
appType,
|
|
4487
|
-
formTitle,
|
|
4488
|
-
formUuid,
|
|
4489
|
-
fieldCount,
|
|
4490
|
-
});
|
|
4491
|
-
configResult = saveAndConfigResult.configResult;
|
|
4492
|
-
} catch (err) {
|
|
4493
|
-
emitCreateFormPostCreateFailure({
|
|
4494
|
-
appType,
|
|
4495
|
-
formTitle,
|
|
4496
|
-
formUuid,
|
|
4497
|
-
fieldCount,
|
|
4498
|
-
stage: postCreateStage,
|
|
4499
|
-
error: err,
|
|
4500
|
-
});
|
|
4501
|
-
throw err;
|
|
4178
|
+
const schema = buildFormSchema(formTitle, fields, formUuid, corpId, appType, layout, theme, labelAlign);
|
|
4179
|
+
const createValidationRules = collectSmartValidationRulesFromFields(fields).concat(validations || []);
|
|
4180
|
+
if (createValidationRules.length > 0) {
|
|
4181
|
+
const appliedValidations = applySmartValidations(schema, createValidationRules);
|
|
4182
|
+
info('已为创建表单写入 ' + appliedValidations.appliedRules.length + ' 条字段校验');
|
|
4502
4183
|
}
|
|
4184
|
+
const { configResult } = await saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, serverRevision, 4);
|
|
4503
4185
|
|
|
4504
4186
|
// 输出结果
|
|
4505
4187
|
const formUrl = authRef.baseUrl + '/' + appType + '/workbench/' + formUuid;
|
|
@@ -4521,25 +4203,11 @@ async function mainCreate(parsedArgs, authRef) {
|
|
|
4521
4203
|
['URL', formUrl],
|
|
4522
4204
|
]);
|
|
4523
4205
|
hint(t('create_form.schema_ok_config_failed'));
|
|
4524
|
-
|
|
4525
|
-
appType,
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
console.log(JSON.stringify(Object.assign(
|
|
4530
|
-
buildCreateFormPostCreateFailurePayload({
|
|
4531
|
-
appType,
|
|
4532
|
-
formTitle,
|
|
4533
|
-
formUuid,
|
|
4534
|
-
fieldCount,
|
|
4535
|
-
stage: 'updateFormConfig',
|
|
4536
|
-
error: configError,
|
|
4537
|
-
}),
|
|
4538
|
-
{
|
|
4539
|
-
url: formUrl,
|
|
4540
|
-
schemaSaved: true,
|
|
4541
|
-
configWarning: configErrorMsg,
|
|
4542
|
-
}
|
|
4206
|
+
console.log(JSON.stringify(withBrowserHandoff(
|
|
4207
|
+
{ success: true, formUuid, formTitle, appType, fieldCount, url: formUrl, configWarning: configErrorMsg },
|
|
4208
|
+
formUrl,
|
|
4209
|
+
{ stage: 'create_form_success', title: formTitle },
|
|
4210
|
+
parsedArgs.browserOpenMode
|
|
4543
4211
|
)));
|
|
4544
4212
|
}
|
|
4545
4213
|
}
|
|
@@ -4560,7 +4228,6 @@ async function createFormForLegacyProcess(context, input) {
|
|
|
4560
4228
|
|
|
4561
4229
|
const { appType, formTitle, fieldsJsonOrFile, layout, theme, labelAlign } = parsedArgs;
|
|
4562
4230
|
const { fields, validations } = readFieldsDefinition(fieldsJsonOrFile);
|
|
4563
|
-
validateFormFieldDefinitions(fields);
|
|
4564
4231
|
const fieldCount = countDataFieldDefinitions(fields);
|
|
4565
4232
|
const createResult = await requestWithAutoLogin(function (auth) {
|
|
4566
4233
|
return sendPostRequest(
|
|
@@ -5526,8 +5193,6 @@ module.exports = {
|
|
|
5526
5193
|
buildFormNodeComponent,
|
|
5527
5194
|
countDataFieldDefinitions,
|
|
5528
5195
|
collectComponentNames,
|
|
5529
|
-
normalizeFormDefinitionType,
|
|
5530
|
-
validateFormFieldDefinitions,
|
|
5531
5196
|
ensureDividerThemeAction,
|
|
5532
5197
|
applyChangesToSchema,
|
|
5533
5198
|
},
|
package/lib/app/generate-page.js
CHANGED
|
@@ -514,40 +514,6 @@ function getCanvasDistPath(outputPath) {
|
|
|
514
514
|
return path.posix.join(distDir, distName);
|
|
515
515
|
}
|
|
516
516
|
|
|
517
|
-
function isOpenYidaProjectCwd(cwd) {
|
|
518
|
-
const currentDir = cwd || process.cwd();
|
|
519
|
-
return path.basename(currentDir) === 'project' && (
|
|
520
|
-
fs.existsSync(path.join(currentDir, 'config.json')) ||
|
|
521
|
-
fs.existsSync(path.join(currentDir, 'pages'))
|
|
522
|
-
);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
function normalizeOutputPathForProjectCwd(output, options = {}) {
|
|
526
|
-
const cwd = options.cwd || process.cwd();
|
|
527
|
-
const rawOutput = String(output || '');
|
|
528
|
-
if (!rawOutput || path.isAbsolute(rawOutput)) {
|
|
529
|
-
return {
|
|
530
|
-
outputPath: path.resolve(cwd, rawOutput),
|
|
531
|
-
strippedProjectPrefix: false,
|
|
532
|
-
requestedOutput: rawOutput,
|
|
533
|
-
normalizedOutput: rawOutput,
|
|
534
|
-
};
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const slashOutput = rawOutput.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
538
|
-
const shouldStrip = isOpenYidaProjectCwd(cwd) && (
|
|
539
|
-
slashOutput.startsWith('project/pages/') ||
|
|
540
|
-
slashOutput.startsWith('project/.cache/')
|
|
541
|
-
);
|
|
542
|
-
const normalizedOutput = shouldStrip ? slashOutput.slice('project/'.length) : rawOutput;
|
|
543
|
-
return {
|
|
544
|
-
outputPath: path.resolve(cwd, normalizedOutput),
|
|
545
|
-
strippedProjectPrefix: shouldStrip,
|
|
546
|
-
requestedOutput: rawOutput,
|
|
547
|
-
normalizedOutput,
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
|
|
551
517
|
async function run(args) {
|
|
552
518
|
const options = parseArgs(args || []);
|
|
553
519
|
const spec = loadSpec(options.spec);
|
|
@@ -567,10 +533,7 @@ async function run(args) {
|
|
|
567
533
|
error(t('generate_page.template_not_found', templateFile));
|
|
568
534
|
}
|
|
569
535
|
|
|
570
|
-
const
|
|
571
|
-
options.output || spec.output || (mode === 'canvas' ? templateConfig.defaultCanvasOutput : templateConfig.defaultNativeOutput)
|
|
572
|
-
);
|
|
573
|
-
const outputPath = outputResolution.outputPath;
|
|
536
|
+
const outputPath = path.resolve(options.output || spec.output || (mode === 'canvas' ? templateConfig.defaultCanvasOutput : templateConfig.defaultNativeOutput));
|
|
574
537
|
const manifestPath = getManifestPath(outputPath);
|
|
575
538
|
const templateSource = fs.readFileSync(templateFile, 'utf-8');
|
|
576
539
|
const ir = normalizePageSpec(spec, {
|
|
@@ -598,9 +561,6 @@ async function run(args) {
|
|
|
598
561
|
fs.writeFileSync(outputPath, outputSource, 'utf-8');
|
|
599
562
|
fs.writeFileSync(manifestPath, `${JSON.stringify(ir, null, 2)}\n`, 'utf-8');
|
|
600
563
|
|
|
601
|
-
if (outputResolution.strippedProjectPrefix) {
|
|
602
|
-
warn(t('generate_page.output_project_prefix_stripped', outputResolution.requestedOutput, outputResolution.normalizedOutput));
|
|
603
|
-
}
|
|
604
564
|
success(t('generate_page.done', outputPath));
|
|
605
565
|
hint(t('generate_page.hint'));
|
|
606
566
|
reportMaterialStatus(materialPrecheck);
|
|
@@ -681,7 +641,6 @@ module.exports = {
|
|
|
681
641
|
escapeJsStringValue,
|
|
682
642
|
getManifestPath,
|
|
683
643
|
getCanvasDistPath,
|
|
684
|
-
normalizeOutputPathForProjectCwd,
|
|
685
644
|
inferMode,
|
|
686
645
|
inferTemplateName,
|
|
687
646
|
};
|
|
@@ -509,9 +509,6 @@ const SUPPORTED_FIELD_TYPES = Object.freeze([
|
|
|
509
509
|
]);
|
|
510
510
|
|
|
511
511
|
function normalizeFieldType(fieldType) {
|
|
512
|
-
if (fieldType === undefined || fieldType === null || fieldType === '') {
|
|
513
|
-
return '';
|
|
514
|
-
}
|
|
515
512
|
return FIELD_TYPE_ALIAS[fieldType] || fieldType;
|
|
516
513
|
}
|
|
517
514
|
|
|
@@ -523,57 +520,6 @@ function isOptionFieldType(fieldType) {
|
|
|
523
520
|
return OPTION_FIELD_TYPES.indexOf(normalizeFieldType(fieldType)) !== -1;
|
|
524
521
|
}
|
|
525
522
|
|
|
526
|
-
function readFieldDefinitionType(field) {
|
|
527
|
-
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
528
|
-
return '';
|
|
529
|
-
}
|
|
530
|
-
if (field.type !== undefined && field.type !== null && field.type !== '') {
|
|
531
|
-
return String(field.type).trim();
|
|
532
|
-
}
|
|
533
|
-
if (field.componentType !== undefined && field.componentType !== null && field.componentType !== '') {
|
|
534
|
-
return String(field.componentType).trim();
|
|
535
|
-
}
|
|
536
|
-
if (field.componentName !== undefined && field.componentName !== null && field.componentName !== '') {
|
|
537
|
-
return String(field.componentName).trim();
|
|
538
|
-
}
|
|
539
|
-
return '';
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
function assertSupportedFieldDefinition(field, details) {
|
|
543
|
-
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
544
|
-
throw createFormCompilerError(
|
|
545
|
-
'字段定义必须是对象',
|
|
546
|
-
'FORM_COMPILER_INVALID_DEFINITION',
|
|
547
|
-
details
|
|
548
|
-
);
|
|
549
|
-
}
|
|
550
|
-
const rawType = readFieldDefinitionType(field);
|
|
551
|
-
const componentName = normalizeFieldType(rawType);
|
|
552
|
-
if (!componentName) {
|
|
553
|
-
throw createFormCompilerError(
|
|
554
|
-
'字段定义缺少 type/componentType/componentName',
|
|
555
|
-
'FORM_COMPILER_FIELD_TYPE_MISSING',
|
|
556
|
-
Object.assign({
|
|
557
|
-
label: field.label,
|
|
558
|
-
title: field.title,
|
|
559
|
-
}, details)
|
|
560
|
-
);
|
|
561
|
-
}
|
|
562
|
-
if (!isSupportedFieldType(componentName)) {
|
|
563
|
-
throw createFormCompilerError(
|
|
564
|
-
'不支持的字段类型: ' + componentName,
|
|
565
|
-
'FORM_COMPILER_UNSUPPORTED_FIELD_TYPE',
|
|
566
|
-
Object.assign({
|
|
567
|
-
label: field.label,
|
|
568
|
-
title: field.title,
|
|
569
|
-
type: rawType,
|
|
570
|
-
componentName,
|
|
571
|
-
}, details)
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
return componentName;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
523
|
const COMPONENT_ALIAS_META = Symbol('openyida.componentAlias');
|
|
578
524
|
|
|
579
525
|
function normalizeComponentAlias(field) {
|
|
@@ -598,9 +544,7 @@ function normalizeComponentAlias(field) {
|
|
|
598
544
|
|
|
599
545
|
function buildFieldComponent(field, options) {
|
|
600
546
|
const compilerOptions = createCompilerOptions(options);
|
|
601
|
-
const componentName =
|
|
602
|
-
semanticPath: compilerOptions.semanticPath,
|
|
603
|
-
});
|
|
547
|
+
const componentName = normalizeFieldType(field.type);
|
|
604
548
|
const semanticKey = normalizeSemanticKey(field);
|
|
605
549
|
if (semanticKey && compilerOptions.requireParentSemanticPath && !compilerOptions.semanticPath) {
|
|
606
550
|
throw createFormCompilerError(
|
|
@@ -1195,16 +1139,10 @@ function buildFieldComponent(field, options) {
|
|
|
1195
1139
|
function collectComponentNames(fields) {
|
|
1196
1140
|
const names = new Set(['Page', 'RootHeader', 'RootContent', 'RootFooter', 'FooterYida', 'FormContainer']);
|
|
1197
1141
|
fields.forEach(function (field) {
|
|
1198
|
-
|
|
1199
|
-
if (
|
|
1200
|
-
names.add(componentName);
|
|
1201
|
-
}
|
|
1202
|
-
if (componentName === 'TableField' && field.children) {
|
|
1142
|
+
names.add(field.type);
|
|
1143
|
+
if (field.type === 'TableField' && field.children) {
|
|
1203
1144
|
field.children.forEach(function (child) {
|
|
1204
|
-
|
|
1205
|
-
if (childComponentName) {
|
|
1206
|
-
names.add(childComponentName);
|
|
1207
|
-
}
|
|
1145
|
+
names.add(child.type);
|
|
1208
1146
|
});
|
|
1209
1147
|
}
|
|
1210
1148
|
});
|
package/lib/core/locales/en.js
CHANGED
|
@@ -721,7 +721,6 @@ Examples:
|
|
|
721
721
|
config_failed: ' ⚠️ Config update failed: {0}',
|
|
722
722
|
schema_ok_config_failed: ' Schema saved, but config update failed',
|
|
723
723
|
schema_saved_config_failed: ' Schema saved, but config update failed',
|
|
724
|
-
create_post_failure_retry_advice: 'Do not repeat create directly. First run openyida list-forms {0} --keyword "{1}" to check for an existing same-title form; if this run already created a blank/existing form, prefer create-form update or a future --resume-form-uuid flow.',
|
|
725
724
|
error: '\n❌ Error: {0}',
|
|
726
725
|
usage_create: 'Usage: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
|
|
727
726
|
example_create: 'Example: openyida create-form create "APP_XXX" "Employee Info" .cache/openyida/forms/employee-fields.json',
|
|
@@ -1074,7 +1073,6 @@ Examples:
|
|
|
1074
1073
|
unknown_template: 'Unknown page template: {0}',
|
|
1075
1074
|
available_templates: 'Available templates: {0}',
|
|
1076
1075
|
template_not_found: 'Template file not found: {0}',
|
|
1077
|
-
output_project_prefix_stripped: 'Current directory is already an OpenYida project; output path was adjusted from {0} to {1} to avoid project/project.',
|
|
1078
1076
|
done: 'Page generated: {0}',
|
|
1079
1077
|
hint: 'Next run openyida compile <file>, or pass --compile to compile immediately.',
|
|
1080
1078
|
success: 'Page generation complete',
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -693,7 +693,6 @@ openyida - 宜搭命令行工具
|
|
|
693
693
|
config_failed: ' ⚠️ 配置更新失败: {0}',
|
|
694
694
|
schema_ok_config_failed: ' Schema 已保存,但配置更新失败',
|
|
695
695
|
schema_saved_config_failed: ' Schema 已保存,但配置更新失败',
|
|
696
|
-
create_post_failure_retry_advice: '不要直接重复 create。先运行 openyida list-forms {0} --keyword "{1}" 确认同名表单;若是本轮创建的空白/已有表单,优先使用 create-form update 或后续 --resume-form-uuid 复用。',
|
|
697
696
|
error: '\n❌ 错误: {0}',
|
|
698
697
|
usage_create: '用法: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
|
|
699
698
|
example_create: '示例:openyida create-form create "APP_XXX" "员工信息登记" .cache/openyida/forms/employee-fields.json',
|
|
@@ -1068,7 +1067,6 @@ openyida - 宜搭命令行工具
|
|
|
1068
1067
|
unknown_template: '未知页面模板:{0}',
|
|
1069
1068
|
available_templates: '可用模板:{0}',
|
|
1070
1069
|
template_not_found: '模板文件不存在:{0}',
|
|
1071
|
-
output_project_prefix_stripped: '检测到当前目录已是 OpenYida project,已将输出路径从 {0} 调整为 {1},避免生成 project/project。',
|
|
1072
1070
|
done: '页面已生成:{0}',
|
|
1073
1071
|
hint: '建议继续运行 openyida compile <file> 或使用 --compile 直接编译校验。',
|
|
1074
1072
|
success: '页面生成完成',
|
package/package.json
CHANGED
package/yida-skills/SKILL.md
CHANGED
|
@@ -231,7 +231,6 @@ schema-managed create/update 必须等待用户对当前 `planId` 显式批准
|
|
|
231
231
|
4. **页面源码修改必须发布闭环**:只要本轮 Write/Edit/Create 了页面源码 `project/pages/src/*.{canvas.jsx,canvas.tsx,oyd.jsx,jsx,tsx}`(含完整搭建、补齐、已有页面 update path、单点优化),final 前必须看到成功的 `openyida publish <source> <appType> <displayPageFormUuid>` 命令结果;本地文件编辑、diff、本地校验或编译只证明源码可发布,不等于远端页面已更新。若没有 publish 成功证据,final 只能说“源码已修改,尚未发布”,禁止说“页面已更新 / 已重新发布 / 已上线”。
|
|
232
232
|
5. **命令输入文件禁止 shell 写入**:当 OpenYida 命令需要 JSON/YAML/CSV/config/script 文件参数时,先使用当前 agent 运行时提供的结构化文件写入工具(如 create_file / Write / file edit tool)创建文件,再把路径传给命令;禁止用 shell heredoc、`cat`/`echo`/`printf`/`tee` 加输出重定向,或把命令 stdout 重定向成业务文件。
|
|
233
233
|
6. **读文件少用 Bash 噪声**:读取或定位 workspace 文件优先用宿主的 Read / Glob / Grep;OpenYida CLI 已返回成功 JSON、URL 或 `formUuid/appType` 时,不要再用 Bash `cat`/`ls` 做无意义复核。
|
|
234
|
-
7. **OpenYida CLI 不吞诊断**:不要给 `openyida` 命令加 `2>/dev/null`;失败时保留 stdout/stderr(必要时用 `2>&1` 合并诊断)。遇到 DENIED 或同一命令重复失败,先换策略、改输入或重做只读确认,不要盲目微调后重跑。
|
|
235
234
|
|
|
236
235
|
### 重要规则(IMPORTANT,影响质量/性能/可维护性)
|
|
237
236
|
|
|
@@ -279,7 +279,6 @@ UI 不是独立替代主流程的步骤,而是按模式插入到页面生成
|
|
|
279
279
|
## 错误处理
|
|
280
280
|
|
|
281
281
|
- 不编造 `appType`、`formUuid`、`fieldId`、`reportId`。
|
|
282
|
-
- OpenYida CLI 不要加 `2>/dev/null`;失败时保留 stdout/stderr 诊断。遇到 DENIED 或同一命令重复失败,先换策略、修改输入文件/参数/登录态/组织或重新只读取证,再重试。
|
|
283
282
|
- 同一命令失败后,必须改变登录态、组织、参数、输入文件或字段 ID 后才能重试;禁止无修改连续重试。
|
|
284
283
|
- corpId 与目标组织不一致时先停下,让用户选择重新登录或在当前组织继续。
|
|
285
284
|
- 已有目标 app/page/form/process 时默认复用;只有用户明确要求新建另一个同类资源,或目标缺失且本次意图允许创建时,才加载 create 类子技能。
|
|
@@ -24,7 +24,6 @@ description: 表单页面创建与更新,支持 19 种业务字段和 Divider
|
|
|
24
24
|
- 不要在 update / patch / rule / validation / bind-datasource 模式中使用猜测的 fieldId,必须先用 `yida-get-schema` 获取
|
|
25
25
|
- 不要用此命令操作数据记录(增删改查),应使用 `yida-data-management`
|
|
26
26
|
- 不要用 shell heredoc、`cat`/`echo`/`printf`/`tee` 或重定向生成字段、变更、补丁、规则、数据源 JSON 文件
|
|
27
|
-
- OpenYida CLI 不要加 `2>/dev/null`;失败时保留 stdout/stderr 诊断,遇到 DENIED 或重复失败必须换策略
|
|
28
27
|
- 已有目标表单且用户是改字段/联动/属性时,不要创建新表单;必须走 update/patch/rule/bind-datasource。
|
|
29
28
|
- 不要用 `GroupContainer` / `PageSection` 承载普通业务分组;普通分组必须优先用 `Divider`
|
|
30
29
|
|
|
@@ -121,15 +120,6 @@ openyida create-form create <appType> <formTitle> <fieldsJsonOrFile> [--layout d
|
|
|
121
120
|
{"success":true,"formUuid":"FORM-XXX","formTitle":"用户信息表","appType":"APP_xxx","fieldCount":4,"url":"{base_url}/APP_xxx/workbench/FORM-XXX"}
|
|
122
121
|
```
|
|
123
122
|
|
|
124
|
-
### create 失败恢复决策树
|
|
125
|
-
|
|
126
|
-
create 命令失败后,不要立刻重复同一条 create:
|
|
127
|
-
|
|
128
|
-
1. 先确认字段 JSON 文件存在,且内容是结构化写入后的最终字段数组/对象,不是半截 JSON、update changes 或 shell 拼接残留。
|
|
129
|
-
2. 运行 `openyida list-forms <appType> --keyword "<表单名>"` 查同名表单;若本轮刚创建过空白表单或已有同名目标表单,优先走 `create-form update` / `patch` / 后续显式 resume 能力复用,不再 create。
|
|
130
|
-
3. 只有确认远端没有同名目标表单,并且已经修改输入文件、参数、登录态或组织后,才重试 create。
|
|
131
|
-
4. 同一 create 命令最多重试 2 次;仍失败时停止并带上完整 stdout/stderr、字段文件路径、appType、表单名和已发现的 formUuid 给用户。
|
|
132
|
-
|
|
133
123
|
## update 模式
|
|
134
124
|
|
|
135
125
|
已有 `formUuid` / 表单 URL / bound form 时优先使用本模式;修改字段前必须用 `openyida get-schema` 确认字段 ID 和当前结构。
|