openyida 0.1.2 → 1.0.0-beta.0
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/README.md +68 -38
- package/bin/yida.js +164 -761
- package/lib/babel-transform/index.js +244 -0
- package/lib/babel-transform/jsx-utils.js +89 -0
- package/lib/check-update.js +72 -0
- package/lib/copy.js +258 -0
- package/lib/create-app.js +174 -0
- package/lib/create-form.js +2244 -0
- package/lib/create-page.js +89 -0
- package/lib/env.js +164 -0
- package/lib/get-page-config.js +102 -0
- package/lib/get-schema.js +76 -0
- package/lib/login.js +323 -0
- package/lib/publish.js +610 -0
- package/lib/save-share-config.js +268 -0
- package/lib/update-form-config.js +237 -0
- package/lib/utils.js +443 -0
- package/lib/verify-short-url.js +279 -0
- package/package.json +20 -7
- package/project/.cache/demo-schema.json +2353 -0
- package/project/pages/src/demo-birthday-game.js +833 -0
- package/project/pages/src/demo-future-vision-2026.js +1102 -0
- package/project/pages/src/demo-salary-calculator.js +904 -0
- package/project/prd/demo-birthday-game.md +39 -0
- package/project/prd/demo-future-vision-2026.md +78 -0
- package/project/prd/demo-salary-calculator.md +101 -0
- package/scripts/postinstall.js +114 -0
- package/yida-skills/SKILL.md +273 -0
- package/yida-skills/reference/association-form-field.md +469 -0
- package/yida-skills/reference/employee-field.md +17 -0
- package/yida-skills/reference/model-api.md +73 -0
- package/yida-skills/reference/serial-number-field.md +132 -0
- package/yida-skills/reference/yida-api.md +1208 -0
- package/yida-skills/skills/yida-app/SKILL.md +394 -0
- package/yida-skills/skills/yida-create-app/SKILL.md +158 -0
- package/yida-skills/skills/yida-create-form-page/SKILL.md +598 -0
- package/yida-skills/skills/yida-create-page/SKILL.md +103 -0
- package/yida-skills/skills/yida-custom-page/SKILL.md +533 -0
- package/yida-skills/skills/yida-get-schema/SKILL.md +90 -0
- package/yida-skills/skills/yida-login/SKILL.md +200 -0
- package/yida-skills/skills/yida-logout/SKILL.md +58 -0
- package/yida-skills/skills/yida-page-config/SKILL.md +261 -0
- package/yida-skills/skills/yida-publish-page/SKILL.md +113 -0
- package/.eslintrc.json +0 -25
- package/.github/workflows/ci.yml +0 -123
- package/.github/workflows/publish.yml +0 -105
- package/.github/workflows/update-contributors.yml +0 -151
- package/.openclaw/skills/yida-issue/SKILL.md +0 -27
- package/.openclaw/skills/yida-issue/scripts/create-issue.js +0 -317
- package/CLAUDE.md +0 -168
- package/CONTRIBUTING.md +0 -59
- package/install-skills.ps1 +0 -162
- package/install-skills.sh +0 -175
- package/pages/dist/.gitkeep +0 -0
- package/pages/src/.gitkeep +0 -0
- package/prd/salary-calculator.md +0 -15
- package/tests/cli.test.js +0 -930
- package/tests/install.test.js +0 -277
- package/tests/yida-issue.test.js +0 -314
- /package/{config.json → project/config.json} +0 -0
- /package/{.cache → project/pages/dist}/.gitkeep +0 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* save-share-config.js - 宜搭页面公开访问/分享配置保存命令
|
|
3
|
+
*
|
|
4
|
+
* 用法:yidacli save-share-config <appType> <formUuid> <url> <isOpen> [openAuth]
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
const https = require("https");
|
|
10
|
+
const http = require("http");
|
|
11
|
+
const fs = require("fs");
|
|
12
|
+
const path = require("path");
|
|
13
|
+
const querystring = require("querystring");
|
|
14
|
+
|
|
15
|
+
const { findProjectRoot, loadCookieData, triggerLogin, refreshCsrfToken, resolveBaseUrl, isLoginExpired, isCsrfTokenExpired } = require('./utils');
|
|
16
|
+
|
|
17
|
+
const PROJECT_ROOT = findProjectRoot();
|
|
18
|
+
const CONFIG_PATH = path.resolve(PROJECT_ROOT, "config.json");
|
|
19
|
+
const CONFIG = fs.existsSync(CONFIG_PATH) ? JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")) : {};
|
|
20
|
+
const DEFAULT_BASE_URL = CONFIG.defaultBaseUrl || "https://www.aliwork.com";
|
|
21
|
+
|
|
22
|
+
function parseArgs() {
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
if (args.length < 4) {
|
|
25
|
+
console.error("用法: node save-share-config.js <appType> <formUuid> <openUrl> <isOpen> [openAuth]");
|
|
26
|
+
console.error("示例: node .claude/skills/yida-save-share-config/scripts/save-share-config.js \"APP_XXX\" \"FORM-XXX\" \"/o/xxx\" \"y\" \"n\"");
|
|
27
|
+
console.error(" isOpen: y=开启公开访问, n=关闭公开访问");
|
|
28
|
+
console.error(" openAuth: y=需要授权, n=不需要授权(默认)");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
appType: args[0],
|
|
33
|
+
formUuid: args[1],
|
|
34
|
+
openUrl: args[2],
|
|
35
|
+
isOpen: args[3],
|
|
36
|
+
openAuth: args[4] || "n",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function validateParams(params) {
|
|
41
|
+
if (params.isOpen !== "y" && params.isOpen !== "n") {
|
|
42
|
+
throw new Error(`isOpen 必须为 y 或 n,当前值: ${params.isOpen}`);
|
|
43
|
+
}
|
|
44
|
+
if (params.openAuth !== "y" && params.openAuth !== "n") {
|
|
45
|
+
throw new Error(`openAuth 必须为 y 或 n,当前值: ${params.openAuth}`);
|
|
46
|
+
}
|
|
47
|
+
if (params.isOpen === "y" && !params.openUrl) {
|
|
48
|
+
throw new Error("开启公开访问时,openUrl 不能为空");
|
|
49
|
+
}
|
|
50
|
+
if (params.isOpen === "n") {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (!params.openUrl.startsWith("/o/")) {
|
|
54
|
+
throw new Error(`openUrl 必须以 /o/ 开头,当前值: ${params.openUrl}`);
|
|
55
|
+
}
|
|
56
|
+
const pathPart = params.openUrl.slice(3);
|
|
57
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(pathPart)) {
|
|
58
|
+
throw new Error(`openUrl 路径部分只支持 a-z A-Z 0-9 _ -,当前值: ${params.openUrl}`);
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
function sendPostRequest(baseUrl, cookies, requestPath, postData) {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const cookieHeader = cookies
|
|
67
|
+
.map((cookie) => `${cookie.name}=${cookie.value}`)
|
|
68
|
+
.join("; ");
|
|
69
|
+
|
|
70
|
+
const parsedUrl = new URL(baseUrl);
|
|
71
|
+
const isHttps = parsedUrl.protocol === "https:";
|
|
72
|
+
const requestModule = isHttps ? https : http;
|
|
73
|
+
|
|
74
|
+
const requestOptions = {
|
|
75
|
+
hostname: parsedUrl.hostname,
|
|
76
|
+
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
77
|
+
path: requestPath,
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers: {
|
|
80
|
+
Origin: baseUrl,
|
|
81
|
+
Referer: baseUrl + "/",
|
|
82
|
+
Cookie: cookieHeader,
|
|
83
|
+
Accept: "application/json, text/json",
|
|
84
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
85
|
+
"x-requested-with": "XMLHttpRequest",
|
|
86
|
+
},
|
|
87
|
+
timeout: 30000,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const request = requestModule.request(requestOptions, (response) => {
|
|
91
|
+
let responseData = "";
|
|
92
|
+
response.on("data", (chunk) => { responseData += chunk; });
|
|
93
|
+
response.on("end", () => {
|
|
94
|
+
console.error(` HTTP 状态码: ${response.statusCode}`);
|
|
95
|
+
let parsed;
|
|
96
|
+
try {
|
|
97
|
+
parsed = JSON.parse(responseData);
|
|
98
|
+
} catch (parseError) {
|
|
99
|
+
console.error(` 响应内容: ${responseData.substring(0, 500)}`);
|
|
100
|
+
resolve({ success: false, errorMsg: `HTTP ${response.statusCode}: 响应非 JSON` });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (isLoginExpired(parsed)) {
|
|
104
|
+
console.error(` 检测到登录过期: ${parsed.errorMsg}`);
|
|
105
|
+
resolve({ __needLogin: true });
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (isCsrfTokenExpired(parsed)) {
|
|
109
|
+
console.error(` 检测到 csrf_token 过期: ${parsed.errorMsg}`);
|
|
110
|
+
resolve({ __csrfExpired: true });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
resolve(parsed);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
request.on("timeout", () => {
|
|
118
|
+
console.error(" ❌ 请求超时");
|
|
119
|
+
request.destroy();
|
|
120
|
+
reject(new Error("请求超时"));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
request.on("error", (requestError) => {
|
|
124
|
+
reject(requestError);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
request.write(postData);
|
|
128
|
+
request.end();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function main() {
|
|
133
|
+
const { appType, formUuid, openUrl, isOpen, openAuth } = parseArgs();
|
|
134
|
+
|
|
135
|
+
console.error("=".repeat(50));
|
|
136
|
+
console.error(" save-share-config - 宜搭公开访问配置保存工具");
|
|
137
|
+
console.error("=".repeat(50));
|
|
138
|
+
console.error(`\n 应用 ID: ${appType}`);
|
|
139
|
+
console.error(` 表单 UUID: ${formUuid}`);
|
|
140
|
+
console.error(` 公开访问路径: ${openUrl || "(空)"}`);
|
|
141
|
+
console.error(` 是否开放: ${isOpen === "y" ? "是" : "否"}`);
|
|
142
|
+
console.error(` 是否需要授权: ${openAuth === "y" ? "是" : "否"}`);
|
|
143
|
+
|
|
144
|
+
console.error("\n📋 Step 0: 验证参数");
|
|
145
|
+
try {
|
|
146
|
+
validateParams({ openUrl, isOpen, openAuth });
|
|
147
|
+
console.error(" ✅ 参数验证通过");
|
|
148
|
+
} catch (err) {
|
|
149
|
+
console.error(` ❌ 参数验证失败: ${err.message}`);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.error("\n🔑 Step 1: 读取登录态");
|
|
154
|
+
let cookieData = loadCookieData();
|
|
155
|
+
if (!cookieData) {
|
|
156
|
+
console.error(" ⚠️ 未找到本地登录态,触发登录...");
|
|
157
|
+
cookieData = triggerLogin();
|
|
158
|
+
}
|
|
159
|
+
let { cookies } = cookieData;
|
|
160
|
+
let baseUrl = resolveBaseUrl(cookieData);
|
|
161
|
+
console.error(` ✅ 登录态已就绪(${baseUrl})`);
|
|
162
|
+
|
|
163
|
+
console.error("\n💾 Step 2: 保存公开访问配置");
|
|
164
|
+
console.error(" 发送 saveShareConfig 请求...");
|
|
165
|
+
let { csrf_token: csrfToken } = cookieData;
|
|
166
|
+
|
|
167
|
+
const authConfig = JSON.stringify({
|
|
168
|
+
openAuth: openAuth,
|
|
169
|
+
authSources: [],
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const postData = querystring.stringify({
|
|
173
|
+
_api: "Share.saveShareConfig",
|
|
174
|
+
_csrf_token: csrfToken,
|
|
175
|
+
_locale_time_zone_offset: "28800000",
|
|
176
|
+
formUuid: formUuid,
|
|
177
|
+
shareUrl: "",
|
|
178
|
+
openUrl: openUrl,
|
|
179
|
+
isOpen: isOpen,
|
|
180
|
+
openPageAuthConfig: authConfig,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
let result = await sendPostRequest(
|
|
184
|
+
baseUrl,
|
|
185
|
+
cookies,
|
|
186
|
+
`/dingtalk/web/${appType}/query/formdesign/saveShareConfig.json`,
|
|
187
|
+
postData
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
if (result && result.__csrfExpired) {
|
|
191
|
+
cookieData = refreshCsrfToken();
|
|
192
|
+
csrfToken = cookieData.csrf_token;
|
|
193
|
+
cookies = cookieData.cookies;
|
|
194
|
+
baseUrl = resolveBaseUrl(cookieData);
|
|
195
|
+
const newPostData = querystring.stringify({
|
|
196
|
+
_api: "Share.saveShareConfig",
|
|
197
|
+
_csrf_token: csrfToken,
|
|
198
|
+
_locale_time_zone_offset: "28800000",
|
|
199
|
+
formUuid: formUuid,
|
|
200
|
+
shareUrl: "",
|
|
201
|
+
openUrl: openUrl,
|
|
202
|
+
isOpen: isOpen,
|
|
203
|
+
openPageAuthConfig: authConfig,
|
|
204
|
+
});
|
|
205
|
+
console.error(" 🔄 重新发送 saveShareConfig 请求(csrf_token 已刷新)...");
|
|
206
|
+
result = await sendPostRequest(
|
|
207
|
+
baseUrl,
|
|
208
|
+
cookies,
|
|
209
|
+
`/dingtalk/web/${appType}/query/formdesign/saveShareConfig.json`,
|
|
210
|
+
newPostData
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (result && result.__needLogin) {
|
|
215
|
+
cookieData = triggerLogin();
|
|
216
|
+
csrfToken = cookieData.csrf_token;
|
|
217
|
+
cookies = cookieData.cookies;
|
|
218
|
+
baseUrl = resolveBaseUrl(cookieData);
|
|
219
|
+
const newPostData = querystring.stringify({
|
|
220
|
+
_api: "Share.saveShareConfig",
|
|
221
|
+
_csrf_token: csrfToken,
|
|
222
|
+
_locale_time_zone_offset: "28800000",
|
|
223
|
+
formUuid: formUuid,
|
|
224
|
+
shareUrl: "",
|
|
225
|
+
openUrl: openUrl,
|
|
226
|
+
isOpen: isOpen,
|
|
227
|
+
openPageAuthConfig: authConfig,
|
|
228
|
+
});
|
|
229
|
+
console.error(" 🔄 重新发送 saveShareConfig 请求...");
|
|
230
|
+
result = await sendPostRequest(
|
|
231
|
+
baseUrl,
|
|
232
|
+
cookies,
|
|
233
|
+
`/dingtalk/web/${appType}/query/formdesign/saveShareConfig.json`,
|
|
234
|
+
newPostData
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
console.error("\n" + "=".repeat(50));
|
|
239
|
+
if (result && !result.__needLogin && !result.__csrfExpired) {
|
|
240
|
+
if (result.success) {
|
|
241
|
+
console.error(" ✅ 配置保存成功!");
|
|
242
|
+
console.error("=".repeat(50));
|
|
243
|
+
console.log(JSON.stringify({
|
|
244
|
+
success: true,
|
|
245
|
+
openUrl: isOpen === "y" ? openUrl : null,
|
|
246
|
+
isOpen: isOpen === "y",
|
|
247
|
+
message: "公开访问配置已保存"
|
|
248
|
+
}, null, 2));
|
|
249
|
+
} else {
|
|
250
|
+
console.error(` ❌ 保存失败: ${result.errorMsg || "未知错误"}`);
|
|
251
|
+
console.error("=".repeat(50));
|
|
252
|
+
console.log(JSON.stringify({
|
|
253
|
+
success: false,
|
|
254
|
+
message: result.errorMsg || "保存失败",
|
|
255
|
+
errorCode: result.errorCode
|
|
256
|
+
}, null, 2));
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
console.error(" ❌ 请求失败");
|
|
260
|
+
console.error("=".repeat(50));
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
main().catch((error) => {
|
|
266
|
+
console.error(`\n❌ 保存异常: ${error.message}`);
|
|
267
|
+
process.exit(1);
|
|
268
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
const https = require("https");
|
|
2
|
+
const http = require("http");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const querystring = require("querystring");
|
|
6
|
+
|
|
7
|
+
const { findProjectRoot, loadCookieData, triggerLogin, refreshCsrfToken, resolveBaseUrl, isLoginExpired, isCsrfTokenExpired } = require('./utils');
|
|
8
|
+
|
|
9
|
+
const PROJECT_ROOT = findProjectRoot();
|
|
10
|
+
const CONFIG_PATH = path.resolve(PROJECT_ROOT, "config.json");
|
|
11
|
+
const CONFIG = fs.existsSync(CONFIG_PATH) ? JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")) : {};
|
|
12
|
+
const DEFAULT_BASE_URL = CONFIG.defaultBaseUrl || "https://www.aliwork.com";
|
|
13
|
+
|
|
14
|
+
function parseArgs() {
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
if (args.length < 4) {
|
|
17
|
+
console.error("用法: node update-form-config.js <appType> <formUuid> <isRenderNav> <title>");
|
|
18
|
+
console.error("示例: node .claude/skills/yida-page-config/scripts/update-form-config.js \"APP_XXX\" \"FORM_XXX\" \"false\" \"我的页面\"");
|
|
19
|
+
console.error("");
|
|
20
|
+
console.error("参数说明:");
|
|
21
|
+
console.error(" isRenderNav: true=显示顶部导航, false=隐藏顶部导航");
|
|
22
|
+
console.error(" title: 页面标题(必填)");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
appType: args[0],
|
|
27
|
+
formUuid: args[1],
|
|
28
|
+
isRenderNav: args[2],
|
|
29
|
+
title: args[3],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function buildPostData(csrfToken, formUuid, isRenderNav, title) {
|
|
34
|
+
const titleJson = JSON.stringify({
|
|
35
|
+
pureEn_US: title,
|
|
36
|
+
en_US: title,
|
|
37
|
+
zh_CN: title,
|
|
38
|
+
envLocale: null,
|
|
39
|
+
type: "i18n",
|
|
40
|
+
ja_JP: null,
|
|
41
|
+
key: null,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return querystring.stringify({
|
|
45
|
+
_api: "Form.updateFormSchemaInfo",
|
|
46
|
+
_csrf_token: csrfToken,
|
|
47
|
+
_locale_time_zone_offset: "28800000",
|
|
48
|
+
formUuid: formUuid,
|
|
49
|
+
serialSwitch: "n",
|
|
50
|
+
consultPerson: "",
|
|
51
|
+
defaultManager: "n",
|
|
52
|
+
submissionRule: "RESUBMIT",
|
|
53
|
+
redirectConfig: "",
|
|
54
|
+
pushTask: "y",
|
|
55
|
+
defaultOrder: "cd",
|
|
56
|
+
showPrint: "y",
|
|
57
|
+
relateUuid: "",
|
|
58
|
+
title: titleJson,
|
|
59
|
+
pageType: "web,mobile",
|
|
60
|
+
isInner: "y",
|
|
61
|
+
isNew: "n",
|
|
62
|
+
isAgent: "y",
|
|
63
|
+
showAgent: "n",
|
|
64
|
+
showDingGroup: "y",
|
|
65
|
+
reStart: "n",
|
|
66
|
+
previewConfig: "y",
|
|
67
|
+
formulaType: "n",
|
|
68
|
+
displayTitle: "%24%7Blegao_creator%7D%E5%8F%91%E8%B5%B7%E7%9A%84%24%7Blegao_formname%7D",
|
|
69
|
+
displayType: "RE",
|
|
70
|
+
isRenderNav: isRenderNav,
|
|
71
|
+
manageCustomActionInfo: "[]",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
function sendPostRequest(baseUrl, cookies, requestPath, postData) {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
const cookieHeader = cookies
|
|
79
|
+
.map((cookie) => `${cookie.name}=${cookie.value}`)
|
|
80
|
+
.join("; ");
|
|
81
|
+
|
|
82
|
+
const parsedUrl = new URL(baseUrl);
|
|
83
|
+
const isHttps = parsedUrl.protocol === "https:";
|
|
84
|
+
const requestModule = isHttps ? https : http;
|
|
85
|
+
|
|
86
|
+
const requestOptions = {
|
|
87
|
+
hostname: parsedUrl.hostname,
|
|
88
|
+
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
89
|
+
path: requestPath,
|
|
90
|
+
method: "POST",
|
|
91
|
+
headers: {
|
|
92
|
+
Origin: baseUrl,
|
|
93
|
+
Referer: baseUrl + "/",
|
|
94
|
+
Cookie: cookieHeader,
|
|
95
|
+
Accept: "application/json, text/json",
|
|
96
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
97
|
+
"x-requested-with": "XMLHttpRequest",
|
|
98
|
+
},
|
|
99
|
+
timeout: 30000,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const request = requestModule.request(requestOptions, (response) => {
|
|
103
|
+
let responseData = "";
|
|
104
|
+
response.on("data", (chunk) => { responseData += chunk; });
|
|
105
|
+
response.on("end", () => {
|
|
106
|
+
console.error(` HTTP 状态码: ${response.statusCode}`);
|
|
107
|
+
let parsed;
|
|
108
|
+
try {
|
|
109
|
+
parsed = JSON.parse(responseData);
|
|
110
|
+
} catch (parseError) {
|
|
111
|
+
console.error(` 响应内容: ${responseData.substring(0, 500)}`);
|
|
112
|
+
resolve({ success: false, errorMsg: `HTTP ${response.statusCode}: 响应非 JSON` });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (isLoginExpired(parsed)) {
|
|
116
|
+
console.error(` 检测到登录过期: ${parsed.errorMsg}`);
|
|
117
|
+
resolve({ __needLogin: true });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (isCsrfTokenExpired(parsed)) {
|
|
121
|
+
console.error(` 检测到 csrf_token 过期: ${parsed.errorMsg}`);
|
|
122
|
+
resolve({ __csrfExpired: true });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
resolve(parsed);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
request.on("timeout", () => {
|
|
130
|
+
console.error(" ❌ 请求超时");
|
|
131
|
+
request.destroy();
|
|
132
|
+
reject(new Error("请求超时"));
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
request.on("error", (requestError) => {
|
|
136
|
+
reject(requestError);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
request.write(postData);
|
|
140
|
+
request.end();
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function main() {
|
|
145
|
+
const { appType, formUuid, isRenderNav, title } = parseArgs();
|
|
146
|
+
|
|
147
|
+
console.error("=".repeat(50));
|
|
148
|
+
console.error(" update-form-config - 宜搭表单配置更新工具");
|
|
149
|
+
console.error("=".repeat(50));
|
|
150
|
+
console.error(`\n 应用 ID: ${appType}`);
|
|
151
|
+
console.error(` 表单 UUID: ${formUuid}`);
|
|
152
|
+
console.error(` 显示导航: ${isRenderNav === "true" ? "是" : "否"}`);
|
|
153
|
+
console.error(` 页面标题: ${title}`);
|
|
154
|
+
|
|
155
|
+
console.error("\n🔑 Step 1: 读取登录态");
|
|
156
|
+
let cookieData = loadCookieData();
|
|
157
|
+
if (!cookieData) {
|
|
158
|
+
console.error(" ⚠️ 未找到本地登录态,触发登录...");
|
|
159
|
+
cookieData = triggerLogin();
|
|
160
|
+
}
|
|
161
|
+
let { cookies } = cookieData;
|
|
162
|
+
let baseUrl = resolveBaseUrl(cookieData);
|
|
163
|
+
console.error(` ✅ 登录态已就绪(${baseUrl})`);
|
|
164
|
+
|
|
165
|
+
console.error("\n💾 Step 2: 更新表单配置(隐藏顶部导航)");
|
|
166
|
+
console.error(" 发送 updateFormSchemaInfo 请求...");
|
|
167
|
+
let { csrf_token: csrfToken } = cookieData;
|
|
168
|
+
|
|
169
|
+
const postData = buildPostData(csrfToken, formUuid, isRenderNav, title);
|
|
170
|
+
|
|
171
|
+
let result = await sendPostRequest(
|
|
172
|
+
baseUrl,
|
|
173
|
+
cookies,
|
|
174
|
+
`/dingtalk/web/${appType}/query/formdesign/updateFormSchemaInfo.json`,
|
|
175
|
+
postData
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
if (result && result.__csrfExpired) {
|
|
179
|
+
cookieData = refreshCsrfToken();
|
|
180
|
+
csrfToken = cookieData.csrf_token;
|
|
181
|
+
cookies = cookieData.cookies;
|
|
182
|
+
baseUrl = resolveBaseUrl(cookieData);
|
|
183
|
+
const newPostData = buildPostData(csrfToken, formUuid, isRenderNav, title);
|
|
184
|
+
console.error(" 🔄 重新发送请求(csrf_token 已刷新)...");
|
|
185
|
+
result = await sendPostRequest(
|
|
186
|
+
baseUrl,
|
|
187
|
+
cookies,
|
|
188
|
+
`/dingtalk/web/${appType}/query/formdesign/updateFormSchemaInfo.json`,
|
|
189
|
+
newPostData
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (result && result.__needLogin) {
|
|
194
|
+
cookieData = triggerLogin();
|
|
195
|
+
csrfToken = cookieData.csrf_token;
|
|
196
|
+
cookies = cookieData.cookies;
|
|
197
|
+
baseUrl = resolveBaseUrl(cookieData);
|
|
198
|
+
const newPostData = buildPostData(csrfToken, formUuid, isRenderNav, title);
|
|
199
|
+
console.error(" 🔄 重新发送请求...");
|
|
200
|
+
result = await sendPostRequest(
|
|
201
|
+
baseUrl,
|
|
202
|
+
cookies,
|
|
203
|
+
`/dingtalk/web/${appType}/query/formdesign/updateFormSchemaInfo.json`,
|
|
204
|
+
newPostData
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
console.error("\n" + "=".repeat(50));
|
|
209
|
+
if (result && !result.__needLogin && !result.__csrfExpired) {
|
|
210
|
+
if (result.success) {
|
|
211
|
+
console.error(" ✅ 配置更新成功!");
|
|
212
|
+
console.error("=".repeat(50));
|
|
213
|
+
console.log(JSON.stringify({
|
|
214
|
+
success: true,
|
|
215
|
+
isRenderNav: isRenderNav === "true",
|
|
216
|
+
message: isRenderNav === "true" ? "已显示顶部导航" : "已隐藏顶部导航"
|
|
217
|
+
}, null, 2));
|
|
218
|
+
} else {
|
|
219
|
+
console.error(` ❌ 更新失败: ${result.errorMsg || "未知错误"}`);
|
|
220
|
+
console.error("=".repeat(50));
|
|
221
|
+
console.log(JSON.stringify({
|
|
222
|
+
success: false,
|
|
223
|
+
message: result.errorMsg || "更新失败",
|
|
224
|
+
errorCode: result.errorCode
|
|
225
|
+
}, null, 2));
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
console.error(" ❌ 请求失败");
|
|
229
|
+
console.error("=".repeat(50));
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
main().catch((error) => {
|
|
235
|
+
console.error(`\n❌ 更新异常: ${error.message}`);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
});
|