sks-maximo-utils 1.0.8 → 1.1.1
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 +18 -1
- package/README.md +15 -1
- package/cli.js +32 -1
- package/index.js +1 -1
- package/nodeutils/maximoTools.js +113 -26
- package/package.json +1 -1
package/CLI.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
| `sks-maximo import-presentation <fileName>` | 导入应用XML配置 |
|
|
13
13
|
| `sks-maximo import-script <fileName>` | 导入自动化脚本 |
|
|
14
14
|
| `sks-maximo import-domain <fileName>` | 导入域配置 |
|
|
15
|
+
| `sks-maximo import-maxintobject <fileName>` | 导入对象结构(Integration Object)配置 |
|
|
15
16
|
|
|
16
17
|
---
|
|
17
18
|
|
|
@@ -116,7 +117,7 @@ sks-maximo import-script <fileName> [-e env] [-l logname]
|
|
|
116
117
|
sks-maximo import-domain <fileName> [-e env] [-l logname]
|
|
117
118
|
```
|
|
118
119
|
|
|
119
|
-
**说明:** 导入 Maximo
|
|
120
|
+
**说明:** 导入 Maximo 域配置,走 `SKS.AUTOSCRIPT.OBJECTS`(`_type=domains&_action=import`)。文件内容支持域数组 / `{domains:[...]}` / 单域对象三种格式。
|
|
120
121
|
|
|
121
122
|
| 参数 | 说明 | 必填 |
|
|
122
123
|
|------|------|------|
|
|
@@ -126,6 +127,22 @@ sks-maximo import-domain <fileName> [-e env] [-l logname]
|
|
|
126
127
|
|
|
127
128
|
---
|
|
128
129
|
|
|
130
|
+
### 3.6 导入对象结构(Integration Object)
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
sks-maximo import-maxintobject <fileName> [-e env] [-l logname]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**说明:** 导入 Maximo 对象结构(发布通道),走 `SKS.AUTOSCRIPT.OBJECTS`(`_type=integrationobjects&_action=import`)。文件内容需为 `{integrationobjects:[...]}` 格式(从对象结构导出的 JSON 可直接回导)。
|
|
137
|
+
|
|
138
|
+
| 参数 | 说明 | 必填 |
|
|
139
|
+
|------|------|------|
|
|
140
|
+
| `<fileName>` | 对象结构 JSON 文件路径 | 是 |
|
|
141
|
+
| `-e` / `--env` | 指定环境(默认 local) | 否 |
|
|
142
|
+
| `-l` / `--logname` | 日志打印名称 | 否 |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
129
146
|
## 4. 调用通用脚本接口
|
|
130
147
|
|
|
131
148
|
```bash
|
package/README.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Maximo 表结构和数据更新工具集。
|
|
4
4
|
|
|
5
|
+
配合 VSCODE插件 [maximo-script-helper](https://marketplace.visualstudio.com/items?itemName=shoukaiseki.maximo-script-helper) 中的脚本
|
|
6
|
+
|
|
7
|
+
配合web端 [maximo-manager-panel](https://gitee.com/shoukaiseki/maximo-manager-panel)
|
|
8
|
+
|
|
9
|
+
该工具的示例代码: [maximo_request_demo](https://gitee.com/shoukaiseki/maximo-helper-box/tree/master/maximo_request_demo)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
5
13
|
## 安装
|
|
6
14
|
|
|
7
15
|
### 全局安装(CLI 使用)
|
|
@@ -40,6 +48,7 @@ import {
|
|
|
40
48
|
importMaxAutoKey,
|
|
41
49
|
importMaxScript,
|
|
42
50
|
importMaxAppInfo,
|
|
51
|
+
importMaxIntObject,
|
|
43
52
|
callMaxScript,
|
|
44
53
|
batchImport,
|
|
45
54
|
printBatchStats,
|
|
@@ -71,6 +80,10 @@ importMaxScript({ fileName: "scripts/TEST.json" });
|
|
|
71
80
|
// 导入应用信息配置
|
|
72
81
|
importMaxAppInfo({ fileName: "MAXAPPINFO/appinfo.json", logname: "应用信息" });
|
|
73
82
|
|
|
83
|
+
// 导入对象结构(Integration Object): 走 SKS.AUTOSCRIPT.OBJECTS (_type=integrationobjects&_action=import)
|
|
84
|
+
// body 需为 {integrationobjects:[...]} 格式(导出的 JSON 可直接回导)
|
|
85
|
+
importMaxIntObject({ fileName: "DBMAXINTOBJECT/OSIBM_POISSUE.json", logname: "PO问题对象结构" });
|
|
86
|
+
|
|
74
87
|
// 通用脚本接口调用(GET)
|
|
75
88
|
callMaxScript({ apiScriptName: "SKS.AUTOSCRIPT.LIBRARY", params: { name: "test" }, logname: "查询脚本库" });
|
|
76
89
|
|
|
@@ -151,6 +164,7 @@ fileUtils.readFileContent('test.txt');
|
|
|
151
164
|
| importMaxAutoKey | 导入 AutoKey 配置 |
|
|
152
165
|
| importMaxScript | 导入自动化脚本(自动保存历史记录) |
|
|
153
166
|
| importMaxAppInfo | 导入应用信息配置 |
|
|
167
|
+
| importMaxIntObject | 导入对象结构(Integration Object)配置 |
|
|
154
168
|
|
|
155
169
|
### 其他方法
|
|
156
170
|
|
|
@@ -190,4 +204,4 @@ npm link sks-maximo-utils
|
|
|
190
204
|
|
|
191
205
|
## License
|
|
192
206
|
|
|
193
|
-
ISC
|
|
207
|
+
ISC
|
package/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ 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, importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, importMaxAppInfo } from './nodeutils/maximoTools.js';
|
|
6
|
+
import { callMaxScript, importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, importMaxAppInfo, importMaxIntObject } from './nodeutils/maximoTools.js';
|
|
7
7
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = new URL('.', import.meta.url).pathname;
|
|
@@ -38,6 +38,7 @@ if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
|
38
38
|
console.log(' sks-maximo import-presentation <fileName> # 导入应用XML配置');
|
|
39
39
|
console.log(' sks-maximo import-script <fileName> # 导入自动化脚本');
|
|
40
40
|
console.log(' sks-maximo import-domain <fileName> # 导入域配置');
|
|
41
|
+
console.log(' sks-maximo import-maxintobject <fileName> # 导入对象结构(Integration Object)配置');
|
|
41
42
|
console.log('');
|
|
42
43
|
console.log('环境:');
|
|
43
44
|
console.log(' local # 使用本地环境配置');
|
|
@@ -51,6 +52,7 @@ if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
|
51
52
|
console.log(' import-presentation # 导入应用XML配置');
|
|
52
53
|
console.log(' import-script # 导入自动化脚本');
|
|
53
54
|
console.log(' import-domain # 导入域配置');
|
|
55
|
+
console.log(' import-maxintobject # 导入对象结构(Integration Object)配置');
|
|
54
56
|
console.log('');
|
|
55
57
|
console.log('选项:');
|
|
56
58
|
console.log(' -h, --help # 显示帮助信息');
|
|
@@ -271,6 +273,35 @@ if (!cmd || ['-h', '--help', '-?', '--version', '-v'].includes(cmd)) {
|
|
|
271
273
|
process.exit(1);
|
|
272
274
|
}
|
|
273
275
|
})();
|
|
276
|
+
} else if (cmd === 'import-maxintobject') {
|
|
277
|
+
const fileName = filteredArgs[1];
|
|
278
|
+
if (!fileName) {
|
|
279
|
+
console.error('错误: 请指定对象结构 JSON 文件路径');
|
|
280
|
+
console.log('用法: sks-maximo import-maxintobject <fileName> [-e env] [-l logname]');
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
let logname = null;
|
|
284
|
+
for (let i = 2; i < filteredArgs.length; i++) {
|
|
285
|
+
if (filteredArgs[i] === '--logname' || filteredArgs[i] === '-l') {
|
|
286
|
+
logname = filteredArgs[i + 1];
|
|
287
|
+
i++;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
loadConfig(globalEnv);
|
|
291
|
+
(async () => {
|
|
292
|
+
try {
|
|
293
|
+
const result = await importMaxIntObject({ fileName, logname: logname || fileName });
|
|
294
|
+
if (result) {
|
|
295
|
+
console.log('导入成功');
|
|
296
|
+
} else {
|
|
297
|
+
console.error('导入失败');
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.error('导入出错:', error.message);
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
})();
|
|
274
305
|
} else {
|
|
275
306
|
console.error(`不支持的命令: ${cmd}`);
|
|
276
307
|
console.log('使用 sks-maximo --help 查看帮助信息');
|
package/index.js
CHANGED
|
@@ -3,5 +3,5 @@ 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
5
|
export * as fileUtils from './nodeutils/fileUtils.js';
|
|
6
|
-
export { importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, saveScriptHistory, importMaxAppInfo, callMaxScript, batchImport, printBatchStats } from './nodeutils/maximoTools.js';
|
|
6
|
+
export { importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, saveScriptHistory, importMaxAppInfo, importMaxIntObject, callMaxScript, batchImport, printBatchStats } from './nodeutils/maximoTools.js';
|
|
7
7
|
export { sendMockData, sendMockDataBatch, sendPOMockData, sendPOMockDataBatch, sendRlImportMockDataBatch } from './nodeutils/mockdataTools.js';
|
package/nodeutils/maximoTools.js
CHANGED
|
@@ -138,10 +138,41 @@ export async function importMaxPresentation({fileName, logname}) {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* 解析 SKS.AUTOSCRIPT.OBJECTS 导入响应,统一处理字符串/对象
|
|
143
|
+
* @param {any} response
|
|
144
|
+
* @returns {Object|null}
|
|
145
|
+
*/
|
|
146
|
+
function parseImportResponse(response) {
|
|
147
|
+
if (response === null || response === undefined) return null;
|
|
148
|
+
if (typeof response === 'string') {
|
|
149
|
+
try { return JSON.parse(response); } catch (e) { return null; }
|
|
150
|
+
}
|
|
151
|
+
return response;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 判断 SKS.AUTOSCRIPT.OBJECTS 批量导入是否真正成功(HTTP 200 但 summary.failed>0 视为失败)
|
|
156
|
+
* @param {any} response
|
|
157
|
+
* @returns {{ok: boolean, summary: Object|null, result: Array}}
|
|
158
|
+
*/
|
|
159
|
+
function checkImportResult(response) {
|
|
160
|
+
const data = parseImportResponse(response);
|
|
161
|
+
if (!data || data.status !== 'success' || !data.summary) {
|
|
162
|
+
return { ok: false, summary: data ? data.summary : null, result: data ? (data.result || []) : [] };
|
|
163
|
+
}
|
|
164
|
+
const failed = data.summary.failed || 0;
|
|
165
|
+
if (failed > 0) {
|
|
166
|
+
return { ok: false, summary: data.summary, result: data.result || [] };
|
|
167
|
+
}
|
|
168
|
+
return { ok: true, summary: data.summary, result: data.result || [] };
|
|
169
|
+
}
|
|
170
|
+
|
|
141
171
|
/**
|
|
142
172
|
* 导入Maximo域
|
|
173
|
+
* 走 SKS.AUTOSCRIPT.OBJECTS (_type=domains&_action=import), body 支持域数组 / {domains:[...]} / 单域对象
|
|
143
174
|
* @param {Object} options - 配置选项
|
|
144
|
-
* @param {string} options.fileName -
|
|
175
|
+
* @param {string} options.fileName - 配置文件名(JSON)
|
|
145
176
|
* @param {string} options.logname - 日志打印名称
|
|
146
177
|
* @returns {Promise<boolean>} 是否导入成功
|
|
147
178
|
*/
|
|
@@ -150,58 +181,114 @@ export async function importMaxDomain({fileName, logname}) {
|
|
|
150
181
|
logname = fileName
|
|
151
182
|
}
|
|
152
183
|
try {
|
|
153
|
-
// 根据文件扩展名选择读取方式
|
|
154
184
|
let fileContent = null;
|
|
155
185
|
fileContent = readFileContent(fileName);
|
|
156
|
-
|
|
157
|
-
// 检查文件是否成功读取
|
|
186
|
+
|
|
158
187
|
if (!fileContent) {
|
|
159
188
|
logger.error(`[${logname}]文件读取失败: ${fileName}`);
|
|
160
189
|
return false;
|
|
161
190
|
}
|
|
162
|
-
|
|
191
|
+
|
|
163
192
|
logger.info(`[${logname}]成功读取文件: ${fileName}`);
|
|
164
193
|
logger.info(`[${logname}]文件大小: ${fileContent.length} 字节`);
|
|
165
194
|
logger.info(`[${logname}]准备导入domain: ${logname || '未指定'}`);
|
|
166
|
-
|
|
167
|
-
// 发送请求到Maximo API
|
|
195
|
+
|
|
168
196
|
logger.info(`[${logname}]开始发送请求...`);
|
|
169
197
|
const response = await request({
|
|
170
|
-
url: '/api/script/
|
|
198
|
+
url: '/api/script/SKS.AUTOSCRIPT.OBJECTS',
|
|
171
199
|
method: 'post',
|
|
172
200
|
params: {
|
|
173
|
-
|
|
201
|
+
_type: 'domains',
|
|
202
|
+
_action: 'import',
|
|
174
203
|
_langcode: getConfig().langcode,
|
|
175
204
|
},
|
|
176
|
-
data: fileContent
|
|
205
|
+
data: fileContent
|
|
177
206
|
})
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// 检查响应 - requestHttp的响应拦截器已返回res.data
|
|
184
|
-
if (response !== null && response !== undefined) {
|
|
185
|
-
logger.warn(`[${logname}]导入成功`)
|
|
207
|
+
|
|
208
|
+
const { ok, summary, result } = checkImportResult(response);
|
|
209
|
+
if (ok) {
|
|
210
|
+
logger.warn(`[${logname}]导入成功 总计:${summary.total} 成功:${summary.success}`)
|
|
186
211
|
return true
|
|
187
212
|
} else {
|
|
188
|
-
logger.error(`[${logname}]
|
|
189
|
-
|
|
213
|
+
logger.error(`[${logname}]导入失败, 响应:`, response)
|
|
214
|
+
if (result && result.length > 0) {
|
|
215
|
+
result.filter(r => r.status === 'FAILED').forEach(r => {
|
|
216
|
+
logger.error(`[${logname}] - ${r.domainid || r.id || '未知'}: ${r.message}`)
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
return false
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
logger.error(`[${logname}]请求出错:`, error.message)
|
|
223
|
+
if (error.response) {
|
|
224
|
+
// 服务器返回了错误状态码
|
|
225
|
+
} else if (error.request) {
|
|
226
|
+
logger.error(`[${logname}]请求已发出但无响应`)
|
|
227
|
+
} else {
|
|
228
|
+
logger.error(`[${logname}]错误详情:`, error)
|
|
229
|
+
}
|
|
230
|
+
return false
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 导入Maximo对象结构(Integration Object / 发布通道)
|
|
237
|
+
* 走 SKS.AUTOSCRIPT.OBJECTS (_type=integrationobjects&_action=import), body 为 {integrationobjects:[...]}
|
|
238
|
+
* @param {Object} options - 配置选项
|
|
239
|
+
* @param {string} options.fileName - 配置文件名(JSON)
|
|
240
|
+
* @param {string} options.logname - 日志打印名称
|
|
241
|
+
* @returns {Promise<boolean>} 是否导入成功
|
|
242
|
+
*/
|
|
243
|
+
export async function importMaxIntObject({fileName, logname}) {
|
|
244
|
+
if(!logname||logname===""||logname===null){
|
|
245
|
+
logname = fileName
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
let fileContent = null;
|
|
249
|
+
fileContent = readFileContent(fileName);
|
|
250
|
+
|
|
251
|
+
if (!fileContent) {
|
|
252
|
+
logger.error(`[${logname}]文件读取失败: ${fileName}`);
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
logger.info(`[${logname}]成功读取文件: ${fileName}`);
|
|
257
|
+
logger.info(`[${logname}]文件大小: ${fileContent.length} 字节`);
|
|
258
|
+
logger.info(`[${logname}]准备导入对象结构: ${logname || '未指定'}`);
|
|
259
|
+
|
|
260
|
+
logger.info(`[${logname}]开始发送请求...`);
|
|
261
|
+
const response = await request({
|
|
262
|
+
url: '/api/script/SKS.AUTOSCRIPT.OBJECTS',
|
|
263
|
+
method: 'post',
|
|
264
|
+
params: {
|
|
265
|
+
_type: 'integrationobjects',
|
|
266
|
+
_action: 'import',
|
|
267
|
+
_langcode: getConfig().langcode,
|
|
268
|
+
},
|
|
269
|
+
data: fileContent
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
const { ok, summary, result } = checkImportResult(response);
|
|
273
|
+
if (ok) {
|
|
274
|
+
logger.warn(`[${logname}]导入成功 总计:${summary.total} 成功:${summary.success}`)
|
|
275
|
+
return true
|
|
276
|
+
} else {
|
|
277
|
+
logger.error(`[${logname}]导入失败, 响应:`, response)
|
|
278
|
+
if (result && result.length > 0) {
|
|
279
|
+
result.filter(r => r.status === 'FAILED').forEach(r => {
|
|
280
|
+
logger.error(`[${logname}] - ${r.intobjectname || r.id || '未知'}: ${r.message}`)
|
|
281
|
+
})
|
|
282
|
+
}
|
|
190
283
|
return false
|
|
191
284
|
}
|
|
192
285
|
} catch (error) {
|
|
193
286
|
logger.error(`[${logname}]请求出错:`, error.message)
|
|
194
287
|
if (error.response) {
|
|
195
288
|
// 服务器返回了错误状态码
|
|
196
|
-
// logger.error(`[${logname}]错误状态码:`, error.response.status)
|
|
197
|
-
// logger.error(`[${logname}]错误响应数据:`, error.response.data)
|
|
198
289
|
} else if (error.request) {
|
|
199
|
-
// 请求已发出但没有收到响应
|
|
200
290
|
logger.error(`[${logname}]请求已发出但无响应`)
|
|
201
|
-
// logger.error(`[${logname}]请求URL:`, error.request.url)
|
|
202
|
-
// logger.error(`[${logname}]请求方法:`, error.request.method)
|
|
203
291
|
} else {
|
|
204
|
-
// 其他错误
|
|
205
292
|
logger.error(`[${logname}]错误详情:`, error)
|
|
206
293
|
}
|
|
207
294
|
return false
|