openyida 2026.7.21 → 2026.7.23-1
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/bin/yida.js +29 -2
- package/lib/app/canvas-compile.js +44 -12
- package/lib/app/create-form/definition-reader.js +22 -2
- package/lib/app/create-form.js +378 -43
- package/lib/app/generate-page.js +42 -1
- package/lib/app/publish.js +27 -0
- package/lib/app/services/form-compiler.js +66 -4
- package/lib/core/agent-capabilities.js +258 -0
- package/lib/core/command-manifest.js +236 -0
- package/lib/core/locales/en.js +11 -0
- package/lib/core/locales/zh.js +11 -0
- package/package.json +1 -1
- package/scripts/postinstall.js +4 -0
- package/scripts/validate-command-manifest.js +72 -0
- package/yida-skills/SKILL.md +12 -5
- package/yida-skills/references/setup-and-env.md +12 -10
- package/yida-skills/skills/yida-app/SKILL.md +24 -3
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +9 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/dependencies-and-cdn.md +5 -1
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +2 -0
- package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +1 -0
- package/yida-skills/skills/yida-create-form-page/SKILL.md +10 -0
- package/yida-skills/skills/yida-custom-page/SKILL.md +3 -0
- package/yida-skills/skills/yida-get-schema/SKILL.md +8 -2
- package/yida-skills/skills/yida-login/SKILL.md +9 -7
- package/yida-skills/skills/yida-publish-page/SKILL.md +3 -1
- package/yida-skills/skills-index.json +1 -1
package/lib/app/create-form.js
CHANGED
|
@@ -95,7 +95,11 @@ function parseOpenOption(inputArgs) {
|
|
|
95
95
|
const OPTION_FIELD_TYPES = ['RadioField', 'SelectField', 'CheckboxField', 'MultiSelectField'];
|
|
96
96
|
|
|
97
97
|
function throwCreateFormError(message, code, details) {
|
|
98
|
-
throw
|
|
98
|
+
throw createCreateFormError(message, code, details);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createCreateFormError(message, code, details) {
|
|
102
|
+
return new CliError(message, {
|
|
99
103
|
code: code || 'CREATE_FORM_FAILED',
|
|
100
104
|
details,
|
|
101
105
|
});
|
|
@@ -210,6 +214,28 @@ const FIELD_TYPE_ALIAS = {
|
|
|
210
214
|
serialnumberfield: 'SerialNumberField',
|
|
211
215
|
};
|
|
212
216
|
|
|
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
|
+
|
|
213
239
|
const FORM_PRESENTATION_TYPE_ALIAS = {
|
|
214
240
|
Divider: 'Divider',
|
|
215
241
|
divider: 'Divider',
|
|
@@ -262,11 +288,28 @@ function normalizeComponentAlias(field) {
|
|
|
262
288
|
return String(rawAlias).trim();
|
|
263
289
|
}
|
|
264
290
|
|
|
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
|
+
|
|
265
307
|
function normalizeFormDefinitionType(field) {
|
|
266
|
-
|
|
308
|
+
const rawType = readFormDefinitionType(field);
|
|
309
|
+
if (!rawType) {
|
|
267
310
|
return '';
|
|
268
311
|
}
|
|
269
|
-
return FORM_PRESENTATION_TYPE_ALIAS[
|
|
312
|
+
return FORM_PRESENTATION_TYPE_ALIAS[rawType] || FIELD_TYPE_ALIAS[rawType] || rawType;
|
|
270
313
|
}
|
|
271
314
|
|
|
272
315
|
function isFormPresentationComponent(componentName) {
|
|
@@ -277,6 +320,194 @@ function isFormPresentationDefinition(field) {
|
|
|
277
320
|
return isFormPresentationComponent(normalizeFormDefinitionType(field));
|
|
278
321
|
}
|
|
279
322
|
|
|
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
|
+
|
|
280
511
|
function normalizeI18nValue(value, fallback) {
|
|
281
512
|
if (value && typeof value === 'object') {
|
|
282
513
|
return value;
|
|
@@ -465,7 +696,16 @@ function buildFormNodeComponents(fields) {
|
|
|
465
696
|
// ── 生成字段组件 ─────────────────────────────────────
|
|
466
697
|
|
|
467
698
|
function buildFieldComponent(field) {
|
|
468
|
-
const componentName =
|
|
699
|
+
const componentName = normalizeFormDefinitionType(field);
|
|
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
|
+
}
|
|
469
709
|
const fieldId = generateFieldId(componentName);
|
|
470
710
|
const nodeId = nextNodeId();
|
|
471
711
|
|
|
@@ -3836,20 +4076,14 @@ function ensureComponentsMapForComponent(schema, component) {
|
|
|
3836
4076
|
}
|
|
3837
4077
|
}
|
|
3838
4078
|
|
|
3839
|
-
function getDefinitionDisplayName(field) {
|
|
3840
|
-
if (!field || typeof field !== 'object') {
|
|
3841
|
-
return '';
|
|
3842
|
-
}
|
|
3843
|
-
return field.label || field.title || field.type || '';
|
|
3844
|
-
}
|
|
3845
|
-
|
|
3846
4079
|
function countDataFieldDefinitions(fields) {
|
|
3847
4080
|
let count = 0;
|
|
3848
4081
|
(fields || []).forEach(function (field) {
|
|
3849
4082
|
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
3850
4083
|
return;
|
|
3851
4084
|
}
|
|
3852
|
-
|
|
4085
|
+
const componentName = normalizeFormDefinitionType(field);
|
|
4086
|
+
if (isSupportedBusinessFieldType(componentName)) {
|
|
3853
4087
|
count++;
|
|
3854
4088
|
}
|
|
3855
4089
|
if (Array.isArray(field.children)) {
|
|
@@ -3881,11 +4115,12 @@ function applyChangesToSchema(schema, changes) {
|
|
|
3881
4115
|
const actionDesc = t('create_form.action_label', changeIndex + 1, change.action);
|
|
3882
4116
|
|
|
3883
4117
|
if (change.action === 'add') {
|
|
3884
|
-
if (!change.field || !change.field
|
|
4118
|
+
if (!change.field || !normalizeFormDefinitionType(change.field) || (!change.field.label && !change.field.title && !isFormPresentationDefinition(change.field))) {
|
|
3885
4119
|
warn(actionDesc + t('create_form.add_missing_field'));
|
|
3886
4120
|
return;
|
|
3887
4121
|
}
|
|
3888
4122
|
|
|
4123
|
+
validateFormFieldDefinitions([change.field], 'changes[' + changeIndex + '].field');
|
|
3889
4124
|
const newComponent = buildFormNodeComponent(change.field);
|
|
3890
4125
|
ensureComponentsMapForComponent(schema, newComponent);
|
|
3891
4126
|
const displayName = getDefinitionDisplayName(change.field);
|
|
@@ -4057,12 +4292,54 @@ function requireSchemaServerRevision(serverRevision, details) {
|
|
|
4057
4292
|
return serverRevision;
|
|
4058
4293
|
}
|
|
4059
4294
|
|
|
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
|
+
|
|
4060
4337
|
// ── 保存 Schema 并更新表单配置(create/update 共用)──
|
|
4061
4338
|
//
|
|
4062
4339
|
// 封装了 saveFormSchema + updateFormConfig 两步,以及各自的 302 自动重登录重试。
|
|
4063
4340
|
// 返回 { saveResult, configResult }。
|
|
4064
4341
|
|
|
4065
|
-
async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, version, stepOffset) {
|
|
4342
|
+
async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, version, stepOffset, failureContext) {
|
|
4066
4343
|
const saveStep = stepOffset || 4;
|
|
4067
4344
|
const configStep = saveStep + 1;
|
|
4068
4345
|
|
|
@@ -4092,12 +4369,20 @@ async function saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, ver
|
|
|
4092
4369
|
if (saveResult && !saveResult.__needLogin) {
|
|
4093
4370
|
hint(t('common.response_detail', JSON.stringify(saveResult, null, 2)));
|
|
4094
4371
|
}
|
|
4095
|
-
|
|
4096
|
-
throwCreateFormError(saveErrorMsg, 'CREATE_FORM_SAVE_SCHEMA_FAILED', {
|
|
4372
|
+
const saveError = createCreateFormError(saveErrorMsg, 'CREATE_FORM_SAVE_SCHEMA_FAILED', {
|
|
4097
4373
|
appType,
|
|
4098
4374
|
formUuid,
|
|
4099
|
-
result: saveResult,
|
|
4375
|
+
result: sanitizeFailureResult(saveResult),
|
|
4100
4376
|
});
|
|
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;
|
|
4101
4386
|
}
|
|
4102
4387
|
|
|
4103
4388
|
success(t('create_form.schema_saved'));
|
|
@@ -4127,6 +4412,7 @@ async function mainCreate(parsedArgs, authRef) {
|
|
|
4127
4412
|
|
|
4128
4413
|
step(2, t('create_form.step_read_fields', 2));
|
|
4129
4414
|
const { fields, columns, validations } = readFieldsDefinition(fieldsJsonOrFile);
|
|
4415
|
+
validateFormFieldDefinitions(fields);
|
|
4130
4416
|
const fieldCount = countDataFieldDefinitions(fields);
|
|
4131
4417
|
success(t('create_form.fields_loaded', fieldCount));
|
|
4132
4418
|
label('Columns:', String(columns));
|
|
@@ -4158,30 +4444,62 @@ async function mainCreate(parsedArgs, authRef) {
|
|
|
4158
4444
|
|
|
4159
4445
|
const formUuid = createResult.content.formUuid || createResult.content;
|
|
4160
4446
|
success(t('create_form.blank_created', formUuid));
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4447
|
+
let configResult;
|
|
4448
|
+
let postCreateStage = 'getFormSchema';
|
|
4449
|
+
try {
|
|
4450
|
+
const shellSchemaResult = await requestWithAutoLogin(function (auth) {
|
|
4451
|
+
return sendGetRequest(
|
|
4452
|
+
auth.baseUrl,
|
|
4453
|
+
buildApiPath(appType, 'getFormSchema', { prefix: '_view', namespace: 'alibaba' }),
|
|
4454
|
+
{ formUuid: formUuid, schemaVersion: 'V5' }
|
|
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);
|
|
4169
4468
|
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4469
|
+
// Step 4 & 5: 生成 Schema 并保存,然后更新表单配置
|
|
4470
|
+
const corpId = resolveCorpId(authRef.authData);
|
|
4471
|
+
if (!corpId) {
|
|
4472
|
+
warn(t('create_form.no_corp_id_warning'));
|
|
4473
|
+
} else {
|
|
4474
|
+
info(t('create_form.corp_id_ok', corpId));
|
|
4475
|
+
}
|
|
4177
4476
|
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4477
|
+
postCreateStage = 'buildFormSchema';
|
|
4478
|
+
const schema = buildFormSchema(formTitle, fields, formUuid, corpId, appType, layout, theme, labelAlign);
|
|
4479
|
+
const createValidationRules = collectSmartValidationRulesFromFields(fields).concat(validations || []);
|
|
4480
|
+
if (createValidationRules.length > 0) {
|
|
4481
|
+
const appliedValidations = applySmartValidations(schema, createValidationRules);
|
|
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;
|
|
4183
4502
|
}
|
|
4184
|
-
const { configResult } = await saveSchemaAndUpdateConfig(authRef, appType, formUuid, schema, serverRevision, 4);
|
|
4185
4503
|
|
|
4186
4504
|
// 输出结果
|
|
4187
4505
|
const formUrl = authRef.baseUrl + '/' + appType + '/workbench/' + formUuid;
|
|
@@ -4203,11 +4521,25 @@ async function mainCreate(parsedArgs, authRef) {
|
|
|
4203
4521
|
['URL', formUrl],
|
|
4204
4522
|
]);
|
|
4205
4523
|
hint(t('create_form.schema_ok_config_failed'));
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4524
|
+
const configError = createCreateFormError(configErrorMsg, 'CREATE_FORM_UPDATE_CONFIG_FAILED', {
|
|
4525
|
+
appType,
|
|
4526
|
+
formUuid,
|
|
4527
|
+
result: sanitizeFailureResult(configResult),
|
|
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
|
+
}
|
|
4211
4543
|
)));
|
|
4212
4544
|
}
|
|
4213
4545
|
}
|
|
@@ -4228,6 +4560,7 @@ async function createFormForLegacyProcess(context, input) {
|
|
|
4228
4560
|
|
|
4229
4561
|
const { appType, formTitle, fieldsJsonOrFile, layout, theme, labelAlign } = parsedArgs;
|
|
4230
4562
|
const { fields, validations } = readFieldsDefinition(fieldsJsonOrFile);
|
|
4563
|
+
validateFormFieldDefinitions(fields);
|
|
4231
4564
|
const fieldCount = countDataFieldDefinitions(fields);
|
|
4232
4565
|
const createResult = await requestWithAutoLogin(function (auth) {
|
|
4233
4566
|
return sendPostRequest(
|
|
@@ -5193,6 +5526,8 @@ module.exports = {
|
|
|
5193
5526
|
buildFormNodeComponent,
|
|
5194
5527
|
countDataFieldDefinitions,
|
|
5195
5528
|
collectComponentNames,
|
|
5529
|
+
normalizeFormDefinitionType,
|
|
5530
|
+
validateFormFieldDefinitions,
|
|
5196
5531
|
ensureDividerThemeAction,
|
|
5197
5532
|
applyChangesToSchema,
|
|
5198
5533
|
},
|
package/lib/app/generate-page.js
CHANGED
|
@@ -514,6 +514,40 @@ 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
|
+
|
|
517
551
|
async function run(args) {
|
|
518
552
|
const options = parseArgs(args || []);
|
|
519
553
|
const spec = loadSpec(options.spec);
|
|
@@ -533,7 +567,10 @@ async function run(args) {
|
|
|
533
567
|
error(t('generate_page.template_not_found', templateFile));
|
|
534
568
|
}
|
|
535
569
|
|
|
536
|
-
const
|
|
570
|
+
const outputResolution = normalizeOutputPathForProjectCwd(
|
|
571
|
+
options.output || spec.output || (mode === 'canvas' ? templateConfig.defaultCanvasOutput : templateConfig.defaultNativeOutput)
|
|
572
|
+
);
|
|
573
|
+
const outputPath = outputResolution.outputPath;
|
|
537
574
|
const manifestPath = getManifestPath(outputPath);
|
|
538
575
|
const templateSource = fs.readFileSync(templateFile, 'utf-8');
|
|
539
576
|
const ir = normalizePageSpec(spec, {
|
|
@@ -561,6 +598,9 @@ async function run(args) {
|
|
|
561
598
|
fs.writeFileSync(outputPath, outputSource, 'utf-8');
|
|
562
599
|
fs.writeFileSync(manifestPath, `${JSON.stringify(ir, null, 2)}\n`, 'utf-8');
|
|
563
600
|
|
|
601
|
+
if (outputResolution.strippedProjectPrefix) {
|
|
602
|
+
warn(t('generate_page.output_project_prefix_stripped', outputResolution.requestedOutput, outputResolution.normalizedOutput));
|
|
603
|
+
}
|
|
564
604
|
success(t('generate_page.done', outputPath));
|
|
565
605
|
hint(t('generate_page.hint'));
|
|
566
606
|
reportMaterialStatus(materialPrecheck);
|
|
@@ -641,6 +681,7 @@ module.exports = {
|
|
|
641
681
|
escapeJsStringValue,
|
|
642
682
|
getManifestPath,
|
|
643
683
|
getCanvasDistPath,
|
|
684
|
+
normalizeOutputPathForProjectCwd,
|
|
644
685
|
inferMode,
|
|
645
686
|
inferTemplateName,
|
|
646
687
|
};
|
package/lib/app/publish.js
CHANGED
|
@@ -126,6 +126,28 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
function normalizeSourcePathForHint(sourceFile) {
|
|
130
|
+
return String(sourceFile || '')
|
|
131
|
+
.replace(/\\/g, '/')
|
|
132
|
+
.replace(/^\.\//, '');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function buildMissingSourceHints(sourceFile, cwd = process.cwd()) {
|
|
136
|
+
const normalized = normalizeSourcePathForHint(sourceFile);
|
|
137
|
+
const candidates = [];
|
|
138
|
+
|
|
139
|
+
if (normalized.startsWith('project/pages/src/')) {
|
|
140
|
+
candidates.push(normalized.slice('project/'.length));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (normalized.startsWith('pages/src/')) {
|
|
144
|
+
candidates.push(`project/${normalized}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return Array.from(new Set(candidates))
|
|
148
|
+
.filter(candidate => fs.existsSync(path.resolve(cwd, candidate)));
|
|
149
|
+
}
|
|
150
|
+
|
|
129
151
|
// ── 2. 读取并构建 Schema ────────────────────────────
|
|
130
152
|
|
|
131
153
|
async function fetchExistingSchemaContent(appType, formUuid, authRef) {
|
|
@@ -618,6 +640,10 @@ async function main(argv) {
|
|
|
618
640
|
let sourcePath = path.resolve(sourceFile);
|
|
619
641
|
if (!fs.existsSync(sourcePath)) {
|
|
620
642
|
error(t('publish.source_not_found', sourcePath));
|
|
643
|
+
buildMissingSourceHints(sourceFile).forEach((candidate) => {
|
|
644
|
+
hint(t('publish.source_path_hint', candidate));
|
|
645
|
+
});
|
|
646
|
+
process.exit(1);
|
|
621
647
|
}
|
|
622
648
|
|
|
623
649
|
// 路由:默认 native;.canvas.jsx / .canvas.tsx 源文件自动走 Code Canvas 链路,
|
|
@@ -799,6 +825,7 @@ if (require.main === module) {
|
|
|
799
825
|
module.exports = main;
|
|
800
826
|
module.exports.parseArgs = parseArgs;
|
|
801
827
|
module.exports.normalizePublishArgs = normalizePublishArgs;
|
|
828
|
+
module.exports.buildMissingSourceHints = buildMissingSourceHints;
|
|
802
829
|
module.exports.findDuplicateSourceMismatches = findDuplicateSourceMismatches;
|
|
803
830
|
module.exports.sendHealthCheckRequest = sendHealthCheckRequest;
|
|
804
831
|
module.exports.normalizeFormType = normalizeFormType;
|