openyida 2026.7.25-beta.2 → 2026.7.25-beta.3
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/page-compiler.js +5 -2
- package/lib/app/publish.js +34 -4
- package/lib/core/cli-error.js +13 -1
- package/lib/core/redact.js +3 -1
- package/lib/process/configure-process.js +131 -57
- package/lib/process/create-process.js +113 -23
- package/lib/process/process-diagnostics.js +188 -0
- package/package.json +1 -1
package/lib/app/page-compiler.js
CHANGED
|
@@ -17,9 +17,10 @@ const { warnLargePageSource } = require('./page-size-guard');
|
|
|
17
17
|
/**
|
|
18
18
|
* 编译宜搭自定义页面 JSX/JS 源码。
|
|
19
19
|
* @param {string} sourcePath
|
|
20
|
+
* @param {{ sourceCode?: string }} [options]
|
|
20
21
|
* @returns {{ sourceCode: string, compiledCode: string, compiledPath: string }}
|
|
21
22
|
*/
|
|
22
|
-
function compileSource(sourcePath) {
|
|
23
|
+
function compileSource(sourcePath, options = {}) {
|
|
23
24
|
assertNoEmojiInArtifactName(sourcePath, {
|
|
24
25
|
code: 'OPENYIDA_PAGE_FILENAME_EMOJI_FORBIDDEN',
|
|
25
26
|
});
|
|
@@ -29,7 +30,9 @@ function compileSource(sourcePath) {
|
|
|
29
30
|
const compiledPath = path.join(findProjectRoot(), 'pages', 'dist', compiledFileName);
|
|
30
31
|
|
|
31
32
|
info(t('publish.reading_source', sourceFileName));
|
|
32
|
-
const rawSourceCode =
|
|
33
|
+
const rawSourceCode = options.sourceCode === undefined
|
|
34
|
+
? fs.readFileSync(sourcePath, 'utf-8')
|
|
35
|
+
: String(options.sourceCode);
|
|
33
36
|
warnLargePageSource(rawSourceCode, sourcePath);
|
|
34
37
|
const runtimeResult = ensureYidaRuntimeContract(rawSourceCode);
|
|
35
38
|
const sourceCode = runtimeResult.code;
|
package/lib/app/publish.js
CHANGED
|
@@ -40,6 +40,7 @@ const { warnLargePageSource } = require('./page-size-guard');
|
|
|
40
40
|
const { fetchFormPageList } = require('./form-navigation');
|
|
41
41
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
42
42
|
const { assertNoEmojiInValue } = require('../core/no-emoji-guard');
|
|
43
|
+
const { loadPageSource } = require('./services/page-source-loader');
|
|
43
44
|
const {
|
|
44
45
|
buildDefaultPageDataSource,
|
|
45
46
|
buildNativePageSchemaContent,
|
|
@@ -143,6 +144,31 @@ function buildMissingSourceHints(sourceFile, cwd = process.cwd()) {
|
|
|
143
144
|
.filter(candidate => fs.existsSync(path.resolve(cwd, candidate)));
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
function isPathInside(rootPath, targetPath) {
|
|
148
|
+
const relative = path.relative(rootPath, targetPath);
|
|
149
|
+
return relative === '' || (!!relative && !relative.startsWith('..') && !path.isAbsolute(relative));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function loadPublishSource(sourcePath, options = {}) {
|
|
153
|
+
const absolutePath = path.resolve(sourcePath);
|
|
154
|
+
const workspaceRoot = path.resolve(options.workspaceRoot || process.cwd());
|
|
155
|
+
|
|
156
|
+
if (isPathInside(workspaceRoot, absolutePath)) {
|
|
157
|
+
const relativePath = path.relative(workspaceRoot, absolutePath) || path.basename(absolutePath);
|
|
158
|
+
const loaded = loadPageSource(relativePath, { workspaceRoot });
|
|
159
|
+
return Object.assign({}, loaded, { absolutePath });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
absolutePath,
|
|
164
|
+
byteLength: fs.statSync(absolutePath).size,
|
|
165
|
+
profile: 'absolute/raw-file',
|
|
166
|
+
relativePath: absolutePath,
|
|
167
|
+
source: fs.readFileSync(absolutePath, 'utf-8'),
|
|
168
|
+
sourceHash: null,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
146
172
|
// ── 2. 读取并构建 Schema ────────────────────────────
|
|
147
173
|
|
|
148
174
|
async function fetchExistingSchemaContent(appType, formUuid, authRef) {
|
|
@@ -679,7 +705,9 @@ async function main(argv) {
|
|
|
679
705
|
// --canvas 作为显式覆盖(用于扩展名不规范但确为 canvas 源码的场景)。
|
|
680
706
|
const isCanvas = canvasFlag || /\.canvas\.(jsx|tsx)$/i.test(sourcePath);
|
|
681
707
|
|
|
682
|
-
const
|
|
708
|
+
const initialSource = loadPublishSource(sourcePath);
|
|
709
|
+
sourcePath = initialSource.absolutePath;
|
|
710
|
+
const initialSourceCode = initialSource.source;
|
|
683
711
|
warnLargePageSource(initialSourceCode, sourcePath);
|
|
684
712
|
|
|
685
713
|
let sourceCode = initialSourceCode;
|
|
@@ -712,12 +740,13 @@ async function main(argv) {
|
|
|
712
740
|
success(t('build_page.output', sourcePath));
|
|
713
741
|
}
|
|
714
742
|
warnDuplicateSourceMismatches(sourcePath);
|
|
743
|
+
const currentSource = loadPublishSource(sourcePath);
|
|
744
|
+
sourcePath = currentSource.absolutePath;
|
|
715
745
|
|
|
716
746
|
// Step 0: 宜搭编码规范预检(可通过 --skip-lint 跳过)
|
|
717
747
|
if (!skipLint) {
|
|
718
748
|
step(0, t('publish.step_lint'));
|
|
719
|
-
const
|
|
720
|
-
const lintPassed = runLintCheck(lintSource, sourcePath, { successMessage: false });
|
|
749
|
+
const lintPassed = runLintCheck(currentSource.source, sourcePath, { successMessage: false });
|
|
721
750
|
if (!lintPassed) {
|
|
722
751
|
process.exit(1);
|
|
723
752
|
}
|
|
@@ -727,7 +756,7 @@ async function main(argv) {
|
|
|
727
756
|
}
|
|
728
757
|
|
|
729
758
|
step(1, t('publish.step_compile'));
|
|
730
|
-
const compiled = compileSource(sourcePath);
|
|
759
|
+
const compiled = compileSource(sourcePath, { sourceCode: currentSource.source });
|
|
731
760
|
sourceCode = compiled.sourceCode;
|
|
732
761
|
compiledCode = compiled.compiledCode;
|
|
733
762
|
}
|
|
@@ -864,6 +893,7 @@ if (require.main === module) {
|
|
|
864
893
|
module.exports.normalizePublishArgs = normalizePublishArgs;
|
|
865
894
|
module.exports.buildMissingSourceHints = buildMissingSourceHints;
|
|
866
895
|
module.exports.findDuplicateSourceMismatches = findDuplicateSourceMismatches;
|
|
896
|
+
module.exports.loadPublishSource = loadPublishSource;
|
|
867
897
|
module.exports.sendHealthCheckRequest = sendHealthCheckRequest;
|
|
868
898
|
module.exports.normalizeFormType = normalizeFormType;
|
|
869
899
|
module.exports.findPublishTarget = findPublishTarget;
|
package/lib/core/cli-error.js
CHANGED
|
@@ -26,7 +26,19 @@ function toErrorPayload(error) {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
if (isCliError(error) && error.details !== undefined) {
|
|
29
|
-
|
|
29
|
+
const details = redactSensitive(error.details);
|
|
30
|
+
if (details && typeof details === 'object' && !Array.isArray(details)) {
|
|
31
|
+
if (details.stage) {
|
|
32
|
+
payload.stage = details.stage;
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(details.completedStages)) {
|
|
35
|
+
payload.completedStages = details.completedStages.slice();
|
|
36
|
+
}
|
|
37
|
+
if (details.nextStep) {
|
|
38
|
+
payload.nextStep = details.nextStep;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
payload.details = details;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
return payload;
|
package/lib/core/redact.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const SENSITIVE_KEY_PATTERN = /(^|[_-])(authorization|auth|cookie|csrf|token|secret|password|passwd|api[_-]?key|access[_-]?key|signature|sign)([_-]|$)/i;
|
|
4
|
+
const SENSITIVE_CAMEL_KEY_PATTERN = /^(?:authorization|auth|cookie|csrf|token|secret|password|passwd|apiKey|accessKey|signature|sign)(?:[A-Z]|$)|(?:Authorization|Auth|Cookie|Csrf|Token|Secret|Password|Passwd|ApiKey|AccessKey|Signature|Sign)$/;
|
|
4
5
|
const EMAIL_PATTERN = /([A-Z0-9._%+-])([A-Z0-9._%+-]*)(@[A-Z0-9.-]+\.[A-Z]{2,})/gi;
|
|
5
6
|
const MAINLAND_PHONE_PATTERN = /(^|[^\d])(1[3-9]\d)(\d{4})(\d{4})(?!\d)/g;
|
|
6
7
|
|
|
@@ -42,7 +43,8 @@ function isPlainObject(value) {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
function shouldMaskKey(key) {
|
|
45
|
-
|
|
46
|
+
const text = String(key || '');
|
|
47
|
+
return SENSITIVE_KEY_PATTERN.test(text) || SENSITIVE_CAMEL_KEY_PATTERN.test(text);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
function redactSensitive(value, options = {}) {
|
|
@@ -11,6 +11,7 @@ const { CliError } = require('../core/cli-error');
|
|
|
11
11
|
const { createAuthRef } = require('../core/yida-client');
|
|
12
12
|
const { t } = require('../core/i18n');
|
|
13
13
|
const { warn } = require('../core/chalk');
|
|
14
|
+
const { createStageTracker, summarizeRemoteResult } = require('./process-diagnostics');
|
|
14
15
|
const {
|
|
15
16
|
buildApproverConfig,
|
|
16
17
|
buildProcessAndViewJson,
|
|
@@ -46,7 +47,7 @@ function formatApiError(result) {
|
|
|
46
47
|
if (!result) {
|
|
47
48
|
return 'empty response';
|
|
48
49
|
}
|
|
49
|
-
return result.errorMsg || result.message || JSON.stringify(result);
|
|
50
|
+
return result.errorMsg || result.message || JSON.stringify(summarizeRemoteResult(result));
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
// ── 主流程 ───────────────────────────────────────────
|
|
@@ -57,6 +58,21 @@ async function run(args) {
|
|
|
57
58
|
const formUuid = parsed.formUuid;
|
|
58
59
|
const processDefinitionFile = parsed.processDefinitionFile;
|
|
59
60
|
const processCodeArg = parsed.processCodeArg;
|
|
61
|
+
const stageTracker = createStageTracker();
|
|
62
|
+
let processCode = processCodeArg;
|
|
63
|
+
let newProcessId = null;
|
|
64
|
+
let newVersion = null;
|
|
65
|
+
|
|
66
|
+
function context(extra) {
|
|
67
|
+
return Object.assign({
|
|
68
|
+
appType,
|
|
69
|
+
formUuid,
|
|
70
|
+
processCode: processCode || null,
|
|
71
|
+
processId: newProcessId || null,
|
|
72
|
+
processVersion: newVersion,
|
|
73
|
+
processDefinitionFile,
|
|
74
|
+
}, extra || {});
|
|
75
|
+
}
|
|
60
76
|
|
|
61
77
|
warn('🔧 ' + t('configure_process.title'));
|
|
62
78
|
warn(' ' + t('configure_process.app_id') + ': ' + appType);
|
|
@@ -72,7 +88,9 @@ async function run(args) {
|
|
|
72
88
|
warn(' ❌ ' + t('configure_process.file_not_found') + ': ' + processDefinitionFile);
|
|
73
89
|
throw new CliError(t('configure_process.file_not_found') + ': ' + processDefinitionFile, {
|
|
74
90
|
code: 'CONFIGURE_PROCESS_FILE_NOT_FOUND',
|
|
75
|
-
details: {
|
|
91
|
+
details: stageTracker.failure('read_definition', {
|
|
92
|
+
context: context(),
|
|
93
|
+
}),
|
|
76
94
|
});
|
|
77
95
|
}
|
|
78
96
|
|
|
@@ -83,49 +101,65 @@ async function run(args) {
|
|
|
83
101
|
warn(' ❌ ' + t('configure_process.parse_failed') + ': ' + e.message);
|
|
84
102
|
throw new CliError(t('configure_process.parse_failed') + ': ' + e.message, {
|
|
85
103
|
code: 'CONFIGURE_PROCESS_INVALID_JSON',
|
|
86
|
-
details: {
|
|
104
|
+
details: stageTracker.failure('read_definition', {
|
|
105
|
+
context: context(),
|
|
106
|
+
cause: e,
|
|
107
|
+
}),
|
|
87
108
|
});
|
|
88
109
|
}
|
|
89
110
|
warn(' ✅ ' + t('configure_process.definition_loaded') + ' (' + (definition.nodes || []).length + ' ' + t('configure_process.nodes') + ')');
|
|
111
|
+
stageTracker.complete('read_definition');
|
|
90
112
|
|
|
91
113
|
// 2. 读取登录态
|
|
92
114
|
warn('\n🔑 ' + t('configure_process.loading_auth') + '...');
|
|
93
115
|
const authRef = createAuthRef();
|
|
94
116
|
warn(' ✅ ' + t('configure_process.auth_loaded') + ', baseUrl: ' + authRef.baseUrl);
|
|
117
|
+
stageTracker.complete('load_auth');
|
|
95
118
|
|
|
96
119
|
// 3. 获取 processCode
|
|
97
120
|
warn('\n🔍 ' + t('configure_process.getting_process_code') + '...');
|
|
98
|
-
let processCode = processCodeArg;
|
|
99
121
|
|
|
100
122
|
if (!processCode) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (switchMsg.indexOf('已转换') >= 0 || switchMsg.indexOf('已经是') >= 0) {
|
|
109
|
-
warn(' ✅ ' + t('configure_process.already_process'));
|
|
123
|
+
try {
|
|
124
|
+
// 确保表单是流程表单
|
|
125
|
+
warn(' ' + t('configure_process.switching_form_type') + '...');
|
|
126
|
+
const switchResult = await switchFormType(authRef, appType, formUuid);
|
|
127
|
+
if (switchResult.success) {
|
|
128
|
+
warn(' ✅ ' + t('configure_process.switch_success'));
|
|
129
|
+
stageTracker.complete('switch_form_type');
|
|
110
130
|
} else {
|
|
111
|
-
|
|
131
|
+
const switchMsg = switchResult.errorMsg || '';
|
|
132
|
+
if (switchMsg.indexOf('已转换') >= 0 || switchMsg.indexOf('已经是') >= 0) {
|
|
133
|
+
warn(' ✅ ' + t('configure_process.already_process'));
|
|
134
|
+
stageTracker.complete('switch_form_type');
|
|
135
|
+
} else {
|
|
136
|
+
warn(' ⚠️ ' + t('configure_process.switch_warning') + ': ' + switchMsg);
|
|
137
|
+
}
|
|
112
138
|
}
|
|
113
|
-
}
|
|
114
139
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (processCode) {
|
|
119
|
-
warn(' ✅ ' + t('configure_process.got_process_code') + ': ' + processCode);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// 方法 2: 从 getFormSchema 中提取
|
|
123
|
-
if (!processCode) {
|
|
124
|
-
warn(' ' + t('configure_process.method2') + '...');
|
|
125
|
-
processCode = await getProcessCodeFromSchema(authRef, appType, formUuid);
|
|
140
|
+
// 方法 1: 从精确表单流程绑定接口提取
|
|
141
|
+
warn(' ' + t('configure_process.method1') + '...');
|
|
142
|
+
processCode = await getProcessCodeFromAppParam(authRef, appType, formUuid);
|
|
126
143
|
if (processCode) {
|
|
127
|
-
warn(' ✅ ' + t('configure_process.
|
|
144
|
+
warn(' ✅ ' + t('configure_process.got_process_code') + ': ' + processCode);
|
|
128
145
|
}
|
|
146
|
+
|
|
147
|
+
// 方法 2: 从 getFormSchema 中提取
|
|
148
|
+
if (!processCode) {
|
|
149
|
+
warn(' ' + t('configure_process.method2') + '...');
|
|
150
|
+
processCode = await getProcessCodeFromSchema(authRef, appType, formUuid);
|
|
151
|
+
if (processCode) {
|
|
152
|
+
warn(' ✅ ' + t('configure_process.got_from_schema') + ': ' + processCode);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} catch (lookupError) {
|
|
156
|
+
throw new CliError(t('configure_process.no_process_code') + ': ' + lookupError.message, {
|
|
157
|
+
code: 'CONFIGURE_PROCESS_CODE_LOOKUP_FAILED',
|
|
158
|
+
details: stageTracker.failure('resolve_process_code', {
|
|
159
|
+
context: context(),
|
|
160
|
+
cause: lookupError,
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
129
163
|
}
|
|
130
164
|
}
|
|
131
165
|
|
|
@@ -134,42 +168,55 @@ async function run(args) {
|
|
|
134
168
|
warn(' 💡 ' + t('configure_process.manual_hint'));
|
|
135
169
|
throw new CliError(t('configure_process.no_process_code'), {
|
|
136
170
|
code: 'CONFIGURE_PROCESS_CODE_NOT_FOUND',
|
|
137
|
-
details:
|
|
171
|
+
details: stageTracker.failure('resolve_process_code', {
|
|
172
|
+
context: context(),
|
|
173
|
+
}),
|
|
138
174
|
});
|
|
139
175
|
}
|
|
140
176
|
warn(' ✅ processCode: ' + processCode);
|
|
177
|
+
stageTracker.complete('resolve_process_code');
|
|
141
178
|
|
|
142
179
|
// 4. 查询流程版本列表
|
|
143
180
|
warn('\n🔍 ' + t('configure_process.querying_versions') + '...');
|
|
144
|
-
|
|
181
|
+
let publishedResult;
|
|
145
182
|
|
|
146
183
|
let latestProcessId = null;
|
|
147
184
|
let latestVersion = 0;
|
|
148
185
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
186
|
+
try {
|
|
187
|
+
publishedResult = await queryProcessVersions(authRef, appType, processCode, 'PUBLISHED');
|
|
188
|
+
if (publishedResult.success && publishedResult.content && publishedResult.content.data && publishedResult.content.data.length > 0) {
|
|
189
|
+
const publishedVersion = publishedResult.content.data[0];
|
|
190
|
+
latestProcessId = publishedVersion.id;
|
|
191
|
+
latestVersion = parseInt(publishedVersion.version, 10);
|
|
192
|
+
warn(' ✅ ' + t('configure_process.found_published') + ': processId=' + latestProcessId + ', version=' + latestVersion);
|
|
193
|
+
} else {
|
|
194
|
+
warn(' ℹ️ ' + t('configure_process.no_published') + '...');
|
|
195
|
+
const allVersionsResult = await queryProcessVersions(authRef, appType, processCode, '');
|
|
196
|
+
if (allVersionsResult.success && allVersionsResult.content && allVersionsResult.content.data && allVersionsResult.content.data.length > 0) {
|
|
197
|
+
const latestItem = allVersionsResult.content.data[0];
|
|
198
|
+
latestProcessId = latestItem.id;
|
|
199
|
+
latestVersion = parseInt(latestItem.version, 10);
|
|
200
|
+
warn(' ✅ ' + t('configure_process.found_latest') + ': processId=' + latestProcessId + ', version=' + latestVersion);
|
|
201
|
+
}
|
|
162
202
|
}
|
|
203
|
+
} catch (versionError) {
|
|
204
|
+
throw new CliError(t('configure_process.querying_versions') + ': ' + versionError.message, {
|
|
205
|
+
code: 'CONFIGURE_PROCESS_QUERY_VERSIONS_FAILED',
|
|
206
|
+
details: stageTracker.failure('query_process_versions', {
|
|
207
|
+
context: context(),
|
|
208
|
+
cause: versionError,
|
|
209
|
+
}),
|
|
210
|
+
});
|
|
163
211
|
}
|
|
212
|
+
stageTracker.complete('query_process_versions');
|
|
164
213
|
|
|
165
|
-
|
|
214
|
+
newVersion = latestVersion + 1;
|
|
166
215
|
|
|
167
216
|
// 5. 创建新流程版本草稿
|
|
168
217
|
warn('\n📝 ' + t('configure_process.creating_draft') + '...');
|
|
169
218
|
const draftResult = await newDraftProcess(authRef, appType, processCode, formUuid, latestProcessId, newVersion);
|
|
170
219
|
|
|
171
|
-
let newProcessId = null;
|
|
172
|
-
|
|
173
220
|
if (draftResult.success && draftResult.content && draftResult.content.processId) {
|
|
174
221
|
// content 是对象,包含 processId 字段
|
|
175
222
|
newProcessId = draftResult.content.processId;
|
|
@@ -194,7 +241,10 @@ async function run(args) {
|
|
|
194
241
|
warn(' ❌ ' + t('configure_process.draft_failed') + ': ' + errorMsg);
|
|
195
242
|
throw new CliError(t('configure_process.draft_failed') + ': ' + errorMsg, {
|
|
196
243
|
code: 'CONFIGURE_PROCESS_DRAFT_FAILED',
|
|
197
|
-
details:
|
|
244
|
+
details: stageTracker.failure('create_draft', {
|
|
245
|
+
context: context(),
|
|
246
|
+
cause: draftResult,
|
|
247
|
+
}),
|
|
198
248
|
});
|
|
199
249
|
}
|
|
200
250
|
|
|
@@ -202,24 +252,40 @@ async function run(args) {
|
|
|
202
252
|
warn(' ❌ ' + t('configure_process.no_draft_id'));
|
|
203
253
|
throw new CliError(t('configure_process.no_draft_id'), {
|
|
204
254
|
code: 'CONFIGURE_PROCESS_DRAFT_ID_NOT_FOUND',
|
|
205
|
-
details:
|
|
255
|
+
details: stageTracker.failure('create_draft', {
|
|
256
|
+
context: context(),
|
|
257
|
+
cause: draftResult,
|
|
258
|
+
}),
|
|
206
259
|
});
|
|
207
260
|
}
|
|
261
|
+
stageTracker.complete('create_draft');
|
|
208
262
|
|
|
209
263
|
// 6. 构建 processJson 和 viewJson
|
|
210
264
|
warn('\n🏗️ ' + t('configure_process.building_json') + '...');
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
265
|
+
let result;
|
|
266
|
+
try {
|
|
267
|
+
result = buildProcessAndViewJson(
|
|
268
|
+
definition,
|
|
269
|
+
processCode,
|
|
270
|
+
formUuid,
|
|
271
|
+
authRef.baseUrl,
|
|
272
|
+
appType,
|
|
273
|
+
{ onWarning: warn }
|
|
274
|
+
);
|
|
275
|
+
} catch (buildError) {
|
|
276
|
+
throw new CliError(t('configure_process.building_json') + ': ' + buildError.message, {
|
|
277
|
+
code: 'CONFIGURE_PROCESS_BUILD_FAILED',
|
|
278
|
+
details: stageTracker.failure('build_definition', {
|
|
279
|
+
context: context(),
|
|
280
|
+
cause: buildError,
|
|
281
|
+
}),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
219
284
|
const processJsonStr = JSON.stringify(result.processJson);
|
|
220
285
|
const viewJsonStr = JSON.stringify(result.viewJson);
|
|
221
286
|
warn(' ✅ processJson: ' + processJsonStr.length + ' chars');
|
|
222
287
|
warn(' ✅ viewJson: ' + viewJsonStr.length + ' chars');
|
|
288
|
+
stageTracker.complete('build_definition');
|
|
223
289
|
|
|
224
290
|
// 7. 保存流程
|
|
225
291
|
warn('\n💾 ' + t('configure_process.saving') + '...');
|
|
@@ -235,9 +301,13 @@ async function run(args) {
|
|
|
235
301
|
warn(' ❌ ' + t('configure_process.save_failed') + ': ' + errorMsg);
|
|
236
302
|
throw new CliError(t('configure_process.save_failed') + ': ' + errorMsg, {
|
|
237
303
|
code: 'CONFIGURE_PROCESS_SAVE_FAILED',
|
|
238
|
-
details:
|
|
304
|
+
details: stageTracker.failure('save_definition', {
|
|
305
|
+
context: context(),
|
|
306
|
+
cause: saveResult,
|
|
307
|
+
}),
|
|
239
308
|
});
|
|
240
309
|
}
|
|
310
|
+
stageTracker.complete('save_definition');
|
|
241
311
|
|
|
242
312
|
// 8. 发布流程
|
|
243
313
|
warn('\n🚀 ' + t('configure_process.publishing') + '...');
|
|
@@ -252,9 +322,13 @@ async function run(args) {
|
|
|
252
322
|
warn(' ❌ ' + t('configure_process.publish_failed') + ': ' + errorMsg);
|
|
253
323
|
throw new CliError(t('configure_process.publish_failed') + ': ' + errorMsg, {
|
|
254
324
|
code: 'CONFIGURE_PROCESS_PUBLISH_FAILED',
|
|
255
|
-
details:
|
|
325
|
+
details: stageTracker.failure('publish_process', {
|
|
326
|
+
context: context(),
|
|
327
|
+
cause: publishResult,
|
|
328
|
+
}),
|
|
256
329
|
});
|
|
257
330
|
}
|
|
331
|
+
stageTracker.complete('publish_process');
|
|
258
332
|
|
|
259
333
|
// 9. 输出结果
|
|
260
334
|
const output = {
|
|
@@ -20,6 +20,7 @@ const { createAuthRef, isAuthRefReady } = require('../core/yida-client');
|
|
|
20
20
|
const { t } = require('../core/i18n');
|
|
21
21
|
const { warn } = require('../core/chalk');
|
|
22
22
|
const { createFormForLegacyProcess } = require('../app/create-form');
|
|
23
|
+
const { createStageTracker, summarizeRemoteResult } = require('./process-diagnostics');
|
|
23
24
|
const {
|
|
24
25
|
getProcessCodeFromAppParam,
|
|
25
26
|
getProcessCodeFromSchema,
|
|
@@ -86,6 +87,50 @@ async function run(args) {
|
|
|
86
87
|
const useExistingForm = !!existingFormUuid;
|
|
87
88
|
const fieldsJsonFile = parsed.fieldsJsonFile ? path.resolve(parsed.fieldsJsonFile) : null;
|
|
88
89
|
const processDefinitionFile = path.resolve(parsed.processDefinitionFile);
|
|
90
|
+
const stageTracker = createStageTracker();
|
|
91
|
+
let formUuid;
|
|
92
|
+
let fieldCount = 0;
|
|
93
|
+
|
|
94
|
+
function context(extra) {
|
|
95
|
+
return Object.assign({
|
|
96
|
+
appType,
|
|
97
|
+
formUuid: formUuid || existingFormUuid || null,
|
|
98
|
+
processDefinitionFile,
|
|
99
|
+
}, extra || {});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function buildRetryCommand() {
|
|
103
|
+
return 'openyida create-process ' + appType + ' --formUuid ' + formUuid + ' ' + path.basename(processDefinitionFile);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function buildConfigureFailureDetails(configError) {
|
|
107
|
+
const retryCommand = buildRetryCommand();
|
|
108
|
+
const outerDetails = stageTracker.failure('configure_process', {
|
|
109
|
+
context: context({ processCode, retryCommand }),
|
|
110
|
+
cause: configError,
|
|
111
|
+
});
|
|
112
|
+
const innerDetails = configError && configError.isCliError && configError.details && configError.details.stage
|
|
113
|
+
? configError.details
|
|
114
|
+
: null;
|
|
115
|
+
if (!innerDetails) {
|
|
116
|
+
return outerDetails;
|
|
117
|
+
}
|
|
118
|
+
const configureProcess = {
|
|
119
|
+
stage: innerDetails.stage,
|
|
120
|
+
completedStages: Array.isArray(innerDetails.completedStages)
|
|
121
|
+
? innerDetails.completedStages.slice()
|
|
122
|
+
: [],
|
|
123
|
+
};
|
|
124
|
+
if (innerDetails.nextStep) {
|
|
125
|
+
configureProcess.nextStep = innerDetails.nextStep;
|
|
126
|
+
}
|
|
127
|
+
return Object.assign({}, outerDetails, {
|
|
128
|
+
stage: innerDetails.stage,
|
|
129
|
+
nextStep: innerDetails.nextStep || outerDetails.nextStep,
|
|
130
|
+
createProcessStage: 'configure_process',
|
|
131
|
+
configureProcess,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
89
134
|
|
|
90
135
|
warn('═'.repeat(60));
|
|
91
136
|
warn(' 🔧 ' + t('create_process.title'));
|
|
@@ -107,14 +152,18 @@ async function run(args) {
|
|
|
107
152
|
warn(' ❌ ' + t('create_process.fields_not_found') + ': ' + fieldsJsonFile);
|
|
108
153
|
throw new CliError(t('create_process.fields_not_found') + ': ' + fieldsJsonFile, {
|
|
109
154
|
code: 'CREATE_PROCESS_FIELDS_NOT_FOUND',
|
|
110
|
-
details: {
|
|
155
|
+
details: stageTracker.failure('validate_inputs', {
|
|
156
|
+
context: context({ fieldsJsonFile }),
|
|
157
|
+
}),
|
|
111
158
|
});
|
|
112
159
|
}
|
|
113
160
|
if (!fs.existsSync(processDefinitionFile)) {
|
|
114
161
|
warn(' ❌ ' + t('create_process.process_def_not_found') + ': ' + processDefinitionFile);
|
|
115
162
|
throw new CliError(t('create_process.process_def_not_found') + ': ' + processDefinitionFile, {
|
|
116
163
|
code: 'CREATE_PROCESS_DEFINITION_NOT_FOUND',
|
|
117
|
-
details: {
|
|
164
|
+
details: stageTracker.failure('validate_inputs', {
|
|
165
|
+
context: context(),
|
|
166
|
+
}),
|
|
118
167
|
});
|
|
119
168
|
}
|
|
120
169
|
|
|
@@ -124,18 +173,20 @@ async function run(args) {
|
|
|
124
173
|
if (!isAuthRefReady(authRef)) {
|
|
125
174
|
throw new CliError('未获取到有效宜搭登录态,请先执行 openyida login', {
|
|
126
175
|
code: 'NEED_LOGIN',
|
|
176
|
+
details: stageTracker.failure('load_auth', {
|
|
177
|
+
context: context(),
|
|
178
|
+
}),
|
|
127
179
|
});
|
|
128
180
|
}
|
|
129
181
|
warn(' ✅ ' + t('create_process.auth_loaded') + ', baseUrl: ' + authRef.baseUrl);
|
|
182
|
+
stageTracker.complete('load_auth');
|
|
130
183
|
|
|
131
184
|
// Step 1: 创建或复用表单
|
|
132
|
-
let formUuid;
|
|
133
|
-
let fieldCount = 0;
|
|
134
|
-
|
|
135
185
|
if (useExistingForm) {
|
|
136
186
|
warn('\n📋 Step 1: ' + t('create_process.reusing_form') + '...');
|
|
137
187
|
formUuid = existingFormUuid;
|
|
138
188
|
warn(' ✅ ' + t('create_process.using_form') + ': ' + formUuid);
|
|
189
|
+
stageTracker.complete('reuse_form');
|
|
139
190
|
} else {
|
|
140
191
|
warn('\n📋 Step 1: ' + t('create_process.creating_form') + '...');
|
|
141
192
|
try {
|
|
@@ -146,23 +197,34 @@ async function run(args) {
|
|
|
146
197
|
});
|
|
147
198
|
|
|
148
199
|
if (!createFormResult || !createFormResult.success || !createFormResult.formUuid) {
|
|
149
|
-
warn(' ❌ ' + t('create_process.create_form_failed') + ': ' + JSON.stringify(createFormResult));
|
|
200
|
+
warn(' ❌ ' + t('create_process.create_form_failed') + ': ' + JSON.stringify(summarizeRemoteResult(createFormResult)));
|
|
150
201
|
throw new CliError(t('create_process.create_form_failed'), {
|
|
151
202
|
code: 'CREATE_PROCESS_CREATE_FORM_FAILED',
|
|
152
|
-
details:
|
|
203
|
+
details: stageTracker.failure('create_form', {
|
|
204
|
+
context: context({ formTitle, fieldsJsonFile }),
|
|
205
|
+
cause: createFormResult,
|
|
206
|
+
}),
|
|
153
207
|
});
|
|
154
208
|
}
|
|
155
209
|
|
|
156
210
|
formUuid = createFormResult.formUuid;
|
|
157
211
|
fieldCount = createFormResult.fieldCount || 0;
|
|
158
212
|
warn(' ✅ ' + t('create_process.form_created') + ': ' + formUuid);
|
|
213
|
+
stageTracker.complete('create_form');
|
|
159
214
|
} catch (createError) {
|
|
160
215
|
warn(' ❌ ' + t('create_process.create_form_failed') + ': ' + createError.message);
|
|
161
216
|
if (createError.stderr) {
|
|
162
217
|
warn(' ' + createError.stderr.substring(0, 1000));
|
|
163
218
|
}
|
|
219
|
+
if (createError && createError.isCliError && createError.details && createError.details.stage) {
|
|
220
|
+
throw createError;
|
|
221
|
+
}
|
|
164
222
|
throw new CliError(t('create_process.create_form_failed') + ': ' + createError.message, {
|
|
165
223
|
code: 'CREATE_PROCESS_CREATE_FORM_FAILED',
|
|
224
|
+
details: stageTracker.failure('create_form', {
|
|
225
|
+
context: context({ formTitle, fieldsJsonFile }),
|
|
226
|
+
cause: createError,
|
|
227
|
+
}),
|
|
166
228
|
});
|
|
167
229
|
}
|
|
168
230
|
}
|
|
@@ -180,32 +242,49 @@ async function run(args) {
|
|
|
180
242
|
warn(' ❌ ' + t('create_process.switch_failed') + ': ' + switchMsg);
|
|
181
243
|
throw new CliError(t('create_process.switch_failed') + ': ' + switchMsg, {
|
|
182
244
|
code: 'CREATE_PROCESS_SWITCH_FAILED',
|
|
183
|
-
details:
|
|
245
|
+
details: stageTracker.failure('switch_form_type', {
|
|
246
|
+
context: context(),
|
|
247
|
+
cause: switchResult,
|
|
248
|
+
}),
|
|
184
249
|
});
|
|
185
250
|
}
|
|
186
251
|
}
|
|
252
|
+
stageTracker.complete('switch_form_type');
|
|
187
253
|
|
|
188
254
|
// Step 3: 获取 processCode
|
|
189
255
|
warn('\n🔍 Step 3: ' + t('create_process.getting_process_code') + '...');
|
|
190
256
|
let processCode = null;
|
|
191
257
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
warn(' ✅ ' + t('create_process.got_process_code') + ': ' + processCode);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// 方法 2: 从 getFormSchema 中提取
|
|
200
|
-
if (!processCode) {
|
|
201
|
-
warn(' ' + t('create_process.method2') + '...');
|
|
202
|
-
processCode = await getProcessCodeFromSchema(authRef, appType, formUuid);
|
|
258
|
+
try {
|
|
259
|
+
// 方法 1: 从精确表单流程绑定接口提取
|
|
260
|
+
warn(' ' + t('create_process.method1') + '...');
|
|
261
|
+
processCode = await getProcessCodeFromAppParam(authRef, appType, formUuid);
|
|
203
262
|
if (processCode) {
|
|
204
|
-
warn(' ✅ ' + t('create_process.
|
|
263
|
+
warn(' ✅ ' + t('create_process.got_process_code') + ': ' + processCode);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 方法 2: 从 getFormSchema 中提取
|
|
267
|
+
if (!processCode) {
|
|
268
|
+
warn(' ' + t('create_process.method2') + '...');
|
|
269
|
+
processCode = await getProcessCodeFromSchema(authRef, appType, formUuid);
|
|
270
|
+
if (processCode) {
|
|
271
|
+
warn(' ✅ ' + t('create_process.got_from_schema') + ': ' + processCode);
|
|
272
|
+
}
|
|
205
273
|
}
|
|
274
|
+
} catch (lookupError) {
|
|
275
|
+
throw new CliError(t('create_process.no_process_code') + ': ' + lookupError.message, {
|
|
276
|
+
code: 'CREATE_PROCESS_CODE_LOOKUP_FAILED',
|
|
277
|
+
details: stageTracker.failure('resolve_process_code', {
|
|
278
|
+
context: context(),
|
|
279
|
+
cause: lookupError,
|
|
280
|
+
}),
|
|
281
|
+
});
|
|
206
282
|
}
|
|
207
283
|
|
|
208
284
|
if (!processCode) {
|
|
285
|
+
const failureDetails = stageTracker.failure('resolve_process_code', {
|
|
286
|
+
context: context(),
|
|
287
|
+
});
|
|
209
288
|
warn(' ❌ ' + t('create_process.no_process_code'));
|
|
210
289
|
warn(' 💡 ' + t('create_process.manual_hint', formUuid));
|
|
211
290
|
console.log(JSON.stringify({
|
|
@@ -215,24 +294,30 @@ async function run(args) {
|
|
|
215
294
|
appType: appType,
|
|
216
295
|
fieldCount: fieldCount,
|
|
217
296
|
error: t('create_process.no_process_code'),
|
|
297
|
+
stage: failureDetails.stage,
|
|
298
|
+
completedStages: failureDetails.completedStages,
|
|
299
|
+
nextStep: failureDetails.nextStep,
|
|
218
300
|
}));
|
|
219
301
|
throw new CliError(t('create_process.no_process_code'), {
|
|
220
302
|
code: 'CREATE_PROCESS_CODE_NOT_FOUND',
|
|
221
|
-
details:
|
|
303
|
+
details: failureDetails,
|
|
222
304
|
});
|
|
223
305
|
}
|
|
306
|
+
stageTracker.complete('resolve_process_code');
|
|
224
307
|
|
|
225
308
|
// Step 4: 配置并发布流程
|
|
226
309
|
warn('\n⚙️ Step 4: ' + t('create_process.configuring_process') + '...');
|
|
227
310
|
try {
|
|
228
311
|
const { run: runConfigureProcess } = require('./configure-process');
|
|
229
312
|
await runConfigureProcess([appType, formUuid, processDefinitionFile, processCode]);
|
|
313
|
+
stageTracker.complete('configure_process');
|
|
230
314
|
} catch (configError) {
|
|
315
|
+
const failureDetails = buildConfigureFailureDetails(configError);
|
|
231
316
|
warn(' ❌ ' + t('create_process.configure_failed') + ': ' + configError.message);
|
|
232
317
|
// 提示用户可以使用 --formUuid 复用已创建的表单
|
|
233
318
|
warn('');
|
|
234
319
|
warn(' 💡 ' + t('create_process.retry_hint'));
|
|
235
|
-
warn('
|
|
320
|
+
warn(' ' + buildRetryCommand());
|
|
236
321
|
warn('');
|
|
237
322
|
console.log(JSON.stringify({
|
|
238
323
|
success: false,
|
|
@@ -241,10 +326,15 @@ async function run(args) {
|
|
|
241
326
|
appType: appType,
|
|
242
327
|
fieldCount: fieldCount,
|
|
243
328
|
error: t('create_process.configure_failed') + ': ' + configError.message,
|
|
329
|
+
stage: failureDetails.stage,
|
|
330
|
+
completedStages: failureDetails.completedStages,
|
|
331
|
+
nextStep: failureDetails.nextStep,
|
|
332
|
+
retryCommand: failureDetails.context && failureDetails.context.retryCommand,
|
|
333
|
+
configureProcess: failureDetails.configureProcess,
|
|
244
334
|
}));
|
|
245
335
|
throw new CliError(t('create_process.configure_failed') + ': ' + configError.message, {
|
|
246
336
|
code: 'CREATE_PROCESS_CONFIGURE_FAILED',
|
|
247
|
-
details:
|
|
337
|
+
details: failureDetails,
|
|
248
338
|
});
|
|
249
339
|
}
|
|
250
340
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_TEXT_LIMIT = 240;
|
|
4
|
+
const DEFAULT_KEY_LIMIT = 12;
|
|
5
|
+
|
|
6
|
+
function truncateText(value, limit = DEFAULT_TEXT_LIMIT) {
|
|
7
|
+
const text = value === undefined || value === null ? '' : String(value);
|
|
8
|
+
if (text.length <= limit) {
|
|
9
|
+
return text;
|
|
10
|
+
}
|
|
11
|
+
return text.slice(0, Math.max(0, limit - 3)) + '...';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isPrimitive(value) {
|
|
15
|
+
return value === null || ['string', 'number', 'boolean'].includes(typeof value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function summarizeContent(content) {
|
|
19
|
+
if (content === undefined) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
if (content === null) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
if (typeof content === 'string') {
|
|
26
|
+
return { type: 'string', sample: truncateText(content) };
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(content)) {
|
|
29
|
+
return { type: 'array', length: content.length };
|
|
30
|
+
}
|
|
31
|
+
if (typeof content !== 'object') {
|
|
32
|
+
return content;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const summary = { type: 'object' };
|
|
36
|
+
['processId', 'processCode', 'formUuid', 'version', 'id', 'status'].forEach((key) => {
|
|
37
|
+
if (isPrimitive(content[key])) {
|
|
38
|
+
summary[key] = content[key];
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
if (Array.isArray(content.data)) {
|
|
42
|
+
summary.dataLength = content.data.length;
|
|
43
|
+
}
|
|
44
|
+
const keys = Object.keys(content).slice(0, DEFAULT_KEY_LIMIT);
|
|
45
|
+
if (keys.length > 0) {
|
|
46
|
+
summary.keys = keys;
|
|
47
|
+
}
|
|
48
|
+
return summary;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function summarizeRemoteResult(result) {
|
|
52
|
+
if (result === undefined) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
if (result === null) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (result instanceof Error) {
|
|
59
|
+
const summary = {
|
|
60
|
+
name: result.name,
|
|
61
|
+
message: truncateText(result.message),
|
|
62
|
+
};
|
|
63
|
+
if (result.code) {
|
|
64
|
+
summary.code = result.code;
|
|
65
|
+
}
|
|
66
|
+
if (result.details && typeof result.details === 'object') {
|
|
67
|
+
['stage', 'nextStep'].forEach((key) => {
|
|
68
|
+
if (isPrimitive(result.details[key])) {
|
|
69
|
+
summary[key] = result.details[key];
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
if (Array.isArray(result.details.completedStages)) {
|
|
73
|
+
summary.completedStages = result.details.completedStages.slice();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return summary;
|
|
77
|
+
}
|
|
78
|
+
if (isPrimitive(result)) {
|
|
79
|
+
return truncateText(result);
|
|
80
|
+
}
|
|
81
|
+
if (Array.isArray(result)) {
|
|
82
|
+
return { type: 'array', length: result.length };
|
|
83
|
+
}
|
|
84
|
+
if (typeof result !== 'object') {
|
|
85
|
+
return String(result);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const summary = {};
|
|
89
|
+
[
|
|
90
|
+
'success',
|
|
91
|
+
'errorCode',
|
|
92
|
+
'errorMsg',
|
|
93
|
+
'message',
|
|
94
|
+
'code',
|
|
95
|
+
'status',
|
|
96
|
+
'statusCode',
|
|
97
|
+
'throwable',
|
|
98
|
+
'requestId',
|
|
99
|
+
'__needLogin',
|
|
100
|
+
'__csrfExpired',
|
|
101
|
+
'stage',
|
|
102
|
+
'nextStep',
|
|
103
|
+
].forEach((key) => {
|
|
104
|
+
if (isPrimitive(result[key])) {
|
|
105
|
+
summary[key] = typeof result[key] === 'string'
|
|
106
|
+
? truncateText(result[key])
|
|
107
|
+
: result[key];
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
if (Array.isArray(result.completedStages)) {
|
|
111
|
+
summary.completedStages = result.completedStages.slice();
|
|
112
|
+
}
|
|
113
|
+
if (result.content !== undefined) {
|
|
114
|
+
summary.content = summarizeContent(result.content);
|
|
115
|
+
}
|
|
116
|
+
const included = new Set(Object.keys(summary).concat(['content']));
|
|
117
|
+
const keys = Object.keys(result).filter(key => !included.has(key)).slice(0, DEFAULT_KEY_LIMIT);
|
|
118
|
+
if (keys.length > 0) {
|
|
119
|
+
summary.keys = keys;
|
|
120
|
+
}
|
|
121
|
+
return summary;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function createStageTracker() {
|
|
125
|
+
const completedStages = [];
|
|
126
|
+
return {
|
|
127
|
+
complete(stage) {
|
|
128
|
+
if (stage && !completedStages.includes(stage)) {
|
|
129
|
+
completedStages.push(stage);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
getCompletedStages() {
|
|
133
|
+
return completedStages.slice();
|
|
134
|
+
},
|
|
135
|
+
failure(stage, options = {}) {
|
|
136
|
+
const details = {
|
|
137
|
+
stage,
|
|
138
|
+
completedStages: completedStages.slice(),
|
|
139
|
+
nextStep: options.nextStep || defaultNextStep(stage),
|
|
140
|
+
};
|
|
141
|
+
if (options.context && typeof options.context === 'object') {
|
|
142
|
+
details.context = options.context;
|
|
143
|
+
}
|
|
144
|
+
if (options.cause !== undefined) {
|
|
145
|
+
details.cause = summarizeRemoteResult(options.cause);
|
|
146
|
+
}
|
|
147
|
+
return details;
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function defaultNextStep(stage) {
|
|
153
|
+
switch (stage) {
|
|
154
|
+
case 'validate_inputs':
|
|
155
|
+
return '检查命令参数和本地 JSON 文件路径后重试。';
|
|
156
|
+
case 'load_auth':
|
|
157
|
+
return '执行 openyida login 后重试。';
|
|
158
|
+
case 'create_form':
|
|
159
|
+
return '检查表单字段 JSON 后重试;如果已创建表单,可改用 --formUuid 复用。';
|
|
160
|
+
case 'reuse_form':
|
|
161
|
+
return '确认 formUuid 属于当前应用后重试。';
|
|
162
|
+
case 'switch_form_type':
|
|
163
|
+
return '确认当前账号有表单管理权限,或在宜搭控制台检查表单类型。';
|
|
164
|
+
case 'resolve_process_code':
|
|
165
|
+
return '确认表单已转为流程表单;必要时先运行 configure-process 并显式传入 processCode。';
|
|
166
|
+
case 'configure_process':
|
|
167
|
+
return '修正流程定义后使用 --formUuid 复用已创建表单重试。';
|
|
168
|
+
case 'read_definition':
|
|
169
|
+
return '检查流程定义 JSON 文件内容后重试。';
|
|
170
|
+
case 'query_process_versions':
|
|
171
|
+
return '确认 processCode 有效,并检查账号流程管理权限。';
|
|
172
|
+
case 'create_draft':
|
|
173
|
+
return '确认流程可编辑并检查账号流程管理权限后重试。';
|
|
174
|
+
case 'build_definition':
|
|
175
|
+
return '修正流程节点 DSL 后重试。';
|
|
176
|
+
case 'save_definition':
|
|
177
|
+
return '检查流程节点配置、字段引用和账号权限后重试。';
|
|
178
|
+
case 'publish_process':
|
|
179
|
+
return '确认流程草稿已保存成功,检查发布权限后重试。';
|
|
180
|
+
default:
|
|
181
|
+
return '按错误信息修正后重试。';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = {
|
|
186
|
+
createStageTracker,
|
|
187
|
+
summarizeRemoteResult,
|
|
188
|
+
};
|