sks-maximo-utils 1.0.6 → 1.0.8

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 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,26 +141,26 @@ sks-maximo call <scriptName> [--file <fileName>] [--params <params>] [--logname
52
141
  | `--params` | `-p` | URL 查询参数(JSON格式) | 否 |
53
142
  | `--logname` | `-l` | 日志名称 | 否 |
54
143
 
55
- ### 3.1 GET 请求(无请求体)
144
+ ### 4.1 GET 请求(无请求体)
56
145
 
57
146
  ```bash
58
- sks-maximo call SHARPTREE.AUTOSCRIPT.LIBRARY --params '{"name":"TEST"}'
147
+ sks-maximo call SKS.AUTOSCRIPT.LIBRARY --params '{"name":"TEST"}'
59
148
  ```
60
149
 
61
- ### 3.2 POST 请求(带请求体文件)
150
+ ### 4.2 POST 请求(带请求体文件)
62
151
 
63
152
  ```bash
64
153
  # JSON 请求体
65
154
  sks-maximo call SKS_DEPLOY_AUTOKEY --file data/autokey.json
66
155
 
67
156
  # XML 请求体
68
- sks-maximo call SHARPTREE.AUTOSCRIPT.SCREENS --file screens/test.xml
157
+ sks-maximo call SKS.AUTOSCRIPT.SCREENS --file screens/test.xml
69
158
 
70
159
  # 同时带参数和请求体
71
160
  sks-maximo call SKS_IMP_MAXAPPINFO --file appinfo.json --params '{"debug":true}' --logname "导入应用信息"
72
161
  ```
73
162
 
74
- ### 3.3 请求体文件处理
163
+ ### 4.3 请求体文件处理
75
164
 
76
165
  - **`.json` 文件**:自动解析为 JSON 对象作为请求体
77
166
  - **其他文件**:读取文件内容作为字符串请求体
@@ -111,7 +200,7 @@ sks-maximo call SKS_IMP_MAXAPPINFO --file appinfo.json --params '{"debug":true}'
111
200
  ### 示例 1:查询脚本库
112
201
 
113
202
  ```bash
114
- sks-maximo call SHARPTREE.AUTOSCRIPT.LIBRARY --params '{"name":"MY_SCRIPT"}'
203
+ sks-maximo call SKS.AUTOSCRIPT.LIBRARY --params '{"name":"MY_SCRIPT"}'
115
204
  ```
116
205
 
117
206
  ### 示例 2:部署自动编码
package/README.md CHANGED
@@ -40,9 +40,13 @@ import {
40
40
  importMaxAutoKey,
41
41
  importMaxScript,
42
42
  importMaxAppInfo,
43
+ callMaxScript,
44
+ batchImport,
45
+ printBatchStats,
46
+ fileUtils,
43
47
  loadConfig,
44
48
  logger
45
- } from 'shoukaiseki-maximo-utils';
49
+ } from 'sks-maximo-utils';
46
50
 
47
51
  // 加载配置(可选,默认 local)
48
52
  loadConfig('local');
@@ -66,6 +70,32 @@ importMaxScript({ fileName: "scripts/TEST.json" });
66
70
 
67
71
  // 导入应用信息配置
68
72
  importMaxAppInfo({ fileName: "MAXAPPINFO/appinfo.json", logname: "应用信息" });
73
+
74
+ // 通用脚本接口调用(GET)
75
+ callMaxScript({ apiScriptName: "SKS.AUTOSCRIPT.LIBRARY", params: { name: "test" }, logname: "查询脚本库" });
76
+
77
+ // 通用脚本接口调用(POST,读取文件内容作为请求体)
78
+ callMaxScript({ apiScriptName: "SKS_DEPLOY_AUTOKEY", fileName: "data/autokey.json", logname: "部署自动编码" });
79
+
80
+ // 通用批量导入(支持对象、脚本、域、应用信息等所有导入功能)
81
+ const stats = await batchImport({
82
+ dirName: "C:/Temp/hd/maxobject_backup", // 目录名(与files二选一)
83
+ extFilter: ".json", // 扩展名过滤
84
+ importFn: importMaxObject, // 导入函数(可换成其他导入方法)
85
+ logname: "批量导入对象",
86
+ concurrency: 1 // 并发数,默认1串行
87
+ });
88
+ printBatchStats(stats); // 打印批量导入统计结果
89
+
90
+ // 直接指定文件列表批量导入
91
+ await batchImport({
92
+ files: ["a.json", "b.json", "c.json"],
93
+ importFn: importMaxDomain
94
+ });
95
+
96
+ // 文件工具
97
+ fileUtils.listFiles('scripts', '.json');
98
+ fileUtils.readFileContent('test.txt');
69
99
  ```
70
100
 
71
101
  ## 配置文件
@@ -126,11 +156,18 @@ importMaxAppInfo({ fileName: "MAXAPPINFO/appinfo.json", logname: "应用信息"
126
156
 
127
157
  | 方法 | 说明 |
128
158
  |------|------|
159
+ | callMaxScript | 通用脚本接口调用(GET/POST) |
160
+ | batchImport | 通用批量导入(支持对象、脚本、域、应用信息等所有导入功能) |
161
+ | printBatchStats | 打印批量导入统计结果 |
129
162
  | loadConfig(env) | 加载指定环境配置 |
130
163
  | saveScriptHistory(options) | 保存脚本历史记录 |
131
164
  | readFileContent(fileName) | 读取文件内容 |
132
165
  | readJsonFile(fileName) | 读取并解析 JSON 文件 |
133
166
  | fileExists(fileName) | 检查文件是否存在 |
167
+ | fileUtils.resolveFilePath(fileName) | 通用路径转换(相对/绝对路径转规范化绝对路径) |
168
+ | fileUtils.listFiles(dirName, extFilter, recursive) | 列出目录文件 |
169
+ | fileUtils.readFileContent(fileName) | 读取文件内容 |
170
+ | fileUtils.readJsonFile(fileName) | 读取并解析 JSON 文件 |
134
171
 
135
172
  ### 日志文件
136
173
 
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
- const cmd = args[0];
14
- const env = args[0];
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> [--file <fileName>] [--params <params>] # 调用脚本接口');
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('local');
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
- loadConfig(env);
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 { readFileContent, readJsonFile, readXmlFile, fileExists } from './nodeutils/fileUtils.js';
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';
@@ -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
  };
@@ -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 prefix = `[${timestamp}] [${levelName}]`;
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); // 输出到 stderr,但通常显示为黄色警告
51
+ console.warn(prefix, ...args);
40
52
  break;
41
53
  case LEVELS.ERROR:
42
54
  case LEVELS.FATAL:
43
- console.error(prefix, ...args); // 输出到 stderr,通常显示为红色错误
55
+ console.error(prefix, ...args);
44
56
  break;
45
57
  }
46
58
  }
@@ -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对象配置
@@ -33,7 +34,7 @@ export async function importMaxObject({fileName, logname}) {
33
34
  // 发送请求到Maximo API
34
35
  logger.info(`[${logname}]开始发送请求...`);
35
36
  const response = await request({
36
- url: '/api/script/SHARPTREE.AUTOSCRIPT.LIBRARY',
37
+ url: '/api/script/SKS.AUTOSCRIPT.LIBRARY',
37
38
  method: 'post',
38
39
  params: {
39
40
  develop: true,
@@ -100,7 +101,7 @@ export async function importMaxPresentation({fileName, logname}) {
100
101
 
101
102
  logger.info(`[${logname}]开始发送请求...`);
102
103
  const response = await request({
103
- url: '/api/script/SHARPTREE.AUTOSCRIPT.SCREENS',
104
+ url: '/api/script/SKS.AUTOSCRIPT.SCREENS',
104
105
  method: 'post',
105
106
  headers: {
106
107
  'Content-Type': 'application/xml'
@@ -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
- const jsonContent = readJsonFile(fileName);
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(`文件读取失败: ${fileName}`);
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}]成功读取配置文件: ${fileName}`);
292
+ logger.info(`[${actualLogname}]成功读取配置文件: ${jsonFilePath}`);
279
293
  logger.warn(`[${actualLogname}]脚本名称: ${autoscript}`);
280
294
  logger.warn(`[${actualLogname}]脚本语言: ${scriptLanguage}`);
281
295
 
282
- const dirname = fileName.substring(0, fileName.lastIndexOf('/')) || fileName.substring(0, fileName.lastIndexOf('\\')) || '';
283
- const scriptFileName = dirname ? `${dirname}/${autoscript}${scriptExt}` : `${autoscript}${scriptExt}`;
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.debug(`[${actualLogname}]响应内容:`, response)
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
+ }
@@ -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:extendedError']) {
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
- if(error.response.data['oslc:Error']['oslc:message']){
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sks-maximo-utils",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Maximo helper tools for updating table structures and data",
5
5
  "type": "module",
6
6
  "main": "index.js",