sks-maximo-utils 1.0.6 → 1.0.7
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/CLI.md +93 -4
- package/README.md +17 -1
- package/cli.js +170 -6
- package/index.js +2 -2
- package/nodeutils/fileUtils.js +62 -1
- package/nodeutils/logger.js +15 -3
- package/nodeutils/maximoTools.js +138 -7
- package/nodeutils/requestHttp.js +4 -6
- package/package.json +1 -1
package/CLI.md
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
| `sks-maximo` | 检查配置文件并打开配置目录 |
|
|
8
8
|
| `sks-maximo <env>` | 加载指定环境配置 |
|
|
9
9
|
| `sks-maximo call <scriptName>` | 调用通用脚本接口 |
|
|
10
|
+
| `sks-maximo import-object <fileName>` | 导入 Maximo 对象配置 |
|
|
11
|
+
| `sks-maximo import-appinfo <fileName>` | 导入应用信息配置 |
|
|
12
|
+
| `sks-maximo import-presentation <fileName>` | 导入应用XML配置 |
|
|
13
|
+
| `sks-maximo import-script <fileName>` | 导入自动化脚本 |
|
|
14
|
+
| `sks-maximo import-domain <fileName>` | 导入域配置 |
|
|
10
15
|
|
|
11
16
|
---
|
|
12
17
|
|
|
@@ -37,7 +42,91 @@ sks-maximo hd # 使用测试环境配置
|
|
|
37
42
|
|
|
38
43
|
---
|
|
39
44
|
|
|
40
|
-
## 3.
|
|
45
|
+
## 3. 导入命令
|
|
46
|
+
|
|
47
|
+
所有导入命令均支持 `-e` / `--env` 指定环境和 `-l` / `--logname` 指定日志名。
|
|
48
|
+
|
|
49
|
+
### 3.1 导入对象配置
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
sks-maximo import-object <fileName> [-e env] [-l logname]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**说明:** 导入 Maximo 对象配置(JSON/XML)
|
|
56
|
+
|
|
57
|
+
| 参数 | 说明 | 必填 |
|
|
58
|
+
|------|------|------|
|
|
59
|
+
| `<fileName>` | JSON 或 XML 配置文件路径 | 是 |
|
|
60
|
+
| `-e` / `--env` | 指定环境(默认 local) | 否 |
|
|
61
|
+
| `-l` / `--logname` | 日志打印名称 | 否 |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### 3.2 导入应用信息
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
sks-maximo import-appinfo <fileName> [-e env] [-l logname]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**说明:** 导入 Maximo 应用信息配置(JSON)
|
|
72
|
+
|
|
73
|
+
| 参数 | 说明 | 必填 |
|
|
74
|
+
|------|------|------|
|
|
75
|
+
| `<fileName>` | 应用信息 JSON 文件路径 | 是 |
|
|
76
|
+
| `-e` / `--env` | 指定环境(默认 local) | 否 |
|
|
77
|
+
| `-l` / `--logname` | 日志打印名称 | 否 |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### 3.3 导入应用XML配置
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
sks-maximo import-presentation <fileName> [-e env] [-l logname]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**说明:** 导入 Maximo 应用 XML 配置
|
|
88
|
+
|
|
89
|
+
| 参数 | 说明 | 必填 |
|
|
90
|
+
|------|------|------|
|
|
91
|
+
| `<fileName>` | XML 配置文件路径 | 是 |
|
|
92
|
+
| `-e` / `--env` | 指定环境(默认 local) | 否 |
|
|
93
|
+
| `-l` / `--logname` | 日志打印名称 | 否 |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### 3.4 导入自动化脚本
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
sks-maximo import-script <fileName> [-e env] [-l logname]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**说明:** 导入 Maximo 自动化脚本。`<fileName>` 可以是 JSON 配置文件路径,也可以是 `.js`/`.py` 脚本文件路径(会自动找同目录下的同名 JSON 配置文件)
|
|
104
|
+
|
|
105
|
+
| 参数 | 说明 | 必填 |
|
|
106
|
+
|------|------|------|
|
|
107
|
+
| `<fileName>` | JSON 配置或脚本文件路径 | 是 |
|
|
108
|
+
| `-e` / `--env` | 指定环境(默认 local) | 否 |
|
|
109
|
+
| `-l` / `--logname` | 日志打印名称 | 否 |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### 3.5 导入域配置
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
sks-maximo import-domain <fileName> [-e env] [-l logname]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**说明:** 导入 Maximo 域配置
|
|
120
|
+
|
|
121
|
+
| 参数 | 说明 | 必填 |
|
|
122
|
+
|------|------|------|
|
|
123
|
+
| `<fileName>` | 域 JSON 文件路径 | 是 |
|
|
124
|
+
| `-e` / `--env` | 指定环境(默认 local) | 否 |
|
|
125
|
+
| `-l` / `--logname` | 日志打印名称 | 否 |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 4. 调用通用脚本接口
|
|
41
130
|
|
|
42
131
|
```bash
|
|
43
132
|
sks-maximo call <scriptName> [--file <fileName>] [--params <params>] [--logname <logname>]
|
|
@@ -52,13 +141,13 @@ sks-maximo call <scriptName> [--file <fileName>] [--params <params>] [--logname
|
|
|
52
141
|
| `--params` | `-p` | URL 查询参数(JSON格式) | 否 |
|
|
53
142
|
| `--logname` | `-l` | 日志名称 | 否 |
|
|
54
143
|
|
|
55
|
-
###
|
|
144
|
+
### 4.1 GET 请求(无请求体)
|
|
56
145
|
|
|
57
146
|
```bash
|
|
58
147
|
sks-maximo call SHARPTREE.AUTOSCRIPT.LIBRARY --params '{"name":"TEST"}'
|
|
59
148
|
```
|
|
60
149
|
|
|
61
|
-
###
|
|
150
|
+
### 4.2 POST 请求(带请求体文件)
|
|
62
151
|
|
|
63
152
|
```bash
|
|
64
153
|
# JSON 请求体
|
|
@@ -71,7 +160,7 @@ sks-maximo call SHARPTREE.AUTOSCRIPT.SCREENS --file screens/test.xml
|
|
|
71
160
|
sks-maximo call SKS_IMP_MAXAPPINFO --file appinfo.json --params '{"debug":true}' --logname "导入应用信息"
|
|
72
161
|
```
|
|
73
162
|
|
|
74
|
-
###
|
|
163
|
+
### 4.3 请求体文件处理
|
|
75
164
|
|
|
76
165
|
- **`.json` 文件**:自动解析为 JSON 对象作为请求体
|
|
77
166
|
- **其他文件**:读取文件内容作为字符串请求体
|
package/README.md
CHANGED
|
@@ -40,9 +40,11 @@ import {
|
|
|
40
40
|
importMaxAutoKey,
|
|
41
41
|
importMaxScript,
|
|
42
42
|
importMaxAppInfo,
|
|
43
|
+
callMaxScript,
|
|
44
|
+
fileUtils,
|
|
43
45
|
loadConfig,
|
|
44
46
|
logger
|
|
45
|
-
} from '
|
|
47
|
+
} from 'sks-maximo-utils';
|
|
46
48
|
|
|
47
49
|
// 加载配置(可选,默认 local)
|
|
48
50
|
loadConfig('local');
|
|
@@ -66,6 +68,16 @@ importMaxScript({ fileName: "scripts/TEST.json" });
|
|
|
66
68
|
|
|
67
69
|
// 导入应用信息配置
|
|
68
70
|
importMaxAppInfo({ fileName: "MAXAPPINFO/appinfo.json", logname: "应用信息" });
|
|
71
|
+
|
|
72
|
+
// 通用脚本接口调用(GET)
|
|
73
|
+
callMaxScript({ apiScriptName: "SHARPTREE.AUTOSCRIPT.LIBRARY", params: { name: "test" }, logname: "查询脚本库" });
|
|
74
|
+
|
|
75
|
+
// 通用脚本接口调用(POST,读取文件内容作为请求体)
|
|
76
|
+
callMaxScript({ apiScriptName: "SKS_DEPLOY_AUTOKEY", fileName: "data/autokey.json", logname: "部署自动编码" });
|
|
77
|
+
|
|
78
|
+
// 文件工具
|
|
79
|
+
fileUtils.listFiles('scripts', '.json');
|
|
80
|
+
fileUtils.readFileContent('test.txt');
|
|
69
81
|
```
|
|
70
82
|
|
|
71
83
|
## 配置文件
|
|
@@ -126,11 +138,15 @@ importMaxAppInfo({ fileName: "MAXAPPINFO/appinfo.json", logname: "应用信息"
|
|
|
126
138
|
|
|
127
139
|
| 方法 | 说明 |
|
|
128
140
|
|------|------|
|
|
141
|
+
| callMaxScript | 通用脚本接口调用(GET/POST) |
|
|
129
142
|
| loadConfig(env) | 加载指定环境配置 |
|
|
130
143
|
| saveScriptHistory(options) | 保存脚本历史记录 |
|
|
131
144
|
| readFileContent(fileName) | 读取文件内容 |
|
|
132
145
|
| readJsonFile(fileName) | 读取并解析 JSON 文件 |
|
|
133
146
|
| fileExists(fileName) | 检查文件是否存在 |
|
|
147
|
+
| fileUtils.listFiles(dirName, extFilter, recursive) | 列出目录文件 |
|
|
148
|
+
| fileUtils.readFileContent(fileName) | 读取文件内容 |
|
|
149
|
+
| fileUtils.readJsonFile(fileName) | 读取并解析 JSON 文件 |
|
|
134
150
|
|
|
135
151
|
### 日志文件
|
|
136
152
|
|
package/cli.js
CHANGED
|
@@ -3,15 +3,28 @@ import { exec } from 'child_process';
|
|
|
3
3
|
import { readFileSync } from 'fs';
|
|
4
4
|
import { fileURLToPath, URL } from 'url';
|
|
5
5
|
import { checkAndCreateConfig, getConfigDir, loadConfig } from './nodeutils/config.js';
|
|
6
|
-
import { callMaxScript } from './nodeutils/maximoTools.js';
|
|
6
|
+
import { callMaxScript, importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, importMaxAppInfo } from './nodeutils/maximoTools.js';
|
|
7
7
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = new URL('.', import.meta.url).pathname;
|
|
10
10
|
const packageJson = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf-8'));
|
|
11
11
|
|
|
12
12
|
const args = process.argv.slice(2);
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
|
|
14
|
+
// 解析全局选项(--env)
|
|
15
|
+
let globalEnv = 'local';
|
|
16
|
+
const filteredArgs = [];
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
if (args[i] === '--env' || args[i] === '-e') {
|
|
19
|
+
globalEnv = args[i + 1];
|
|
20
|
+
i++; // 跳过值
|
|
21
|
+
} else {
|
|
22
|
+
filteredArgs.push(args[i]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const cmd = filteredArgs[0];
|
|
27
|
+
const env = filteredArgs[0];
|
|
15
28
|
|
|
16
29
|
if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
17
30
|
console.log(`sks-maximo v${packageJson.version}`);
|
|
@@ -19,7 +32,12 @@ if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
|
19
32
|
console.log('用法:');
|
|
20
33
|
console.log(' sks-maximo # 检查配置文件并打开配置目录');
|
|
21
34
|
console.log(' sks-maximo <env> # 加载指定环境配置');
|
|
22
|
-
console.log(' sks-maximo call <scriptName> [
|
|
35
|
+
console.log(' sks-maximo call <scriptName> [options] # 调用脚本接口');
|
|
36
|
+
console.log(' sks-maximo import-object <fileName> # 导入 Maximo 对象配置');
|
|
37
|
+
console.log(' sks-maximo import-appinfo <fileName> # 导入应用信息配置');
|
|
38
|
+
console.log(' sks-maximo import-presentation <fileName> # 导入应用XML配置');
|
|
39
|
+
console.log(' sks-maximo import-script <fileName> # 导入自动化脚本');
|
|
40
|
+
console.log(' sks-maximo import-domain <fileName> # 导入域配置');
|
|
23
41
|
console.log('');
|
|
24
42
|
console.log('环境:');
|
|
25
43
|
console.log(' local # 使用本地环境配置');
|
|
@@ -28,10 +46,16 @@ if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
|
28
46
|
console.log('');
|
|
29
47
|
console.log('命令:');
|
|
30
48
|
console.log(' call # 调用通用脚本接口');
|
|
49
|
+
console.log(' import-object # 导入 Maximo 对象配置');
|
|
50
|
+
console.log(' import-appinfo # 导入应用信息配置');
|
|
51
|
+
console.log(' import-presentation # 导入应用XML配置');
|
|
52
|
+
console.log(' import-script # 导入自动化脚本');
|
|
53
|
+
console.log(' import-domain # 导入域配置');
|
|
31
54
|
console.log('');
|
|
32
55
|
console.log('选项:');
|
|
33
56
|
console.log(' -h, --help # 显示帮助信息');
|
|
34
57
|
console.log(' -v, --version # 显示版本信息');
|
|
58
|
+
console.log(' --env, -e <env> # 指定环境(默认 local)');
|
|
35
59
|
console.log(' --file <fileName> # 请求体文件路径(JSON)');
|
|
36
60
|
console.log(' --params <params> # URL参数(JSON格式)');
|
|
37
61
|
console.log('');
|
|
@@ -93,7 +117,7 @@ if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
|
93
117
|
}
|
|
94
118
|
}
|
|
95
119
|
|
|
96
|
-
loadConfig(
|
|
120
|
+
loadConfig(globalEnv);
|
|
97
121
|
|
|
98
122
|
(async () => {
|
|
99
123
|
try {
|
|
@@ -109,8 +133,148 @@ if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
|
109
133
|
process.exit(1);
|
|
110
134
|
}
|
|
111
135
|
})();
|
|
136
|
+
} else if (cmd === 'import-object') {
|
|
137
|
+
const fileName = filteredArgs[1];
|
|
138
|
+
if (!fileName) {
|
|
139
|
+
console.error('错误: 请指定 JSON 文件路径');
|
|
140
|
+
console.log('用法: sks-maximo import-object <fileName> [-e env]');
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
loadConfig(globalEnv);
|
|
144
|
+
(async () => {
|
|
145
|
+
try {
|
|
146
|
+
const result = await importMaxObject({ fileName, logname: fileName });
|
|
147
|
+
if (result) {
|
|
148
|
+
console.log('导入成功');
|
|
149
|
+
} else {
|
|
150
|
+
console.error('导入失败');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error('导入出错:', error.message);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
})();
|
|
158
|
+
} else if (cmd === 'import-appinfo') {
|
|
159
|
+
const fileName = filteredArgs[1];
|
|
160
|
+
if (!fileName) {
|
|
161
|
+
console.error('错误: 请指定 JSON 文件路径');
|
|
162
|
+
console.log('用法: sks-maximo import-appinfo <fileName> [-e env] [-l logname]');
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
let logname = null;
|
|
166
|
+
for (let i = 2; i < filteredArgs.length; i++) {
|
|
167
|
+
if (filteredArgs[i] === '--logname' || filteredArgs[i] === '-l') {
|
|
168
|
+
logname = filteredArgs[i + 1];
|
|
169
|
+
i++;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
loadConfig(globalEnv);
|
|
173
|
+
(async () => {
|
|
174
|
+
try {
|
|
175
|
+
const result = await importMaxAppInfo({ fileName, logname: logname || fileName });
|
|
176
|
+
if (result) {
|
|
177
|
+
console.log('导入成功');
|
|
178
|
+
} else {
|
|
179
|
+
console.error('导入失败');
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error('导入出错:', error.message);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
})();
|
|
187
|
+
} else if (cmd === 'import-presentation') {
|
|
188
|
+
const fileName = filteredArgs[1];
|
|
189
|
+
if (!fileName) {
|
|
190
|
+
console.error('错误: 请指定 XML 文件路径');
|
|
191
|
+
console.log('用法: sks-maximo import-presentation <fileName> [-e env] [-l logname]');
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
let logname = null;
|
|
195
|
+
for (let i = 2; i < filteredArgs.length; i++) {
|
|
196
|
+
if (filteredArgs[i] === '--logname' || filteredArgs[i] === '-l') {
|
|
197
|
+
logname = filteredArgs[i + 1];
|
|
198
|
+
i++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
loadConfig(globalEnv);
|
|
202
|
+
(async () => {
|
|
203
|
+
try {
|
|
204
|
+
const result = await importMaxPresentation({ fileName, logname: logname || fileName });
|
|
205
|
+
if (result) {
|
|
206
|
+
console.log('导入成功');
|
|
207
|
+
} else {
|
|
208
|
+
console.error('导入失败');
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error('导入出错:', error.message);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
})();
|
|
216
|
+
} else if (cmd === 'import-script') {
|
|
217
|
+
const fileName = filteredArgs[1];
|
|
218
|
+
if (!fileName) {
|
|
219
|
+
console.error('错误: 请指定脚本 JSON 配置文件路径');
|
|
220
|
+
console.log('用法: sks-maximo import-script <fileName> [-e env] [-l logname]');
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
let logname = null;
|
|
224
|
+
for (let i = 2; i < filteredArgs.length; i++) {
|
|
225
|
+
if (filteredArgs[i] === '--logname' || filteredArgs[i] === '-l') {
|
|
226
|
+
logname = filteredArgs[i + 1];
|
|
227
|
+
i++;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
loadConfig(globalEnv);
|
|
231
|
+
(async () => {
|
|
232
|
+
try {
|
|
233
|
+
const result = await importMaxScript({ fileName, logname: logname || fileName });
|
|
234
|
+
if (result) {
|
|
235
|
+
console.log('导入成功');
|
|
236
|
+
} else {
|
|
237
|
+
console.error('导入失败');
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
} catch (error) {
|
|
241
|
+
console.error('导入出错:', error.message);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
})();
|
|
245
|
+
} else if (cmd === 'import-domain') {
|
|
246
|
+
const fileName = filteredArgs[1];
|
|
247
|
+
if (!fileName) {
|
|
248
|
+
console.error('错误: 请指定域 JSON 文件路径');
|
|
249
|
+
console.log('用法: sks-maximo import-domain <fileName> [-e env] [-l logname]');
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
let logname = null;
|
|
253
|
+
for (let i = 2; i < filteredArgs.length; i++) {
|
|
254
|
+
if (filteredArgs[i] === '--logname' || filteredArgs[i] === '-l') {
|
|
255
|
+
logname = filteredArgs[i + 1];
|
|
256
|
+
i++;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
loadConfig(globalEnv);
|
|
260
|
+
(async () => {
|
|
261
|
+
try {
|
|
262
|
+
const result = await importMaxDomain({ fileName, logname: logname || fileName });
|
|
263
|
+
if (result) {
|
|
264
|
+
console.log('导入成功');
|
|
265
|
+
} else {
|
|
266
|
+
console.error('导入失败');
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
} catch (error) {
|
|
270
|
+
console.error('导入出错:', error.message);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
})();
|
|
112
274
|
} else {
|
|
113
|
-
|
|
275
|
+
console.error(`不支持的命令: ${cmd}`);
|
|
276
|
+
console.log('使用 sks-maximo --help 查看帮助信息');
|
|
277
|
+
process.exit(1);
|
|
114
278
|
}
|
|
115
279
|
|
|
116
280
|
export * from './nodeutils/maximoTools.js';
|
package/index.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
export { loadConfig, getConfig, getWorkDir } from './nodeutils/config.js';
|
|
3
3
|
export { default as logger } from './nodeutils/logger.js';
|
|
4
4
|
export { default as request } from './nodeutils/requestHttp.js';
|
|
5
|
-
export
|
|
6
|
-
export { importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, saveScriptHistory, importMaxAppInfo, callMaxScript } from './nodeutils/maximoTools.js';
|
|
5
|
+
export * as fileUtils from './nodeutils/fileUtils.js';
|
|
6
|
+
export { importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, saveScriptHistory, importMaxAppInfo, callMaxScript, batchImport, printBatchStats } from './nodeutils/maximoTools.js';
|
|
7
7
|
export { sendMockData, sendMockDataBatch, sendPOMockData, sendPOMockDataBatch, sendRlImportMockDataBatch } from './nodeutils/mockdataTools.js';
|
package/nodeutils/fileUtils.js
CHANGED
|
@@ -88,9 +88,70 @@ function fileExists(fileNameIn) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* 通用文件路径转换 - 将各种形式的文件路径转换为规范化后的实际可用路径
|
|
93
|
+
* @param {string} fileName - 文件名或路径(支持相对路径、绝对路径)
|
|
94
|
+
* @returns {string} 规范化后的绝对路径
|
|
95
|
+
*/
|
|
96
|
+
function resolveFilePath(fileName) {
|
|
97
|
+
if (!fileName) return '';
|
|
98
|
+
// 统一分隔符
|
|
99
|
+
fileName = fileName.replace(/\\/g, '/');
|
|
100
|
+
// 绝对路径直接规范化返回
|
|
101
|
+
if (path.isAbsolute(fileName)) {
|
|
102
|
+
return path.normalize(fileName);
|
|
103
|
+
}
|
|
104
|
+
// 相对路径拼接工作目录
|
|
105
|
+
return path.normalize(path.join(getWorkDir(), fileName));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 列出目录中的文件
|
|
110
|
+
* @param {string} dirName - 目录名(相对或绝对路径)
|
|
111
|
+
* @param {string} [extFilter] - 文件扩展名过滤,如 '.json'、'.js',不传则返回所有文件
|
|
112
|
+
* @param {boolean} [recursive=true] - 是否递归检索子目录
|
|
113
|
+
* @returns {string[]} 文件全路径数组
|
|
114
|
+
*/
|
|
115
|
+
function listFiles(dirName, extFilter, recursive = true) {
|
|
116
|
+
const dirPath = path.isAbsolute(dirName.replace(/\\/g, '/')) ? dirName : path.join(getWorkDir(), dirName);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
if (!fs.existsSync(dirPath)) {
|
|
120
|
+
console.error(`目录不存在: ${dirPath}`);
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const results = [];
|
|
125
|
+
|
|
126
|
+
function scanDir(currentPath, baseRelative) {
|
|
127
|
+
const entries = fs.readdirSync(currentPath, { withFileTypes: true });
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
const fullPath = path.join(currentPath, entry.name);
|
|
130
|
+
const relativePath = baseRelative ? path.join(baseRelative, entry.name) : entry.name;
|
|
131
|
+
|
|
132
|
+
if (entry.isFile()) {
|
|
133
|
+
if (!extFilter || entry.name.endsWith(extFilter)) {
|
|
134
|
+
results.push(fullPath);
|
|
135
|
+
}
|
|
136
|
+
} else if (entry.isDirectory() && recursive) {
|
|
137
|
+
scanDir(fullPath, relativePath);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
scanDir(dirPath, '');
|
|
143
|
+
return results;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(`列出目录文件失败: ${dirName}`, error.message);
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
91
150
|
export {
|
|
92
151
|
readFileContent,
|
|
93
152
|
readJsonFile,
|
|
94
153
|
readXmlFile,
|
|
95
|
-
fileExists
|
|
154
|
+
fileExists,
|
|
155
|
+
listFiles,
|
|
156
|
+
resolveFilePath
|
|
96
157
|
};
|
package/nodeutils/logger.js
CHANGED
|
@@ -8,6 +8,17 @@ const LEVELS = {
|
|
|
8
8
|
FATAL: 5
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// 颜色定义
|
|
12
|
+
const COLORS = {
|
|
13
|
+
TRACE: '\x1b[90m', // 灰色
|
|
14
|
+
DEBUG: '\x1b[36m', // 青色
|
|
15
|
+
INFO: '\x1b[32m', // 绿色
|
|
16
|
+
WARN: '\x1b[33m', // 黄色
|
|
17
|
+
ERROR: '\x1b[31m', // 红色
|
|
18
|
+
FATAL: '\x1b[1;31m' // 粗体红
|
|
19
|
+
};
|
|
20
|
+
const RESET = '\x1b[0m';
|
|
21
|
+
|
|
11
22
|
class ConsoleLogger {
|
|
12
23
|
constructor(level = 'INFO') {
|
|
13
24
|
this.level = LEVELS[level] !== undefined ? LEVELS[level] : LEVELS.INFO;
|
|
@@ -27,7 +38,8 @@ class ConsoleLogger {
|
|
|
27
38
|
if (levelValue < this.level) return;
|
|
28
39
|
|
|
29
40
|
const timestamp = new Date().toLocaleTimeString();
|
|
30
|
-
const
|
|
41
|
+
const color = COLORS[levelName] || '';
|
|
42
|
+
const prefix = `${color}[${timestamp}] [${levelName}]${RESET}`;
|
|
31
43
|
|
|
32
44
|
switch (levelValue) {
|
|
33
45
|
case LEVELS.TRACE:
|
|
@@ -36,11 +48,11 @@ class ConsoleLogger {
|
|
|
36
48
|
console.log(prefix, ...args);
|
|
37
49
|
break;
|
|
38
50
|
case LEVELS.WARN:
|
|
39
|
-
console.warn(prefix, ...args);
|
|
51
|
+
console.warn(prefix, ...args);
|
|
40
52
|
break;
|
|
41
53
|
case LEVELS.ERROR:
|
|
42
54
|
case LEVELS.FATAL:
|
|
43
|
-
console.error(prefix, ...args);
|
|
55
|
+
console.error(prefix, ...args);
|
|
44
56
|
break;
|
|
45
57
|
}
|
|
46
58
|
}
|
package/nodeutils/maximoTools.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import request from '../nodeutils/requestHttp.js'
|
|
2
|
-
import { readFileContent, readJsonFile, readXmlFile } from './fileUtils.js'
|
|
2
|
+
import { readFileContent, readJsonFile, readXmlFile, resolveFilePath, listFiles } from './fileUtils.js'
|
|
3
3
|
import logger from './logger.js';
|
|
4
4
|
import { getConfig } from './config.js';
|
|
5
5
|
import os from 'os'
|
|
6
|
+
import path from 'path'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* 导入Maximo对象配置
|
|
@@ -255,10 +256,23 @@ export async function saveScriptHistory({autoscript, source, version = '', alias
|
|
|
255
256
|
*/
|
|
256
257
|
export async function importMaxScript({fileName, logname}) {
|
|
257
258
|
try {
|
|
258
|
-
|
|
259
|
+
// 使用通用路径转换方法解析路径
|
|
260
|
+
const resolvedFilePath = resolveFilePath(fileName);
|
|
261
|
+
const fileExt = path.extname(resolvedFilePath).toLowerCase();
|
|
262
|
+
|
|
263
|
+
// 如果不是JSON文件(如直接传入了.js/.py脚本文件路径),自动找同目录下的同名JSON配置文件
|
|
264
|
+
let jsonFilePath = resolvedFilePath;
|
|
265
|
+
if (fileExt !== '.json') {
|
|
266
|
+
const dir = path.dirname(resolvedFilePath);
|
|
267
|
+
const baseName = path.basename(resolvedFilePath, fileExt);
|
|
268
|
+
jsonFilePath = path.join(dir, `${baseName}.json`);
|
|
269
|
+
logger.info(`[导入脚本] 传入的是脚本文件,尝试查找配置文件: ${jsonFilePath}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const jsonContent = readJsonFile(jsonFilePath);
|
|
259
273
|
|
|
260
274
|
if (!jsonContent) {
|
|
261
|
-
logger.error(
|
|
275
|
+
logger.error(`配置文件读取失败: ${jsonFilePath}`);
|
|
262
276
|
return false;
|
|
263
277
|
}
|
|
264
278
|
|
|
@@ -275,12 +289,13 @@ export async function importMaxScript({fileName, logname}) {
|
|
|
275
289
|
const scriptExt = isPython ? '.py' : '.js';
|
|
276
290
|
|
|
277
291
|
const actualLogname = logname || autoscript;
|
|
278
|
-
logger.info(`[${actualLogname}]成功读取配置文件: ${
|
|
292
|
+
logger.info(`[${actualLogname}]成功读取配置文件: ${jsonFilePath}`);
|
|
279
293
|
logger.warn(`[${actualLogname}]脚本名称: ${autoscript}`);
|
|
280
294
|
logger.warn(`[${actualLogname}]脚本语言: ${scriptLanguage}`);
|
|
281
295
|
|
|
282
|
-
|
|
283
|
-
const
|
|
296
|
+
// 脚本文件路径:在配置文件同目录下,按 autoscript 名称查找
|
|
297
|
+
const dirname = path.dirname(jsonFilePath);
|
|
298
|
+
const scriptFileName = path.join(dirname, `${autoscript}${scriptExt}`);
|
|
284
299
|
|
|
285
300
|
const fileContent = readFileContent(scriptFileName);
|
|
286
301
|
|
|
@@ -656,7 +671,7 @@ export async function callMaxScript({ apiScriptName, fileName, params = {}, logn
|
|
|
656
671
|
const response = await request(requestConfig)
|
|
657
672
|
|
|
658
673
|
logger.info(`[${actualLogname}]收到响应`)
|
|
659
|
-
logger.
|
|
674
|
+
logger.warn(`[${actualLogname}]响应内容:`, response)
|
|
660
675
|
|
|
661
676
|
if (response !== null && response !== undefined) {
|
|
662
677
|
logger.info(`[${actualLogname}]调用成功`)
|
|
@@ -677,3 +692,119 @@ export async function callMaxScript({ apiScriptName, fileName, params = {}, logn
|
|
|
677
692
|
return null
|
|
678
693
|
}
|
|
679
694
|
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* 通用批量导入 - 支持各种导入功能(对象、脚本、应用信息、域、应用XML等)的批量处理
|
|
698
|
+
* @param {Object} options - 配置选项
|
|
699
|
+
* @param {string} [options.dirName] - 目录名(与files二选一),自动列出目录下符合条件的文件
|
|
700
|
+
* @param {string[]} [options.files] - 文件路径数组(与dirName二选一),直接指定要导入的文件
|
|
701
|
+
* @param {string} [options.extFilter] - 扩展名过滤,如 '.json'、'.xml'(配合dirName使用)
|
|
702
|
+
* @param {boolean} [options.recursive=true] - 是否递归检索子目录(配合dirName使用)
|
|
703
|
+
* @param {Function} options.importFn - 导入函数,接收 {fileName, logname} 参数,如 importMaxObject、importMaxScript 等
|
|
704
|
+
* @param {string} [options.logname] - 日志打印名称
|
|
705
|
+
* @param {number} [options.concurrency=1] - 并发数量,默认1串行执行
|
|
706
|
+
* @param {boolean} [options.continueOnError=true] - 单个文件失败时是否继续,默认继续
|
|
707
|
+
* @returns {Promise<Object>} 批量导入统计结果
|
|
708
|
+
*/
|
|
709
|
+
export async function batchImport({ dirName, files, extFilter, recursive = true, importFn, logname = '批量导入', concurrency = 1, continueOnError = true }) {
|
|
710
|
+
if (typeof importFn !== 'function') {
|
|
711
|
+
logger.error('[batchImport]必须指定importFn导入函数')
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
let fileNames = [];
|
|
716
|
+
if (files && Array.isArray(files) && files.length > 0) {
|
|
717
|
+
fileNames = files;
|
|
718
|
+
} else if (dirName) {
|
|
719
|
+
fileNames = listFiles(dirName, extFilter, recursive);
|
|
720
|
+
} else {
|
|
721
|
+
logger.error('[batchImport]必须指定dirName或files');
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if (fileNames.length === 0) {
|
|
726
|
+
logger.warn('[batchImport]没有找到需要导入的文件');
|
|
727
|
+
return null;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const stats = {
|
|
731
|
+
fileCount: fileNames.length,
|
|
732
|
+
successCount: 0,
|
|
733
|
+
failCount: 0,
|
|
734
|
+
successList: [],
|
|
735
|
+
failList: [],
|
|
736
|
+
startTime: new Date().getTime(),
|
|
737
|
+
endTime: null,
|
|
738
|
+
totalTime: null
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
logger.warn(`[${logname}]开始批量导入,共 ${fileNames.length} 个文件,并发数: ${concurrency}`);
|
|
742
|
+
|
|
743
|
+
// 并发池处理
|
|
744
|
+
let index = 0;
|
|
745
|
+
const worker = async () => {
|
|
746
|
+
while (index < fileNames.length) {
|
|
747
|
+
const cur = index++;
|
|
748
|
+
const filename = fileNames[cur];
|
|
749
|
+
try {
|
|
750
|
+
const result = await importFn({ fileName: filename, logname });
|
|
751
|
+
if (result) {
|
|
752
|
+
stats.successCount++;
|
|
753
|
+
stats.successList.push(filename);
|
|
754
|
+
} else {
|
|
755
|
+
stats.failCount++;
|
|
756
|
+
stats.failList.push(filename);
|
|
757
|
+
}
|
|
758
|
+
} catch (error) {
|
|
759
|
+
stats.failCount++;
|
|
760
|
+
stats.failList.push(filename);
|
|
761
|
+
logger.error(`[${logname}]导入异常: ${filename}`, error.message);
|
|
762
|
+
if (!continueOnError) {
|
|
763
|
+
throw error;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
logger.warn(`[${logname}]进度: ${cur + 1}/${fileNames.length} 成功: ${stats.successCount} 失败: ${stats.failCount}`);
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
const workerCount = Math.max(1, Math.min(concurrency, fileNames.length));
|
|
771
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
772
|
+
|
|
773
|
+
stats.endTime = new Date().getTime();
|
|
774
|
+
stats.totalTime = stats.endTime - stats.startTime;
|
|
775
|
+
|
|
776
|
+
logger.warn(`[${logname}]批量导入完成,耗时: ${stats.totalTime}ms,成功: ${stats.successCount},失败: ${stats.failCount}`);
|
|
777
|
+
if (stats.failList.length > 0) {
|
|
778
|
+
logger.warn(`[${logname}]失败文件列表:`);
|
|
779
|
+
stats.failList.forEach(f => logger.warn(` ${f}`));
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return stats;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* 打印批量导入统计结果
|
|
787
|
+
* @param {Object} stats - batchImport 返回的统计结果
|
|
788
|
+
* @param {string} [logname] - 日志打印名称
|
|
789
|
+
*/
|
|
790
|
+
export function printBatchStats(stats, logname = '批量导入') {
|
|
791
|
+
if (!stats) {
|
|
792
|
+
logger.warn(`[${logname}]无统计结果可打印`);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
const formatDateTime = (timestamp) => {
|
|
796
|
+
const d = new Date(timestamp);
|
|
797
|
+
const pad = n => String(n).padStart(2, '0');
|
|
798
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
799
|
+
};
|
|
800
|
+
logger.warn(`[${logname}]========== 批量导入统计 ==========`);
|
|
801
|
+
logger.warn(`[${logname}]总文件数: ${stats.fileCount}`);
|
|
802
|
+
logger.warn(`[${logname}]成功数量: ${stats.successCount}`);
|
|
803
|
+
logger.warn(`[${logname}]失败数量: ${stats.failCount}`);
|
|
804
|
+
logger.warn(`[${logname}]开始时间: ${formatDateTime(stats.startTime)} 结束时间: ${formatDateTime(stats.endTime)} 耗时: ${stats.totalTime}ms`);
|
|
805
|
+
logger.warn(`[${logname}]成功文件列表:`);
|
|
806
|
+
stats.successList.forEach(f => logger.warn(` ${f}`));
|
|
807
|
+
logger.warn(`[${logname}]失败文件列表:`);
|
|
808
|
+
stats.failList.forEach(f => logger.warn(` ${f}`));
|
|
809
|
+
logger.warn(`[${logname}]====================================`);
|
|
810
|
+
}
|
package/nodeutils/requestHttp.js
CHANGED
|
@@ -265,17 +265,15 @@ function createService() {
|
|
|
265
265
|
if (error.response&&error.response.data) {
|
|
266
266
|
logger.info('[Response Error] 错误error.response.data:', error.response.data);
|
|
267
267
|
if (error.response.data['oslc:Error']) {
|
|
268
|
-
if (error.response.data['oslc:Error']['oslc:
|
|
268
|
+
if (error.response.data['oslc:Error']['oslc:message']) {
|
|
269
|
+
logger.error('[Response Error] 错误error.response.data.oslc:Error.oslc:message:\x1b[32m['+error.response.data['oslc:Error']['oslc:message']+"]\x1b[0m");
|
|
270
|
+
}else if (error.response.data['oslc:Error']['oslc:extendedError']) {
|
|
269
271
|
if (error.response.data['oslc:Error']['oslc:extendedError']['oslc:moreInfo']) {
|
|
270
272
|
logger.error('[Response Error] 错误error.response.data:', error.response.data['oslc:Error']['oslc:extendedError']['oslc:moreInfo']);
|
|
271
273
|
|
|
272
274
|
}
|
|
273
275
|
} else {
|
|
274
|
-
|
|
275
|
-
logger.error('[Response Error] 错误error.response.data.oslc:Error.oslc:message:', error.response.data['oslc:Error']['oslc:message']);
|
|
276
|
-
}else{
|
|
277
|
-
logger.error('[Response Error] 错误error.response.data.oslc:Error.oslc:message:', error.response.data['oslc:Error']);
|
|
278
|
-
}
|
|
276
|
+
logger.error('[Response Error] 错误error.response.data.oslc:Error', error.response.data['oslc:Error']);
|
|
279
277
|
}
|
|
280
278
|
}
|
|
281
279
|
}
|