cloudcc-cli 2.3.8 → 2.4.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/.cursor/skills/{cloudcc-cli-dev → dev-guide}/SKILL.md +5 -1
- package/README.md +82 -1
- package/bin/cc.js +2 -1
- package/bin/index.js +1 -0
- package/cloudcc-dev-skill/SKILL.md +31 -8
- package/cloudcc-dev-skill/cloudcc-dev-html.md +42 -0
- package/cloudcc-dev-skill/config.json +2 -2
- package/mcp/index.js +27 -3
- package/mcp/tools/JSP Migrator/handler.js +51 -866
- package/mcp/tools/Object Creator/handler.js +14 -4
- package/mcp/tools/Object Fields Creator/handler.js +149 -3
- package/package.json +1 -1
- package/src/classes/docs/devguide.md +758 -364
- package/src/classes/docs/introduction.md +279 -143
- package/src/fields/buildFieldData.js +692 -0
- package/src/fields/create.js +10 -170
- package/src/fields/detail.js +37 -0
- package/src/fields/docs/devguide.md +168 -44
- package/src/fields/docs/introduction.md +2 -0
- package/src/fields/fields/A.js +3 -2
- package/src/fields/fields/AD.js +4 -2
- package/src/fields/fields/B.js +8 -5
- package/src/fields/fields/C.js +13 -5
- package/src/fields/fields/D.js +4 -4
- package/src/fields/fields/E.js +10 -5
- package/src/fields/fields/ENC.js +27 -8
- package/src/fields/fields/ENCD.js +27 -8
- package/src/fields/fields/F.js +4 -4
- package/src/fields/fields/FL.js +8 -4
- package/src/fields/fields/H.js +4 -4
- package/src/fields/fields/IMG.js +23 -5
- package/src/fields/fields/J.js +21 -6
- package/src/fields/fields/L.js +32 -8
- package/src/fields/fields/LT.js +23 -6
- package/src/fields/fields/M.js +2 -2
- package/src/fields/fields/MR.js +2 -2
- package/src/fields/fields/N.js +31 -8
- package/src/fields/fields/P.js +13 -5
- package/src/fields/fields/Q.js +42 -12
- package/src/fields/fields/S.js +19 -7
- package/src/fields/fields/SCORE.js +9 -4
- package/src/fields/fields/T.js +4 -4
- package/src/fields/fields/U.js +18 -5
- package/src/fields/fields/X.js +20 -6
- package/src/fields/fields/Y.js +17 -4
- package/src/fields/index.js +2 -0
- package/src/fields/update.js +148 -0
- package/src/jsp/analyze.js +17 -0
- package/src/jsp/doc.js +18 -0
- package/src/jsp/docs/devguide.md +111 -0
- package/src/jsp/docs/introduction.md +50 -0
- package/src/jsp/docs.js +21 -0
- package/src/jsp/index.js +14 -0
- package/src/jsp/migration.js +871 -0
- package/src/jsp/split.js +17 -0
- package/src/object/create.js +36 -10
- package/src/object/docs/devguide.md +6 -3
- package/src/project/docs/devguide.md +1 -1
- package/src/timer/docs/devguide.md +849 -400
- package/src/timer/docs/introduction.md +343 -231
- package/src/triggers/docs/devguide.md +929 -352
- package/src/triggers/docs/introduction.md +640 -369
- package/src/version/listModuleCommands.js +6 -0
- package/test/fields.cli.test.js +3 -1
- package/test/jsp.cli.test.js +70 -0
- package/test/object.cli.test.js +9 -1
package/src/fields/fields/Q.js
CHANGED
|
@@ -1,35 +1,65 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 选项列表(多选)字段(Q)
|
|
2
|
+
* 选项列表(多选)字段(Q)配置模板(与 `L` 类似,另含 `visibleLines`、`showalloptions`)
|
|
3
|
+
* @param {string} useGlobalSelect 是否使用全局选项列表:`"0"` 否,`"1"` 是
|
|
4
|
+
* @param {string} edittype 选择样式,写入 `obj.edittype`:`radio` 或 `select`(多选常见为 `select`)
|
|
5
|
+
* @param {string} isPicklistSorted 是否按字母排序:`"0"` 否,`"1"` 是
|
|
6
|
+
* @param {string} defPl 是否将第一个值作为默认值:`"0"` 否,`"1"` 是
|
|
7
|
+
* @param {string} globalSelectId 全局选项列表 id(`useGlobalSelect` 为 `"1"` 时使用)
|
|
8
|
+
* @param {string} visibleLines 下拉最多展示几行选项,写入 `obj.visibleLines`
|
|
9
|
+
* @param {string} showalloptions 是否显示所有选项:`"0"` 否,`"1"` 是,写入 `obj.showalloptions`
|
|
3
10
|
*/
|
|
4
|
-
module.exports = function (
|
|
11
|
+
module.exports = function (
|
|
12
|
+
objid,
|
|
13
|
+
nameLabel,
|
|
14
|
+
apiname,
|
|
15
|
+
ptext,
|
|
16
|
+
helps = "",
|
|
17
|
+
defaultValue = "",
|
|
18
|
+
profileList,
|
|
19
|
+
useGlobalSelect = "0",
|
|
20
|
+
edittype = "select",
|
|
21
|
+
isPicklistSorted = "0",
|
|
22
|
+
defPl = "0",
|
|
23
|
+
globalSelectId = "",
|
|
24
|
+
visibleLines = "4",
|
|
25
|
+
showalloptions = "0"
|
|
26
|
+
) {
|
|
27
|
+
const ugs = useGlobalSelect === "1" ? "1" : "0";
|
|
28
|
+
const et = edittype === "radio" ? "radio" : "select";
|
|
29
|
+
const sorted = isPicklistSorted === "1" ? "1" : "0";
|
|
30
|
+
const dp = defPl === "1" ? "1" : "0";
|
|
31
|
+
const gid = ugs === "1" ? String(globalSelectId || "").trim() : "";
|
|
32
|
+
const vl = String(visibleLines || "4").trim() || "4";
|
|
33
|
+
const sao = showalloptions === "1" ? "1" : "0";
|
|
5
34
|
return {
|
|
6
|
-
"objid": objid,
|
|
7
35
|
"obj": {
|
|
8
36
|
"id": "",
|
|
9
37
|
"nameLabel": nameLabel,
|
|
10
38
|
"apiname": apiname,
|
|
11
39
|
"schemefieldLength": "255",
|
|
12
|
-
"edittype":
|
|
13
|
-
"visibleLines":
|
|
14
|
-
"showalloptions":
|
|
40
|
+
"edittype": et,
|
|
41
|
+
"visibleLines": vl,
|
|
42
|
+
"showalloptions": sao,
|
|
15
43
|
"renderstyle": "1",
|
|
16
44
|
"remark": "",
|
|
17
|
-
"helps": ""
|
|
45
|
+
"helps": helps !== undefined && helps !== null ? String(helps) : "",
|
|
46
|
+
"defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
|
|
18
47
|
},
|
|
48
|
+
"objid": objid,
|
|
19
49
|
"dtype": "Q:选项列表(多选)",
|
|
20
50
|
"fdtype": "Q",
|
|
21
51
|
"ischecked": "false",
|
|
22
|
-
"useGlobalSelect":
|
|
23
|
-
"globalSelectId":
|
|
52
|
+
"useGlobalSelect": ugs,
|
|
53
|
+
"globalSelectId": gid,
|
|
24
54
|
"ptext": ptext,
|
|
25
|
-
"isPicklistSorted":
|
|
26
|
-
"defPl":
|
|
55
|
+
"isPicklistSorted": sorted,
|
|
56
|
+
"defPl": dp,
|
|
27
57
|
"iscover": "",
|
|
28
58
|
"formulaText": "",
|
|
29
59
|
"profileFieldJson": profileList.map(profile => ({
|
|
30
60
|
"profileId": profile.id,
|
|
31
61
|
"visible": "true",
|
|
32
62
|
"readonly": "false"
|
|
33
|
-
}))
|
|
63
|
+
}))
|
|
34
64
|
}
|
|
35
65
|
}
|
package/src/fields/fields/S.js
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 文本字段(S)配置模板
|
|
3
3
|
*/
|
|
4
|
-
module.exports = function (
|
|
4
|
+
module.exports = function (
|
|
5
|
+
objid,
|
|
6
|
+
nameLabel,
|
|
7
|
+
apiname,
|
|
8
|
+
schemefieldLength,
|
|
9
|
+
helps,
|
|
10
|
+
isrepeat,
|
|
11
|
+
casesensitive,
|
|
12
|
+
placeholder,
|
|
13
|
+
defaultValue,
|
|
14
|
+
profileList
|
|
15
|
+
) {
|
|
16
|
+
const length = schemefieldLength ? String(schemefieldLength) : "255";
|
|
5
17
|
return {
|
|
6
18
|
"objid": objid,
|
|
7
19
|
"obj": {
|
|
@@ -9,12 +21,12 @@ module.exports = function (objid, nameLabel, apiname, profileList) {
|
|
|
9
21
|
"nameLabel": nameLabel,
|
|
10
22
|
"apiname": apiname,
|
|
11
23
|
"remark": "",
|
|
12
|
-
"helps": "",
|
|
13
|
-
"schemefieldLength":
|
|
14
|
-
"isrepeat": "true",
|
|
15
|
-
"casesensitive": "",
|
|
16
|
-
"placeholder": "",
|
|
17
|
-
"defaultValue": ""
|
|
24
|
+
"helps": helps ? String(helps) : "",
|
|
25
|
+
"schemefieldLength": length,
|
|
26
|
+
"isrepeat": isrepeat !== undefined ? String(isrepeat) : "true",
|
|
27
|
+
"casesensitive": casesensitive ? String(casesensitive) : "",
|
|
28
|
+
"placeholder": placeholder ? String(placeholder) : "",
|
|
29
|
+
"defaultValue": defaultValue ? String(defaultValue) : ""
|
|
18
30
|
},
|
|
19
31
|
"dtype": "S:文本",
|
|
20
32
|
"fdtype": "S",
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 评分字段(SCORE)配置模板
|
|
3
|
+
* schemefieldLength:最大评分,控制星星图标个数;平台允许 1~100,默认 10
|
|
3
4
|
*/
|
|
4
|
-
module.exports = function (objid, nameLabel, apiname, profileList) {
|
|
5
|
+
module.exports = function (objid, nameLabel, apiname, helps = "", defaultValue = "", schemefieldLength = "10", profileList) {
|
|
6
|
+
const len =
|
|
7
|
+
schemefieldLength !== undefined && schemefieldLength !== null && String(schemefieldLength).trim() !== ""
|
|
8
|
+
? String(schemefieldLength).trim()
|
|
9
|
+
: "10";
|
|
5
10
|
return {
|
|
6
11
|
"objid": objid,
|
|
7
12
|
"obj": {
|
|
@@ -9,9 +14,9 @@ module.exports = function (objid, nameLabel, apiname, profileList) {
|
|
|
9
14
|
"nameLabel": nameLabel,
|
|
10
15
|
"apiname": apiname,
|
|
11
16
|
"remark": "",
|
|
12
|
-
"helps": "",
|
|
13
|
-
"schemefieldLength":
|
|
14
|
-
"defaultValue": ""
|
|
17
|
+
"helps": helps !== undefined && helps !== null ? String(helps) : "",
|
|
18
|
+
"schemefieldLength": len,
|
|
19
|
+
"defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
|
|
15
20
|
},
|
|
16
21
|
"dtype": "SCORE:评分",
|
|
17
22
|
"fdtype": "SCORE",
|
package/src/fields/fields/T.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 时间字段(T)配置模板
|
|
3
3
|
*/
|
|
4
|
-
module.exports = function (objid, nameLabel, apiname, profileList) {
|
|
4
|
+
module.exports = function (objid, nameLabel, apiname, helps = "", defaultValue = "", profileList) {
|
|
5
5
|
return {
|
|
6
6
|
"objid": objid,
|
|
7
7
|
"obj": {
|
|
8
8
|
"id": "",
|
|
9
9
|
"nameLabel": nameLabel,
|
|
10
10
|
"apiname": apiname,
|
|
11
|
-
"schemefieldLength": "255",
|
|
12
11
|
"remark": "",
|
|
13
|
-
"helps": "",
|
|
14
|
-
"
|
|
12
|
+
"helps": helps !== undefined && helps !== null ? String(helps) : "",
|
|
13
|
+
"schemefieldLength": "20",
|
|
14
|
+
"defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
|
|
15
15
|
},
|
|
16
16
|
"dtype": "T:时间",
|
|
17
17
|
"fdtype": "T",
|
package/src/fields/fields/U.js
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* URL字段(U)配置模板
|
|
3
3
|
*/
|
|
4
|
-
module.exports = function (objid, nameLabel, apiname, profileList) {
|
|
4
|
+
module.exports = function (objid, nameLabel, apiname, helps, edittype, defaultValue, profileList) {
|
|
5
|
+
const openMode = edittype && String(edittype).trim() !== ""
|
|
6
|
+
? String(edittype).trim()
|
|
7
|
+
: "_blank";
|
|
8
|
+
const safeEdittype = openMode === "_self" ? "_self" : "_blank";
|
|
5
9
|
return {
|
|
10
|
+
// 对象ID
|
|
6
11
|
"objid": objid,
|
|
7
12
|
"obj": {
|
|
13
|
+
// 字段ID
|
|
8
14
|
"id": "",
|
|
15
|
+
// 字段名称
|
|
9
16
|
"nameLabel": nameLabel,
|
|
17
|
+
// 字段API名称
|
|
10
18
|
"apiname": apiname,
|
|
19
|
+
// 字段备注
|
|
11
20
|
"remark": "",
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"
|
|
21
|
+
// 字段帮助
|
|
22
|
+
"helps": helps !== undefined && helps !== null ? String(helps) : "",
|
|
23
|
+
// 最大输入长度(字符)
|
|
24
|
+
"schemefieldLength": "2000",
|
|
25
|
+
// URL打开方式: _blank 新窗口打开, _self 当前窗口打开
|
|
26
|
+
"edittype": safeEdittype,
|
|
27
|
+
// 默认值
|
|
28
|
+
"defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
|
|
16
29
|
},
|
|
17
30
|
"dtype": "U:URL",
|
|
18
31
|
"fdtype": "U",
|
package/src/fields/fields/X.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 文本区字段(X)
|
|
2
|
+
* 文本区字段(X)配置模板(多行文本,schemefieldLength 为最大字符数,常见上限 4000)
|
|
3
3
|
*/
|
|
4
|
-
module.exports = function (
|
|
4
|
+
module.exports = function (
|
|
5
|
+
objid,
|
|
6
|
+
nameLabel,
|
|
7
|
+
apiname,
|
|
8
|
+
helps = "",
|
|
9
|
+
defaultValue = "",
|
|
10
|
+
schemefieldLength = "4000",
|
|
11
|
+
placeholder = "",
|
|
12
|
+
profileList
|
|
13
|
+
) {
|
|
14
|
+
const len =
|
|
15
|
+
schemefieldLength !== undefined && schemefieldLength !== null && String(schemefieldLength).trim() !== ""
|
|
16
|
+
? String(schemefieldLength).trim()
|
|
17
|
+
: "4000";
|
|
18
|
+
const ph = placeholder !== undefined && placeholder !== null ? String(placeholder) : "";
|
|
5
19
|
return {
|
|
6
20
|
"objid": objid,
|
|
7
21
|
"obj": {
|
|
@@ -9,10 +23,10 @@ module.exports = function (objid, nameLabel, apiname, profileList) {
|
|
|
9
23
|
"nameLabel": nameLabel,
|
|
10
24
|
"apiname": apiname,
|
|
11
25
|
"remark": "",
|
|
12
|
-
"helps": "",
|
|
13
|
-
"defaultValue": "",
|
|
14
|
-
"schemefieldLength":
|
|
15
|
-
"placeholder":
|
|
26
|
+
"helps": helps !== undefined && helps !== null ? String(helps) : "",
|
|
27
|
+
"defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : "",
|
|
28
|
+
"schemefieldLength": len,
|
|
29
|
+
"placeholder": ph
|
|
16
30
|
},
|
|
17
31
|
"dtype": "X",
|
|
18
32
|
"fdtype": "X",
|
package/src/fields/fields/Y.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 查找关系字段(Y)配置模板
|
|
3
|
+
* @param {string} lookupObjDefaultField 搜索辅助字段(`obj.lookupObjDefaultField`);搜索时用于展示,可为 API 名字段等
|
|
3
4
|
*/
|
|
4
|
-
module.exports = function (
|
|
5
|
+
module.exports = function (
|
|
6
|
+
objid,
|
|
7
|
+
nameLabel,
|
|
8
|
+
apiname,
|
|
9
|
+
lookupObj,
|
|
10
|
+
helps = "",
|
|
11
|
+
defaultValue = "",
|
|
12
|
+
profileList,
|
|
13
|
+
lookupObjDefaultField = ""
|
|
14
|
+
) {
|
|
15
|
+
const ldf =
|
|
16
|
+
lookupObjDefaultField !== undefined && lookupObjDefaultField !== null
|
|
17
|
+
? String(lookupObjDefaultField).trim()
|
|
18
|
+
: "";
|
|
5
19
|
return {
|
|
6
20
|
"objid": objid,
|
|
7
21
|
"obj": {
|
|
@@ -10,11 +24,10 @@ module.exports = function (objid, nameLabel, apiname, lookupObj, profileList) {
|
|
|
10
24
|
"apiname": apiname,
|
|
11
25
|
"schemefieldLength": "255",
|
|
12
26
|
"remark": "",
|
|
13
|
-
"helps": "",
|
|
27
|
+
"helps": helps !== undefined && helps !== null ? String(helps) : "",
|
|
14
28
|
"lookupObj": lookupObj,
|
|
15
|
-
"defaultValue": "",
|
|
16
29
|
"childrelationName": nameLabel,
|
|
17
|
-
"lookupObjDefaultField":
|
|
30
|
+
"lookupObjDefaultField": ldf
|
|
18
31
|
},
|
|
19
32
|
"dtype": "Y:查找关系",
|
|
20
33
|
"fdtype": "Y",
|
package/src/fields/index.js
CHANGED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { postClass } = require("../../utils/http")
|
|
4
|
+
const { getPackageJson } = require("../../utils/config");
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const { buildFieldData } = require("./buildFieldData");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 在 object/custom-objects 与 object/standard-objects 中按对象 id 查找 objprefix(供 queryField 使用)
|
|
10
|
+
*/
|
|
11
|
+
function findObjPrefixForObjId(projectPath, objid) {
|
|
12
|
+
if (!objid || String(objid).trim() === "") return null;
|
|
13
|
+
const roots = [
|
|
14
|
+
path.join(path.resolve(projectPath), "object/custom-objects"),
|
|
15
|
+
path.join(path.resolve(projectPath), "object/standard-objects"),
|
|
16
|
+
];
|
|
17
|
+
for (const dir of roots) {
|
|
18
|
+
if (!fs.existsSync(dir)) continue;
|
|
19
|
+
let files;
|
|
20
|
+
try {
|
|
21
|
+
files = fs.readdirSync(dir);
|
|
22
|
+
} catch (_) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
for (const f of files) {
|
|
26
|
+
if (!f.endsWith(".json")) continue;
|
|
27
|
+
const fp = path.join(dir, f);
|
|
28
|
+
try {
|
|
29
|
+
const j = JSON.parse(fs.readFileSync(fp, "utf8"));
|
|
30
|
+
if (j && j.id === objid && j.objprefix) return String(j.objprefix).trim();
|
|
31
|
+
} catch (_) {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* saveField 需要与平台上已有字段一致的元数据(如 datafieldRef、schemetableId)。
|
|
39
|
+
* 在发起 saveField 前,用 queryField 拉取当前字段并合并进 payload。
|
|
40
|
+
*/
|
|
41
|
+
async function mergeUpdatePayloadFromServer(config, projectPath, fieldId, objid, fieldData) {
|
|
42
|
+
const prefix = findObjPrefixForObjId(projectPath, objid);
|
|
43
|
+
if (!prefix) {
|
|
44
|
+
console.error(
|
|
45
|
+
chalk.yellow(
|
|
46
|
+
"⚠ cloudcc update fields: 未在 object/custom-objects 或 object/standard-objects 中找到 objid=" +
|
|
47
|
+
objid +
|
|
48
|
+
" 的 objprefix;请先执行 cloudcc get object 同步对象清单后再试。"
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
if (fieldData.obj) fieldData.obj.schemetableId = String(objid).trim();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const res = await postClass(
|
|
55
|
+
config.setupSvc + "/api/fieldSetup/queryField",
|
|
56
|
+
{ prefix },
|
|
57
|
+
config.accessToken
|
|
58
|
+
);
|
|
59
|
+
if (!res || !res.result || !res.data) return;
|
|
60
|
+
const pool = [...(res.data.stdFields || []), ...(res.data.cusFields || [])];
|
|
61
|
+
const raw = pool.find((f) => f && f.id === fieldId);
|
|
62
|
+
if (!fieldData.obj) return;
|
|
63
|
+
fieldData.obj.schemetableId = String(objid).trim();
|
|
64
|
+
if (raw && raw.datafieldRef) fieldData.obj.datafieldRef = String(raw.datafieldRef);
|
|
65
|
+
if (raw && (raw.schemefieldName || raw.apiname)) {
|
|
66
|
+
fieldData.obj.apiname = String(raw.schemefieldName || raw.apiname);
|
|
67
|
+
}
|
|
68
|
+
if (raw && Array.isArray(raw.profileFieldJson) && raw.profileFieldJson.length > 0) {
|
|
69
|
+
fieldData.profileFieldJson = raw.profileFieldJson;
|
|
70
|
+
}
|
|
71
|
+
if (fieldData.layoutIds === undefined) fieldData.layoutIds = "";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* create 使用 save,简档为 profileId + visible + readonly;saveField 需 profileid + permission。
|
|
76
|
+
*/
|
|
77
|
+
function normalizeProfileFieldJsonForSaveField(fieldData) {
|
|
78
|
+
if (!fieldData || !Array.isArray(fieldData.profileFieldJson)) return;
|
|
79
|
+
fieldData.profileFieldJson = fieldData.profileFieldJson
|
|
80
|
+
.map((row) => {
|
|
81
|
+
const pid = row.profileid || row.profileId;
|
|
82
|
+
if (!pid) return null;
|
|
83
|
+
if (row.permission != null && String(row.permission) !== "") {
|
|
84
|
+
return { profileid: String(pid), permission: String(row.permission) };
|
|
85
|
+
}
|
|
86
|
+
return { profileid: String(pid), permission: "1,0" };
|
|
87
|
+
})
|
|
88
|
+
.filter(Boolean);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 更新字段(与 create 共用同一套 payload 与类型分支;区别在于必须设置 `obj.id` 为字段 ID,且不请求 layout 绑定)
|
|
93
|
+
* @param {Array} argvs - 命令行参数数组
|
|
94
|
+
* @param {string} argvs[2] projectPath
|
|
95
|
+
* @param {string} argvs[3] fieldId(平台字段 id)
|
|
96
|
+
* @param {string} argvs[4] fieldType
|
|
97
|
+
* @param {string} argvs[5] objid
|
|
98
|
+
* @param {string} argvs[6] nameLabel
|
|
99
|
+
* @param {string} argvs[7] remark(与 create 相比各类型可选参数整体下标 +1)
|
|
100
|
+
* @returns {Promise<boolean>}
|
|
101
|
+
*/
|
|
102
|
+
async function update(argvs) {
|
|
103
|
+
try {
|
|
104
|
+
let projectPath = argvs[2];
|
|
105
|
+
const fieldId = argvs[3];
|
|
106
|
+
if (!fieldId || String(fieldId).trim() === "") {
|
|
107
|
+
throw new Error("Missing field id: argvs[3] (field id from platform)");
|
|
108
|
+
}
|
|
109
|
+
const config = await getPackageJson(projectPath);
|
|
110
|
+
let nameLabel = argvs[6];
|
|
111
|
+
let remarkText = argvs[7];
|
|
112
|
+
if (!remarkText) remarkText = "auto created by cloudcc-cli ai agent";
|
|
113
|
+
console.error(chalk.blue('\nUpdating field ' + nameLabel + ' (id=' + fieldId + ')...'));
|
|
114
|
+
let fieldData = await buildFieldData(argvs, { shift: 1 });
|
|
115
|
+
if (!fieldData) {
|
|
116
|
+
throw new Error("Unsupported or unknown fieldType for update");
|
|
117
|
+
}
|
|
118
|
+
if (fieldData.obj) fieldData.obj.id = String(fieldId).trim();
|
|
119
|
+
if (fieldData && fieldData.obj) fieldData.obj.remark = remarkText;
|
|
120
|
+
if (fieldData) fieldData.remark = remarkText;
|
|
121
|
+
|
|
122
|
+
const objid = argvs[5];
|
|
123
|
+
await mergeUpdatePayloadFromServer(config, projectPath, fieldId, objid, fieldData);
|
|
124
|
+
normalizeProfileFieldJsonForSaveField(fieldData);
|
|
125
|
+
|
|
126
|
+
const result = await postClass(
|
|
127
|
+
config.setupSvc + "/api/fieldSetup/saveField",
|
|
128
|
+
fieldData,
|
|
129
|
+
config.accessToken
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (result && result.result) {
|
|
133
|
+
const okId = result.data && (typeof result.data === "string" || typeof result.data === "number")
|
|
134
|
+
? result.data
|
|
135
|
+
: (result.data && result.data.id) || fieldId;
|
|
136
|
+
console.error(chalk.green('✓ Field updated successfully! ID: ' + okId));
|
|
137
|
+
return true;
|
|
138
|
+
} else {
|
|
139
|
+
console.error(chalk.yellow('⚠ Field update completed with warnings: ' + (result && result.returnInfo)));
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error(chalk.red("Failed to update field: "), error.message || error);
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
module.exports = update;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { analyzeJspMigration, parseCliJsonArg } = require("./migration")
|
|
2
|
+
|
|
3
|
+
async function analyze(argvs) {
|
|
4
|
+
const params = parseCliJsonArg(
|
|
5
|
+
argvs[2],
|
|
6
|
+
"cloudcc analyze jsp <encodeURI(JSON.stringify(params))>"
|
|
7
|
+
)
|
|
8
|
+
const result = await analyzeJspMigration(params)
|
|
9
|
+
if (!result.success) {
|
|
10
|
+
throw new Error(result.text)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
console.log(result.text)
|
|
14
|
+
return result.text
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = analyze
|
package/src/jsp/doc.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { readIntroductionDoc, readDevGuideDoc } = require("./docs")
|
|
2
|
+
|
|
3
|
+
function doc(argvs) {
|
|
4
|
+
const subType = String(argvs[2] || "").trim().toLowerCase()
|
|
5
|
+
if (!subType || subType === "devguide") {
|
|
6
|
+
const content = readDevGuideDoc()
|
|
7
|
+
console.log(content)
|
|
8
|
+
return content
|
|
9
|
+
}
|
|
10
|
+
if (subType === "introduction") {
|
|
11
|
+
const content = readIntroductionDoc()
|
|
12
|
+
console.log(content)
|
|
13
|
+
return content
|
|
14
|
+
}
|
|
15
|
+
throw new Error(`cloudcc doc jsp 需要子命令:introduction 或 devguide`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = doc
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# CloudCC JSP 迁移开发指南
|
|
2
|
+
|
|
3
|
+
## 1. 命令总览
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cloudcc doc jsp devguide
|
|
7
|
+
cloudcc analyze jsp <encodeURI(JSON.stringify(params))>
|
|
8
|
+
cloudcc split jsp <encodeURI(JSON.stringify(params))>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 2. 参数结构
|
|
12
|
+
|
|
13
|
+
推荐将参数组织成 JSON,再使用 `encodeURI(JSON.stringify(params))` 传入 CLI。
|
|
14
|
+
|
|
15
|
+
参数示例:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"jspPath": "customize/wt_ly.jsp",
|
|
20
|
+
"helpDocPath": "jspTemp/help.md",
|
|
21
|
+
"projectPath": "/abs/project",
|
|
22
|
+
"outputProjectPath": "/abs/output-project",
|
|
23
|
+
"className": "WtLyMigratedService",
|
|
24
|
+
"componentName": "wt-ly-migrated",
|
|
25
|
+
"reportDir": "migration-report",
|
|
26
|
+
"mode": "apply",
|
|
27
|
+
"overwrite": false
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
字段说明:
|
|
32
|
+
|
|
33
|
+
- `jspPath`:必填,JSP 文件路径,可为绝对路径或相对 `projectPath`
|
|
34
|
+
- `helpDocPath`:可选,帮助文档路径
|
|
35
|
+
- `projectPath`:可选,项目根目录,默认当前工作目录
|
|
36
|
+
- `outputProjectPath`:可选,输出项目目录,默认等于 `projectPath`
|
|
37
|
+
- `className`:可选,生成的自定义类名
|
|
38
|
+
- `componentName`:可选,生成的组件名
|
|
39
|
+
- `reportDir`:可选,报告目录,默认 `migration-report`
|
|
40
|
+
- `mode`:仅 `split jsp` 有意义,支持 `apply` / `dry-run`
|
|
41
|
+
- `overwrite`:是否覆盖现有文件,默认 `false`
|
|
42
|
+
|
|
43
|
+
## 3. 常用命令示例
|
|
44
|
+
|
|
45
|
+
### 3.1 查看开发文档与规则
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cloudcc doc jsp devguide
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3.2 分析 JSP(不写文件)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cloudcc analyze jsp "$(node -e 'console.log(encodeURI(JSON.stringify({jspPath:\"customize/wt_ly.jsp\",projectPath:process.cwd()})))')"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3.3 生成迁移结果
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cloudcc split jsp "$(node -e 'console.log(encodeURI(JSON.stringify({jspPath:\"customize/wt_ly.jsp\",projectPath:process.cwd(),overwrite:false})))')"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 4. 输出结果
|
|
64
|
+
|
|
65
|
+
`split jsp` 默认会输出:
|
|
66
|
+
|
|
67
|
+
- `classes/<ClassName>/<ClassName>.java`
|
|
68
|
+
- `classes/<ClassName>/<ClassName>Test.java`
|
|
69
|
+
- `classes/<ClassName>/config.json`
|
|
70
|
+
- `plugins/<componentName>/<componentName>.vue`
|
|
71
|
+
- `plugins/<componentName>/config.json`
|
|
72
|
+
- `<reportDir>/<jspBaseName>.migration.md`
|
|
73
|
+
|
|
74
|
+
## 5. 推荐流程
|
|
75
|
+
|
|
76
|
+
1. 先阅读 `cloudcc doc jsp devguide` 中的规则章节
|
|
77
|
+
2. 根据旧 URL 或仓库结构定位 `customize/*.jsp`
|
|
78
|
+
3. 用 `cloudcc analyze jsp ...` 做单文件分析
|
|
79
|
+
4. 调整类名、组件名、输出目录等参数
|
|
80
|
+
5. 用 `cloudcc split jsp ...` 生成迁移草稿
|
|
81
|
+
6. 手工补全生成类中的业务逻辑并验证依赖
|
|
82
|
+
|
|
83
|
+
## 6. JSP 迁移规则
|
|
84
|
+
|
|
85
|
+
### 6.1 从旧系统 URL 定位 JSP 源文件
|
|
86
|
+
|
|
87
|
+
- 若页面或配置中出现形如 `/controller.action?name=<name>` 的地址,应在项目根目录下的 `customize` 目录中查找对应 JSP
|
|
88
|
+
- 常见约定:`<projectPath>/customize/<name>.jsp`
|
|
89
|
+
- 解析出真实路径后,可将其作为 `jspPath` 传入 CLI `cloudcc analyze jsp` / `cloudcc split jsp`,或对应的 MCP 工具
|
|
90
|
+
|
|
91
|
+
### 6.2 批量迁移时的建议流程
|
|
92
|
+
|
|
93
|
+
1. 先查看本节规则;若走 CLI,可执行 `cloudcc doc jsp devguide`
|
|
94
|
+
2. 在仓库中列举或搜索 `customize` 下需处理的 `.jsp`
|
|
95
|
+
3. 对每个 JSP 单独执行 `cloudcc analyze jsp` 或 `cloudcc split jsp`
|
|
96
|
+
4. 不要假设服务端会自动循环多个文件
|
|
97
|
+
|
|
98
|
+
### 6.3 PageClsInvoker 调用约定
|
|
99
|
+
|
|
100
|
+
在服务端自定义类中,通过 `PageClsInvoker` 调用其它自定义类方法,典型形式如下:
|
|
101
|
+
|
|
102
|
+
```java
|
|
103
|
+
Object result = new PageClsInvoker(userInfo).invoker("TargetClassName", "targetMethodName", argList);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
迁移 JSP 内出现的同类调用时,保持上述调用形态,并核对目标类、方法在平台中已存在且参数类型一致。
|
|
107
|
+
|
|
108
|
+
### 6.4 与迁移工具的配合
|
|
109
|
+
|
|
110
|
+
- `cloudcc analyze jsp` / `cloudcc split jsp`(以及对应 MCP 工具)会从 JSP 文本中识别 `PageClsInvoker(userInfo).invoker("类名","方法名", ...)` 形式的依赖,并写入迁移报告
|
|
111
|
+
- 具体业务实现仍需在生成后的自定义类中补全或调整
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# CloudCC JSP 迁移介绍
|
|
2
|
+
|
|
3
|
+
## 1. 模块定位
|
|
4
|
+
|
|
5
|
+
`jsp` 模块用于辅助将旧 JSP 页面迁移为 CloudCC 自定义类与自定义组件。
|
|
6
|
+
|
|
7
|
+
当前资源主要提供三类能力:
|
|
8
|
+
|
|
9
|
+
- 读取固定迁移规则
|
|
10
|
+
- 对单个 JSP 做 dry-run 分析
|
|
11
|
+
- 对单个 JSP 输出迁移产物
|
|
12
|
+
|
|
13
|
+
可通过以下命令查看:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cloudcc doc jsp introduction
|
|
17
|
+
cloudcc doc jsp devguide
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 2. 当前支持的命令
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
cloudcc doc jsp devguide
|
|
24
|
+
cloudcc analyze jsp <encodeURI(JSON.stringify(params))>
|
|
25
|
+
cloudcc split jsp <encodeURI(JSON.stringify(params))>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
其中 `params` 主要包含:
|
|
29
|
+
|
|
30
|
+
- `jspPath`
|
|
31
|
+
- `helpDocPath`
|
|
32
|
+
- `projectPath`
|
|
33
|
+
- `outputProjectPath`
|
|
34
|
+
- `className`
|
|
35
|
+
- `componentName`
|
|
36
|
+
- `reportDir`
|
|
37
|
+
- `mode`
|
|
38
|
+
- `overwrite`
|
|
39
|
+
|
|
40
|
+
## 3. 适用场景
|
|
41
|
+
|
|
42
|
+
- 旧系统 JSP 页面迁移评估
|
|
43
|
+
- 识别 `reason` 分支、对象依赖、`PageClsInvoker` 调用
|
|
44
|
+
- 生成 CloudCC 自定义类、自定义组件和迁移报告草稿
|
|
45
|
+
|
|
46
|
+
## 4. 使用建议
|
|
47
|
+
|
|
48
|
+
- 先阅读 `cloudcc doc jsp devguide`
|
|
49
|
+
- 再执行 `cloudcc analyze jsp ...` 做分析
|
|
50
|
+
- 确认命名、输出目录和覆盖策略后,再执行 `cloudcc split jsp ...`
|
package/src/jsp/docs.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const fs = require("fs")
|
|
2
|
+
const path = require("path")
|
|
3
|
+
|
|
4
|
+
const DOCS_DIR = path.join(__dirname, "docs")
|
|
5
|
+
|
|
6
|
+
function readDocFile(name) {
|
|
7
|
+
return fs.readFileSync(path.join(DOCS_DIR, `${name}.md`), "utf8")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function readIntroductionDoc() {
|
|
11
|
+
return readDocFile("introduction")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function readDevGuideDoc() {
|
|
15
|
+
return readDocFile("devguide")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
readIntroductionDoc,
|
|
20
|
+
readDevGuideDoc,
|
|
21
|
+
}
|