cloudcc-cli 2.3.4 → 2.3.5
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/.claude/settings.json +22 -1
- package/.cursor/skills/cloudcc-cli-dev/SKILL.md +175 -0
- package/.cursor/skills/cloudcc-dev-skill/SKILL.md +71 -0
- package/README.md +54 -7
- package/bin/cc.js +106 -28
- package/bin/index.js +54 -55
- package/mcp/cliRunner.js +11 -4
- package/mcp/index.js +12 -2
- package/mcp/tools/CloudCC Development Overview/handler.js +1 -1
- package/mcp/tools/JSP Migrator/handler.js +46 -0
- package/package.json +3 -4
- package/src/button/create.js +169 -0
- package/src/button/delete.js +35 -0
- package/src/button/doc.js +36 -0
- package/src/button/docs/devguide.md +133 -0
- package/src/button/docs/introduction.md +60 -0
- package/src/button/get.js +60 -0
- package/src/button/index.js +20 -0
- package/src/classes/docs/introduction.md +0 -20
- package/src/identityProvider/create.js +78 -0
- package/src/identityProvider/delete.js +61 -0
- package/src/identityProvider/doc.js +46 -0
- package/src/identityProvider/docs/devguide.md +107 -0
- package/src/identityProvider/docs/introduction.md +31 -0
- package/src/identityProvider/download.js +105 -0
- package/src/identityProvider/get.js +70 -0
- package/src/identityProvider/index.js +12 -0
- package/src/permission/add.js +164 -0
- package/src/permission/assign.js +84 -0
- package/src/permission/docs/devguide.md +238 -0
- package/src/permission/docs/introduction.md +200 -0
- package/src/permission/get.js +107 -0
- package/src/permission/index.js +10 -0
- package/src/permission/remove.js +145 -0
- package/src/project/docs/devguide.md +7 -6
- package/src/singleSignOn/delete.js +61 -0
- package/src/singleSignOn/doc.js +46 -0
- package/src/singleSignOn/docs/devguide.md +61 -0
- package/src/singleSignOn/docs/introduction.md +3 -0
- package/src/singleSignOn/get.js +70 -0
- package/src/singleSignOn/index.js +10 -0
- package/src/staticResource/docs/introduction.md +44 -1
- package/src/validationRule/create.js +2 -2
- package/src/version/actionHelp.js +25 -0
- package/src/version/docs.js +26 -0
- package/src/version/doctor.js +25 -0
- package/src/version/get.js +7 -1
- package/src/version/help.js +47 -0
- package/src/version/index.js +9 -2
- package/src/version/initHelp.js +13 -0
- package/src/version/listModuleCommands.js +241 -0
- package/src/version/stats.js +44 -0
- package/src/version/uninstall.js +30 -0
- package/src/version/update.js +13 -0
- package/utils/checkVersion.js +31 -2
- package/utils/commandStats.js +94 -0
- package/utils/formatReleaseNotes.js +312 -0
- package/utils/readmeReleases.js +69 -0
- package/.cloudcc-cache.json +0 -54
- package/.cursor/skills/cloudcc-cli-dev.zip +0 -0
- package/.cursor/skills/cloudcc-dev-usage/SKILL.md +0 -68
- package/build/component-cc-cc-dd.common.js +0 -831
- package/build/component-cc-cc-dd.common.js.map +0 -1
- package/build/component-cc-cc-dd.css +0 -1
- package/build/component-cc-cc-dd.umd.js +0 -874
- package/build/component-cc-cc-dd.umd.js.map +0 -1
- package/build/component-cc-cc-dd.umd.min.js +0 -8
- package/build/component-cc-cc-dd.umd.min.js.map +0 -1
- package/build/demo.html +0 -1
- package/plugins/cc-cc-dd/cc-cc-dd.vue +0 -32
- package/plugins/cc-cc-dd/components/HelloWorld.vue +0 -11
- package/plugins/cc-cc-dd/config.json +0 -6
package/mcp/index.js
CHANGED
|
@@ -662,11 +662,21 @@ mcpServer.registerTool(
|
|
|
662
662
|
cloudccOverviewHandler.getCloudCCDevelopmentOverview
|
|
663
663
|
);
|
|
664
664
|
|
|
665
|
+
// ==================== JSP 迁移规则(供 AI 编排批量迁移) ====================
|
|
666
|
+
mcpServer.registerTool(
|
|
667
|
+
'get_jsp_migration_rules',
|
|
668
|
+
{
|
|
669
|
+
description: '返回 JSP 迁移的固定规则:从 /controller.action?name= 定位 customize 下 JSP、批量迁移时如何循环调用其它 JSP 工具、以及 PageClsInvoker 调用约定。处理 JSP 迁移或批量迁移前应先调用本工具。',
|
|
670
|
+
inputSchema: z.object({})
|
|
671
|
+
},
|
|
672
|
+
jspMigratorHandler.getJspMigrationRules
|
|
673
|
+
);
|
|
674
|
+
|
|
665
675
|
// ==================== JSP Migration Analyzer 工具 ====================
|
|
666
676
|
mcpServer.registerTool(
|
|
667
677
|
'analyze_jsp_migration',
|
|
668
678
|
{
|
|
669
|
-
description: '分析旧 JSP 页面,提取 reason
|
|
679
|
+
description: '分析旧 JSP 页面,提取 reason 分支、对象依赖和迁移风险,输出迁移报告(不落地代码)。批量迁移前建议先调用 get_jsp_migration_rules。',
|
|
670
680
|
inputSchema: z.object({
|
|
671
681
|
jspPath: z.string().min(1).describe('JSP 文件路径(绝对路径或相对 projectPath)'),
|
|
672
682
|
helpDocPath: z.string().optional().describe('帮助文档路径(可选),如 jspTemp/帮助文档.md'),
|
|
@@ -684,7 +694,7 @@ mcpServer.registerTool(
|
|
|
684
694
|
mcpServer.registerTool(
|
|
685
695
|
'split_jsp_to_cloudcc',
|
|
686
696
|
{
|
|
687
|
-
description: '将旧 JSP 页面拆分为 CloudCC 自定义类和自定义组件,并生成迁移报告。支持 apply/dry-run
|
|
697
|
+
description: '将旧 JSP 页面拆分为 CloudCC 自定义类和自定义组件,并生成迁移报告。支持 apply/dry-run 两种模式。批量迁移前建议先调用 get_jsp_migration_rules。',
|
|
688
698
|
inputSchema: z.object({
|
|
689
699
|
jspPath: z.string().min(1).describe('JSP 文件路径(绝对路径或相对 projectPath)'),
|
|
690
700
|
helpDocPath: z.string().optional().describe('帮助文档路径(可选),如 jspTemp/帮助文档.md'),
|
|
@@ -21,7 +21,7 @@ const { runCcCommand, buildRunDetail } = require('../../cliRunner');
|
|
|
21
21
|
*/
|
|
22
22
|
async function getCloudCCDevelopmentOverview({ }) {
|
|
23
23
|
try {
|
|
24
|
-
const run = runCcCommand(['doc', 'project'
|
|
24
|
+
const run = runCcCommand(['doc', 'project']);
|
|
25
25
|
if (!run.success) {
|
|
26
26
|
return {
|
|
27
27
|
content: [{
|
|
@@ -827,6 +827,51 @@ async function runMigration({
|
|
|
827
827
|
}
|
|
828
828
|
}
|
|
829
829
|
|
|
830
|
+
/**
|
|
831
|
+
* 供 MCP 工具 get_jsp_migration_rules 返回的固定说明,便于 AI 在批量迁移前统一遵循。
|
|
832
|
+
*/
|
|
833
|
+
const JSP_MIGRATION_RULES_MARKDOWN = `# JSP 迁移处理规则(CloudCC)
|
|
834
|
+
|
|
835
|
+
## 1. 从旧系统 URL 定位 JSP 源文件
|
|
836
|
+
|
|
837
|
+
- 若页面或配置中出现形如 \`/controller.action?name=<name>\` 的地址(示例:\`name=wt_ly\`),应在**项目根目录下的 customize 目录**中查找对应 JSP。
|
|
838
|
+
- 常见约定:\`<projectPath>/customize/<name>.jsp\`(若实际仓库使用子目录或其它扩展名,以仓库为准)。
|
|
839
|
+
- 解析出真实路径后,再将其作为 \`jspPath\` 传入 \`analyze_jsp_migration\` 或 \`split_jsp_to_cloudcc\`(可相对 \`projectPath\`)。
|
|
840
|
+
|
|
841
|
+
## 2. 批量迁移时的建议流程
|
|
842
|
+
|
|
843
|
+
1. 先调用本说明(get_jsp_migration_rules)确认规则。
|
|
844
|
+
2. 在仓库中列举或搜索 \`customize\` 下需处理的 \`.jsp\`(或根据 URL 中的 \`name\` 逐个解析路径)。
|
|
845
|
+
3. 对每个 JSP 单独调用 \`analyze_jsp_migration\`(仅分析)或 \`split_jsp_to_cloudcc\`(生成类与组件);不要假设 MCP 会在服务端自动循环多个文件。
|
|
846
|
+
|
|
847
|
+
## 3. 自定义页面 / 自定义类中调用其它类(PageClsInvoker)
|
|
848
|
+
|
|
849
|
+
在服务端自定义类中,通过 \`PageClsInvoker\` 调用其它自定义类方法,典型形式如下:
|
|
850
|
+
|
|
851
|
+
\`\`\`java
|
|
852
|
+
// userInfo 为当前上下文的 UserInfo;类名、方法名为目标自定义类及其方法;最后一个参数为参数列表(如 List)
|
|
853
|
+
Object result = new PageClsInvoker(userInfo).invoker("TargetClassName", "targetMethodName", argList);
|
|
854
|
+
\`\`\`
|
|
855
|
+
|
|
856
|
+
示例(类名、方法名以实际平台为准):
|
|
857
|
+
|
|
858
|
+
\`\`\`java
|
|
859
|
+
Object result2 = new PageClsInvoker(userInfo).invoker("LabDingTalkProdlemMessage", "sendTextMessageByUserCodeList", arglist0);
|
|
860
|
+
\`\`\`
|
|
861
|
+
|
|
862
|
+
迁移 JSP 内出现的同类调用时,保持上述调用形态,并核对目标类、方法在平台中已存在且参数类型一致。
|
|
863
|
+
|
|
864
|
+
## 4. 与迁移工具的配合
|
|
865
|
+
|
|
866
|
+
- \`analyze_jsp_migration\` / \`split_jsp_to_cloudcc\` 会从 JSP 文本中识别 \`PageClsInvoker(userInfo).invoker("类名","方法名", ...)\` 形式的依赖,并写入迁移报告;具体业务实现需在生成后的自定义类中补全或调整。
|
|
867
|
+
`;
|
|
868
|
+
|
|
869
|
+
async function getJspMigrationRules() {
|
|
870
|
+
return {
|
|
871
|
+
content: [{ type: 'text', text: JSP_MIGRATION_RULES_MARKDOWN }]
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
|
|
830
875
|
async function analyzeJspMigration(params) {
|
|
831
876
|
return runMigration({ ...(params || {}), mode: 'dry-run' });
|
|
832
877
|
}
|
|
@@ -836,6 +881,7 @@ async function splitJspToCloudcc(params) {
|
|
|
836
881
|
}
|
|
837
882
|
|
|
838
883
|
module.exports = {
|
|
884
|
+
getJspMigrationRules,
|
|
839
885
|
analyzeJspMigration,
|
|
840
886
|
splitJspToCloudcc,
|
|
841
887
|
runMigrationForCli: runMigration
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudcc-cli",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.5",
|
|
4
4
|
"description": "cloudcc-cli",
|
|
5
5
|
"author": "cloudcc",
|
|
6
6
|
"license": "ISC",
|
|
@@ -12,14 +12,13 @@
|
|
|
12
12
|
"bin": {
|
|
13
13
|
"cloudccCreate": "bin/project.js",
|
|
14
14
|
"cloudccBuild": "bin/plugin.js",
|
|
15
|
-
"cc": "bin/cc.js"
|
|
16
|
-
"cc-mcp": "bin/mcp.js"
|
|
15
|
+
"cc": "bin/cc.js"
|
|
17
16
|
},
|
|
18
17
|
"scripts": {
|
|
19
18
|
"test-cli-one": "node --test test/globalSelectList.cli.test.js",
|
|
20
19
|
"test-cli-all": "node --test ",
|
|
21
20
|
"cc-pull": "git fetch --tags -f && git pull",
|
|
22
|
-
"npm-login": "npm login --registry https://registry.
|
|
21
|
+
"npm-login": "npm login --registry https://registry.npmjs.com",
|
|
23
22
|
"npm-publish": "npm publish --registry https://registry.npmjs.org && git add . && git commit -m 'update' && git push && curl https://npmmirror.com/sync/cloudcc-cli",
|
|
24
23
|
"package-jar": "mvn clean && mvn package",
|
|
25
24
|
"fetch-dev-env": "node src/mcp/tools/dev-env/fetcher.js",
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自定义按钮 - 新建
|
|
3
|
+
* API: POST {setupSvc}/api/buttonlink/saveButton
|
|
4
|
+
* CLI: cc create button <projectPath> <objid> <label> [name] [btnType] [event]
|
|
5
|
+
*
|
|
6
|
+
* 参数说明:
|
|
7
|
+
* - projectPath : 项目根目录
|
|
8
|
+
* - objid : 对象 ID
|
|
9
|
+
* - label : 按钮标签(必填)
|
|
10
|
+
* - name : 按钮 API 名称(可选,默认同 label)
|
|
11
|
+
* - btnType : 显示类型,detailBtn(详情页面按钮,默认)| listBtn(列表按钮)
|
|
12
|
+
* - event : 按钮类型,template(默认)| lightning-script | lightning-url | url
|
|
13
|
+
*
|
|
14
|
+
* 各类型默认值:
|
|
15
|
+
* - template / lightning-script : functionCode = "alert('hello world')"
|
|
16
|
+
* - lightning-script : h5FunctionCode = "alert('hello world')"
|
|
17
|
+
* - lightning-url / url : functionCode = "www.cloudcc.com"
|
|
18
|
+
* - lightning-url : mobileurl 自动选取自定义页面组件列表第一项
|
|
19
|
+
*/
|
|
20
|
+
const chalk = require("chalk");
|
|
21
|
+
const axios = require("axios");
|
|
22
|
+
const https = require("https");
|
|
23
|
+
const http = require("http");
|
|
24
|
+
const { getPackageJson } = require("../../utils/config");
|
|
25
|
+
const { postClass } = require("../../utils/http");
|
|
26
|
+
|
|
27
|
+
// 用户侧 event 名称 -> API 实际 event 值
|
|
28
|
+
const EVENT_MAP = {
|
|
29
|
+
"template": "lightning",
|
|
30
|
+
"lightning-script": "lightning-script",
|
|
31
|
+
"lightning-url": "lightning-url",
|
|
32
|
+
"url": "URL"
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
36
|
+
const httpAgent = new http.Agent({ rejectUnauthorized: false });
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 从 devconsole-svc 获取自定义页面组件列表,返回首个页面对象
|
|
40
|
+
* @param {string} setupSvc 配置中的 setupSvc 地址
|
|
41
|
+
* @param {string} accessToken
|
|
42
|
+
*/
|
|
43
|
+
async function fetchFirstCustomPage(setupSvc, accessToken) {
|
|
44
|
+
// 从 setupSvc 移除末尾服务路径,拼 devconsole 路径
|
|
45
|
+
// 例:https://xxx/ccdomaingateway/setup → https://xxx/ccdomaingateway/devconsole/...
|
|
46
|
+
const base = setupSvc.replace(/\/[^/]+$/, "");
|
|
47
|
+
const url = base + "/devconsole/custom/pc/1.0/post/pageCustomPage";
|
|
48
|
+
const res = await axios({
|
|
49
|
+
url,
|
|
50
|
+
method: "post",
|
|
51
|
+
httpsAgent,
|
|
52
|
+
httpAgent,
|
|
53
|
+
timeout: 60000,
|
|
54
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
55
|
+
data: {
|
|
56
|
+
head: {
|
|
57
|
+
appType: "lightning-setup",
|
|
58
|
+
appVersion: "0.0.1",
|
|
59
|
+
accessToken,
|
|
60
|
+
source: "lightning-setup",
|
|
61
|
+
version: "public"
|
|
62
|
+
},
|
|
63
|
+
body: {
|
|
64
|
+
pageNo: 1,
|
|
65
|
+
pageSize: 2000000,
|
|
66
|
+
condition: { pageLabel: "", dtBegin: "", dtEnd: "" }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
const list = res.data && res.data.data && res.data.data.list;
|
|
71
|
+
return Array.isArray(list) && list.length > 0 ? list[0] : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 新建自定义按钮
|
|
76
|
+
* @param {string} projectPath
|
|
77
|
+
* @param {string} objid 对象 ID
|
|
78
|
+
* @param {string} label 按钮标签
|
|
79
|
+
* @param {string} name 按钮 API 名称(可选)
|
|
80
|
+
* @param {string} btnType detailBtn | listBtn(默认 detailBtn)
|
|
81
|
+
* @param {string} eventType template | lightning-script | lightning-url | url(默认 template)
|
|
82
|
+
*/
|
|
83
|
+
async function create(projectPath = process.cwd(), objid, label, name, btnType = "detailBtn", eventType = "template") {
|
|
84
|
+
if (!objid) throw new Error("Create Button Failed: objid is required");
|
|
85
|
+
if (!label) throw new Error("Create Button Failed: label is required");
|
|
86
|
+
|
|
87
|
+
const resolvedName = name || label;
|
|
88
|
+
const resolvedBtnType = btnType || "detailBtn";
|
|
89
|
+
const resolvedEvent = eventType || "template";
|
|
90
|
+
|
|
91
|
+
const apiEvent = EVENT_MAP[resolvedEvent];
|
|
92
|
+
if (!apiEvent) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Create Button Failed: unknown event type "${resolvedEvent}". ` +
|
|
95
|
+
`Must be one of: template, lightning-script, lightning-url, url`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const config = await getPackageJson(projectPath);
|
|
100
|
+
|
|
101
|
+
console.error();
|
|
102
|
+
console.error(chalk.green("Creating custom button, please wait..."));
|
|
103
|
+
console.error();
|
|
104
|
+
|
|
105
|
+
// 构建按钮 VO 基础结构
|
|
106
|
+
const tpSysButtonVO = {
|
|
107
|
+
label,
|
|
108
|
+
name: resolvedName,
|
|
109
|
+
btnType: resolvedBtnType,
|
|
110
|
+
event: apiEvent,
|
|
111
|
+
behavior: "self",
|
|
112
|
+
menubar: true,
|
|
113
|
+
functionCode: "",
|
|
114
|
+
remark: "",
|
|
115
|
+
mobileurl: "",
|
|
116
|
+
h5FunctionCode: "",
|
|
117
|
+
category: "CustomButton",
|
|
118
|
+
custompageId: "",
|
|
119
|
+
iscustom: "",
|
|
120
|
+
visible: "1"
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// 按类型填充默认值
|
|
124
|
+
if (resolvedEvent === "template") {
|
|
125
|
+
// PC 端 JavaScript 代码
|
|
126
|
+
tpSysButtonVO.functionCode = "alert('hello world')";
|
|
127
|
+
} else if (resolvedEvent === "lightning-script") {
|
|
128
|
+
// PC + 移动端均支持
|
|
129
|
+
tpSysButtonVO.functionCode = "alert('hello world')";
|
|
130
|
+
tpSysButtonVO.h5FunctionCode = "alert('hello world')";
|
|
131
|
+
} else if (resolvedEvent === "lightning-url") {
|
|
132
|
+
// PC 端 URL 地址
|
|
133
|
+
tpSysButtonVO.functionCode = "www.cloudcc.com";
|
|
134
|
+
// 移动端:自动取自定义页面组件列表第一项
|
|
135
|
+
try {
|
|
136
|
+
const firstPage = await fetchFirstCustomPage(config.setupSvc, config.accessToken);
|
|
137
|
+
if (firstPage) {
|
|
138
|
+
tpSysButtonVO.mobileurl = `__UNI__110007E/#/pages/index/index?pageApi=${firstPage.pageApi}`;
|
|
139
|
+
tpSysButtonVO.custompageId = firstPage.id;
|
|
140
|
+
console.error(chalk.cyan(`Using custom page: ${firstPage.pageLabel} (pageApi: ${firstPage.pageApi})`));
|
|
141
|
+
} else {
|
|
142
|
+
console.error(chalk.yellow("Warning: No custom page found, mobileurl will be empty."));
|
|
143
|
+
}
|
|
144
|
+
} catch (e) {
|
|
145
|
+
console.error(chalk.yellow(`Warning: Could not fetch custom page list: ${e.message}`));
|
|
146
|
+
}
|
|
147
|
+
} else if (resolvedEvent === "url") {
|
|
148
|
+
// PC 端 URL(仅 PC 支持)
|
|
149
|
+
tpSysButtonVO.functionCode = "www.cloudcc.com";
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const body = { objid, tpSysButtonVO };
|
|
153
|
+
|
|
154
|
+
const res = await postClass(
|
|
155
|
+
config.setupSvc + "/api/buttonlink/saveButton",
|
|
156
|
+
body,
|
|
157
|
+
config.accessToken
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
if (res && res.result) {
|
|
161
|
+
console.error(chalk.green(`Success! Custom button "${label}" created.`));
|
|
162
|
+
console.error();
|
|
163
|
+
return res;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
throw new Error("Create Button Failed: " + (res?.returnInfo || res?.message || "Unknown error"));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = create;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自定义按钮 - 删除
|
|
3
|
+
* API: POST {setupSvc}/api/buttonlink/deleteButton
|
|
4
|
+
* CLI: cc delete button <projectPath> <id>
|
|
5
|
+
*
|
|
6
|
+
* 参数说明:
|
|
7
|
+
* - projectPath : 项目根目录
|
|
8
|
+
* - id : 自定义按钮 ID
|
|
9
|
+
*/
|
|
10
|
+
const chalk = require("chalk");
|
|
11
|
+
const { getPackageJson } = require("../../utils/config");
|
|
12
|
+
const { postClass } = require("../../utils/http");
|
|
13
|
+
|
|
14
|
+
async function remove(projectPath = process.cwd(), id) {
|
|
15
|
+
if (!id) {
|
|
16
|
+
throw new Error("Delete Button Failed: id is required");
|
|
17
|
+
}
|
|
18
|
+
const config = await getPackageJson(projectPath);
|
|
19
|
+
console.error();
|
|
20
|
+
console.error(chalk.green(`Deleting button (${id}), please wait...`));
|
|
21
|
+
console.error();
|
|
22
|
+
const res = await postClass(
|
|
23
|
+
config.setupSvc + "/api/buttonlink/deleteButton",
|
|
24
|
+
{ id },
|
|
25
|
+
config.accessToken
|
|
26
|
+
);
|
|
27
|
+
if (res && res.result) {
|
|
28
|
+
console.error(chalk.green("Success! Button deleted."));
|
|
29
|
+
console.error();
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
throw new Error("Delete Button Failed: " + (res?.returnInfo || res?.message || "Unknown error"));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = remove;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* button 文档统一入口
|
|
3
|
+
*/
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const DOCS_DIR = path.join(__dirname, "docs");
|
|
8
|
+
|
|
9
|
+
function readDocFile(basename) {
|
|
10
|
+
return fs.readFileSync(path.join(DOCS_DIR, `${basename}.md`), "utf8");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* cc doc button <introduction|devguide>
|
|
15
|
+
* @param {string[]} argvs [doc, type, introduction|devguide, ...]
|
|
16
|
+
*/
|
|
17
|
+
function doc(argvs) {
|
|
18
|
+
const subType = argvs[2];
|
|
19
|
+
const key = String(subType || "").trim().toLowerCase();
|
|
20
|
+
if (!key) {
|
|
21
|
+
throw new Error("cc doc button 需要子命令:introduction 或 devguide");
|
|
22
|
+
}
|
|
23
|
+
if (key === "introduction") {
|
|
24
|
+
const content = readDocFile("introduction");
|
|
25
|
+
console.log(content);
|
|
26
|
+
return content;
|
|
27
|
+
}
|
|
28
|
+
if (key === "devguide") {
|
|
29
|
+
const content = readDocFile("devguide");
|
|
30
|
+
console.log(content);
|
|
31
|
+
return content;
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`doc 不支持的子命令: ${subType},请使用 introduction 或 devguide`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = doc;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# CloudCC 按钮与链接操作指南
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## 1. 入口与列表页
|
|
6
|
+
|
|
7
|
+
进入路径:`对象管理 → 选择对象 → 按钮和链接` 标签页
|
|
8
|
+
|
|
9
|
+
列表页分为两个 Tab:
|
|
10
|
+
- **标准按钮和链接**:系统内置,不可删除
|
|
11
|
+
- **自定义按钮和链接**:开发者自定义
|
|
12
|
+
|
|
13
|
+
列表展示字段:标签 / 名称 / 显示类型
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. 查询按钮列表
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cc get button . <prefix>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `<prefix>`:对象的 prefix,可从对象管理页或对象 API 名称前缀获取(如 `a75`)
|
|
24
|
+
|
|
25
|
+
返回结构:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"objname": "玫瑰花不带刺",
|
|
30
|
+
"objid": "202646FC67ACF24D39sG",
|
|
31
|
+
"standbutton": [
|
|
32
|
+
{
|
|
33
|
+
"id": "adc20262A1F4957UmT0l",
|
|
34
|
+
"label": "提交待审批",
|
|
35
|
+
"name": "Submit",
|
|
36
|
+
"btnType": "detailBtn",
|
|
37
|
+
"category": "StandardButton",
|
|
38
|
+
"event": "URL",
|
|
39
|
+
"behavior": "self",
|
|
40
|
+
"url": null,
|
|
41
|
+
"functionCode": null,
|
|
42
|
+
"mobileurl": ""
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"custbutton": []
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
| 字段 | 说明 |
|
|
50
|
+
|---------------|---------------------------------------------|
|
|
51
|
+
| `standbutton` | 标准按钮列表 |
|
|
52
|
+
| `custbutton` | 自定义按钮列表 |
|
|
53
|
+
| `btnType` | `detailBtn` 详情页按钮 / `listBtn` 列表按钮 |
|
|
54
|
+
| `category` | `StandardButton` 标准 / `CustomButton` 自定义 |
|
|
55
|
+
| `event` | `URL` 跳转 / `JavaScript` 执行脚本 |
|
|
56
|
+
| `behavior` | 打开方式:`self` 当前页 / `newWindow` 新窗口 |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 3. 新建自定义按钮
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
cc create button . <objid> <label> [name] [btnType] [event]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| 参数 | 必填 | 说明 |
|
|
67
|
+
|-------------|------|-----------------------------------------------------------------------------|
|
|
68
|
+
| `objid` | ✅ | 所属对象 ID |
|
|
69
|
+
| `label` | ✅ | 按钮标签(显示名称) |
|
|
70
|
+
| `name` | ❌ | 按钮 API 名称,默认同 `label` |
|
|
71
|
+
| `btnType` | ❌ | 显示类型:`detailBtn`(详情页按钮,默认)/ `listBtn`(列表按钮) |
|
|
72
|
+
| `event` | ❌ | 按钮类型,见下表,默认 `template` |
|
|
73
|
+
|
|
74
|
+
### 按钮类型(event)
|
|
75
|
+
|
|
76
|
+
| 取值 | 平台支持 | 说明 |
|
|
77
|
+
|-------------------|------------------|-----------------------------------------------------------|
|
|
78
|
+
| `template` | 仅 PC | PC 端 JavaScript 代码,默认代码 `alert('hello world')` |
|
|
79
|
+
| `lightning-script`| PC + 移动端 | PC 和移动端各需要 JS 代码,默认均为 `alert('hello world')` |
|
|
80
|
+
| `lightning-url` | PC + 移动端 | PC 端填 URL,移动端自动选取自定义页面组件列表第一项 |
|
|
81
|
+
| `url` | 仅 PC | PC 端 URL 地址,默认 `www.cloudcc.com` |
|
|
82
|
+
|
|
83
|
+
### 示例
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# 新建 template 类型按钮(默认)
|
|
87
|
+
cc create button . 202646FC67ACF24D39sG "我的按钮"
|
|
88
|
+
|
|
89
|
+
# 指定名称和显示类型
|
|
90
|
+
cc create button . 202646FC67ACF24D39sG "我的按钮" myBtn detailBtn
|
|
91
|
+
|
|
92
|
+
# lightning-script 类型,列表按钮
|
|
93
|
+
cc create button . 202646FC67ACF24D39sG "脚本按钮" scriptBtn listBtn lightning-script
|
|
94
|
+
|
|
95
|
+
# lightning-url 类型(移动端自动取第一个自定义页面组件)
|
|
96
|
+
cc create button . 202646FC67ACF24D39sG "跳转按钮" urlBtn detailBtn lightning-url
|
|
97
|
+
|
|
98
|
+
# url 类型
|
|
99
|
+
cc create button . 202646FC67ACF24D39sG "外链按钮" linkBtn detailBtn url
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> **注意:** 各类型代码/URL 默认值仅供快速创建使用,创建后请在页面上编辑替换为实际内容。
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 4. 删除自定义按钮
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cc delete button . <id>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| 参数 | 必填 | 说明 |
|
|
113
|
+
|-------|------|--------------------|
|
|
114
|
+
| `id` | ✅ | 自定义按钮 ID |
|
|
115
|
+
|
|
116
|
+
> **注意:** 仅支持删除自定义按钮,标准按钮不可删除。
|
|
117
|
+
|
|
118
|
+
### 示例
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
cc delete button . adc202642BBED6BFlu6D
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 5. 查看文档
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
cc doc button introduction # 能力与适用场景说明
|
|
130
|
+
cc doc button devguide # 本操作指南
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# CloudCC 按钮与链接能力说明
|
|
2
|
+
|
|
3
|
+
## 1. 什么是按钮与链接
|
|
4
|
+
|
|
5
|
+
按钮和链接有助于将 CloudCC 数据与外部 URL、应用程序、公司内部网或其他后端办公系统集成在一起。
|
|
6
|
+
|
|
7
|
+
按钮可以显示在以下位置:
|
|
8
|
+
- **详细信息页**:记录详情页面上的操作按钮
|
|
9
|
+
- **相关列表**:对象关联子列表区域的操作按钮
|
|
10
|
+
- **列表视图**:搜索/列表布局中的批量操作按钮
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 2. 按钮分类
|
|
15
|
+
|
|
16
|
+
### 2.1 标准按钮(Standard Button)
|
|
17
|
+
|
|
18
|
+
系统内置的标准操作按钮,不可删除,可控制显示/隐藏。
|
|
19
|
+
|
|
20
|
+
| 标签 | 名称 | 显示类型 |
|
|
21
|
+
|------------|----------------|-----------------|
|
|
22
|
+
| 提交待审批 | Submit | 详细信息页按钮 |
|
|
23
|
+
| 编辑 | Edit | 详细信息页按钮 |
|
|
24
|
+
| 新建 | New | 列表按钮 |
|
|
25
|
+
| 批量转移 | Batch Transfer | 列表按钮 |
|
|
26
|
+
| 删除 | Delete | 详细信息页按钮 |
|
|
27
|
+
| 批量新增 | Batch Added | 列表按钮 |
|
|
28
|
+
| 复制 | Clone | 详细信息页按钮 |
|
|
29
|
+
| 共享 | Share | 详细信息页按钮 |
|
|
30
|
+
| 批量删除 | Batch Delete | 列表按钮 |
|
|
31
|
+
| 批量编辑 | Batch Editor | 列表按钮 |
|
|
32
|
+
| 合并 | Merge | 列表按钮 |
|
|
33
|
+
|
|
34
|
+
### 2.2 自定义按钮(Custom Button)
|
|
35
|
+
|
|
36
|
+
开发者自定义的按钮或链接,支持配置跳转 URL、执行脚本、调用自定义类等行为。
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 3. 按钮类型(btnType)
|
|
41
|
+
|
|
42
|
+
| 值 | 说明 |
|
|
43
|
+
|-------------|----------------|
|
|
44
|
+
| `detailBtn` | 详细信息页按钮 |
|
|
45
|
+
| `listBtn` | 列表按钮 |
|
|
46
|
+
|
|
47
|
+
## 4. 按钮行为(event)
|
|
48
|
+
|
|
49
|
+
| 值 | 说明 |
|
|
50
|
+
|---------------|------------------------|
|
|
51
|
+
| `URL` | 跳转到指定 URL |
|
|
52
|
+
| `JavaScript` | 执行 JavaScript 代码 |
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 5. 如何将按钮添加到页面
|
|
57
|
+
|
|
58
|
+
- **详细信息页**:编辑页面布局,将按钮拖入布局
|
|
59
|
+
- **相关列表**:在页面布局中找到相关列表,编辑其属性
|
|
60
|
+
- **列表视图**:在"搜索布局"中编辑列表视图布局
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const { getPackageJson } = require("../../utils/config");
|
|
2
|
+
const { postClass } = require("../../utils/http");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* cc get button <projectPath> <prefix>
|
|
6
|
+
* 查询对象的标准按钮和自定义按钮列表
|
|
7
|
+
*
|
|
8
|
+
* @param {string} projectPath
|
|
9
|
+
* @param {string} prefix 对象 prefix(如 "a75")
|
|
10
|
+
* @param {boolean} isMcp
|
|
11
|
+
*/
|
|
12
|
+
async function get(projectPath = process.cwd(), prefix, isMcp = false) {
|
|
13
|
+
if (!prefix) {
|
|
14
|
+
throw new Error("Get Button List Failed: prefix is required");
|
|
15
|
+
}
|
|
16
|
+
const config = await getPackageJson(projectPath);
|
|
17
|
+
const res = await postClass(
|
|
18
|
+
config.setupSvc + "/api/buttonlink/listButton",
|
|
19
|
+
{ prefix },
|
|
20
|
+
config.accessToken
|
|
21
|
+
);
|
|
22
|
+
if (res && res.result) {
|
|
23
|
+
const data = res.data || {};
|
|
24
|
+
const result = {
|
|
25
|
+
objname: data.objname || "",
|
|
26
|
+
objid: data.objid || "",
|
|
27
|
+
standbutton: (data.standbutton || []).map(btn => ({
|
|
28
|
+
id: btn.id,
|
|
29
|
+
label: btn.label,
|
|
30
|
+
name: btn.name,
|
|
31
|
+
btnType: btn.btnType,
|
|
32
|
+
category: btn.category,
|
|
33
|
+
event: btn.event,
|
|
34
|
+
behavior: btn.behavior,
|
|
35
|
+
url: btn.url || null,
|
|
36
|
+
functionCode: btn.functionCode || null,
|
|
37
|
+
mobileurl: btn.mobileurl || ""
|
|
38
|
+
})),
|
|
39
|
+
custbutton: (data.custbutton || []).map(btn => ({
|
|
40
|
+
id: btn.id,
|
|
41
|
+
label: btn.label,
|
|
42
|
+
name: btn.name,
|
|
43
|
+
btnType: btn.btnType,
|
|
44
|
+
category: btn.category,
|
|
45
|
+
event: btn.event,
|
|
46
|
+
behavior: btn.behavior,
|
|
47
|
+
url: btn.url || null,
|
|
48
|
+
functionCode: btn.functionCode || null,
|
|
49
|
+
mobileurl: btn.mobileurl || ""
|
|
50
|
+
}))
|
|
51
|
+
};
|
|
52
|
+
if (!isMcp) {
|
|
53
|
+
console.log(JSON.stringify(result));
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
throw new Error("Get Button List Failed: " + (res?.returnInfo || res?.message || "Unknown error"));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = get;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const cc = {};
|
|
2
|
+
cc.doc = require("./doc");
|
|
3
|
+
cc.get = require("./get");
|
|
4
|
+
cc.create = require("./create");
|
|
5
|
+
cc.delete = require("./delete");
|
|
6
|
+
|
|
7
|
+
function Button(action, argvs) {
|
|
8
|
+
if (action === "doc") {
|
|
9
|
+
cc.doc(argvs);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (action === "create") {
|
|
13
|
+
// cc create button <projectPath> <objid> <label> [name] [btnType] [event]
|
|
14
|
+
cc.create(argvs[2], argvs[3], argvs[4], argvs[5], argvs[6], argvs[7]);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
cc[action](argvs[2], argvs[3], argvs[4]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = Button;
|
|
@@ -232,26 +232,6 @@
|
|
|
232
232
|
|
|
233
233
|
---
|
|
234
234
|
|
|
235
|
-
## 11. 线上现状观察(来自当前环境)
|
|
236
|
-
|
|
237
|
-
线上共 87 个自定义类,命名与职责呈现明显分层趋势:
|
|
238
|
-
|
|
239
|
-
- `Controller` 类:承接流程入口与动作编排
|
|
240
|
-
- `Util` 类:沉淀通用方法与查询能力
|
|
241
|
-
- `Service` 类:承担外部集成与业务服务
|
|
242
|
-
- `Handler` 类:承接触发器下沉逻辑
|
|
243
|
-
- `Bot` 类:承载智能助手相关业务
|
|
244
|
-
|
|
245
|
-
从源码统计看,当前环境中大量类已在使用:
|
|
246
|
-
|
|
247
|
-
- `CCService`(数据 CRUD 与查询)
|
|
248
|
-
- JSON 处理能力
|
|
249
|
-
- 异常机制(`Exception` 相关)
|
|
250
|
-
|
|
251
|
-
这说明自定义类已成为该环境中“复杂逻辑与复用能力”的核心载体。
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
235
|
## 12. 一句话结论
|
|
256
236
|
|
|
257
237
|
当业务进入“多对象、复杂规则、跨系统、可复用、可治理”阶段时,CloudCC 自定义类是最关键的后端实现手段:它不仅能实现功能,更能提升系统长期可维护性与稳定性。
|