sks-maximo-utils 1.0.3 → 1.0.4
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/README.md +26 -3
- package/index.js +1 -1
- package/nodeutils/config.js +8 -0
- package/nodeutils/maximoTools.js +347 -4
- package/nodeutils/requestHttp.js +83 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,6 +38,8 @@ import {
|
|
|
38
38
|
importMaxPresentation,
|
|
39
39
|
importMaxDomain,
|
|
40
40
|
importMaxAutoKey,
|
|
41
|
+
importMaxScript,
|
|
42
|
+
importMaxAppInfo,
|
|
41
43
|
loadConfig,
|
|
42
44
|
logger
|
|
43
45
|
} from 'shoukaiseki-maximo-utils';
|
|
@@ -56,6 +58,14 @@ importMaxDomain({ fileName: "DBDOMAINJSON/domain.json", logname: "域" });
|
|
|
56
58
|
|
|
57
59
|
// 导入 AutoKey 配置
|
|
58
60
|
importMaxAutoKey({ fileName: "AUTOKEYJSON/autokey.json", logname: "自动编码" });
|
|
61
|
+
|
|
62
|
+
// 导入自动化脚本(自动保存历史记录)
|
|
63
|
+
// fileName为JSON配置文件,同目录下需有同名.js文件
|
|
64
|
+
// 例如:scripts/TEST.json 和 scripts/TEST.js
|
|
65
|
+
importMaxScript({ fileName: "scripts/TEST.json" });
|
|
66
|
+
|
|
67
|
+
// 导入应用信息配置
|
|
68
|
+
importMaxAppInfo({ fileName: "MAXAPPINFO/appinfo.json", logname: "应用信息" });
|
|
59
69
|
```
|
|
60
70
|
|
|
61
71
|
## 配置文件
|
|
@@ -66,18 +76,21 @@ importMaxAutoKey({ fileName: "AUTOKEYJSON/autokey.json", logname: "自动编码"
|
|
|
66
76
|
```json
|
|
67
77
|
{
|
|
68
78
|
"logLevel": "INFO",
|
|
79
|
+
"langcode": "zh",
|
|
69
80
|
"envs": {
|
|
70
81
|
"local": {
|
|
71
82
|
"baseUrl": "http://127.0.0.1:9080/maximo",
|
|
72
83
|
"apiKey": "your-api-key",
|
|
73
84
|
"maxauth": "",
|
|
74
|
-
"authType": "apiKey"
|
|
85
|
+
"authType": "apiKey",
|
|
86
|
+
"langcode": "zh"
|
|
75
87
|
},
|
|
76
88
|
"dev": {
|
|
77
89
|
"baseUrl": "https://mdev/maximo",
|
|
78
90
|
"apiKey": "your-api-key",
|
|
79
91
|
"maxauth": "",
|
|
80
|
-
"authType": "apiKey"
|
|
92
|
+
"authType": "apiKey",
|
|
93
|
+
"langcode": "zh"
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
}
|
|
@@ -88,12 +101,13 @@ importMaxAutoKey({ fileName: "AUTOKEYJSON/autokey.json", logname: "自动编码"
|
|
|
88
101
|
| 字段 | 说明 |
|
|
89
102
|
|------|------|
|
|
90
103
|
| logLevel | 全局日志级别:TRACE, DEBUG, INFO, WARN, ERROR, FATAL |
|
|
104
|
+
| langcode | 全局语言代码,默认 zh |
|
|
91
105
|
| baseUrl | Maximo 服务地址 |
|
|
92
106
|
| apiKey | API 认证密钥 |
|
|
93
107
|
| maxauth | Maxauth 认证值 |
|
|
94
108
|
| authType | 认证类型:apiKey 或 maxauth |
|
|
95
109
|
|
|
96
|
-
环境配置中可单独设置 `logLevel`,优先级高于全局配置。
|
|
110
|
+
环境配置中可单独设置 `logLevel` 和 `langcode`,优先级高于全局配置。
|
|
97
111
|
|
|
98
112
|
## API
|
|
99
113
|
|
|
@@ -105,16 +119,25 @@ importMaxAutoKey({ fileName: "AUTOKEYJSON/autokey.json", logname: "自动编码"
|
|
|
105
119
|
| importMaxPresentation | 导入应用 XML 配置 |
|
|
106
120
|
| importMaxDomain | 导入域配置 |
|
|
107
121
|
| importMaxAutoKey | 导入 AutoKey 配置 |
|
|
122
|
+
| importMaxScript | 导入自动化脚本(自动保存历史记录) |
|
|
123
|
+
| importMaxAppInfo | 导入应用信息配置 |
|
|
108
124
|
|
|
109
125
|
### 其他方法
|
|
110
126
|
|
|
111
127
|
| 方法 | 说明 |
|
|
112
128
|
|------|------|
|
|
113
129
|
| loadConfig(env) | 加载指定环境配置 |
|
|
130
|
+
| saveScriptHistory(options) | 保存脚本历史记录 |
|
|
114
131
|
| readFileContent(fileName) | 读取文件内容 |
|
|
115
132
|
| readJsonFile(fileName) | 读取并解析 JSON 文件 |
|
|
116
133
|
| fileExists(fileName) | 检查文件是否存在 |
|
|
117
134
|
|
|
135
|
+
### 日志文件
|
|
136
|
+
|
|
137
|
+
请求和响应日志会自动保存到 `~/.sks/nodeutils/logs/` 目录:
|
|
138
|
+
- `request-*.http` - 请求日志(IntelliJ IDEA HTTP Client 格式)
|
|
139
|
+
- `response-*.json` - 响应日志
|
|
140
|
+
|
|
118
141
|
## 开发
|
|
119
142
|
|
|
120
143
|
```bash
|
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 { readFileContent, readJsonFile, readXmlFile, fileExists } from './nodeutils/fileUtils.js';
|
|
6
|
-
export { importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey } from './nodeutils/maximoTools.js';
|
|
6
|
+
export { importMaxObject, importMaxPresentation, importMaxDomain, importMaxAutoKey, importMaxScript, saveScriptHistory, importMaxAppInfo } from './nodeutils/maximoTools.js';
|
|
7
7
|
export { sendMockData, sendMockDataBatch, sendPOMockData, sendPOMockDataBatch, sendRlImportMockDataBatch } from './nodeutils/mockdataTools.js';
|
package/nodeutils/config.js
CHANGED
|
@@ -77,6 +77,10 @@ export function loadConfig(env = null) {
|
|
|
77
77
|
|
|
78
78
|
// logLevel 优先使用环境配置,否则使用全局配置
|
|
79
79
|
const logLevel = envConfig.logLevel || globalLogLevel;
|
|
80
|
+
|
|
81
|
+
// langcode 优先使用环境配置,否则使用全局配置,默认 zh
|
|
82
|
+
const langcode = envConfig.langcode || allConfigs.langcode || 'zh';
|
|
83
|
+
globalConfig.langcode = langcode;
|
|
80
84
|
|
|
81
85
|
// 规范化 baseUrl
|
|
82
86
|
if (globalConfig.baseUrl) {
|
|
@@ -111,19 +115,23 @@ function copySampleConfig(configPath) {
|
|
|
111
115
|
// 如果 sample.config.json 不存在,创建默认配置
|
|
112
116
|
const defaultConfig = {
|
|
113
117
|
"logLevel": "INFO",
|
|
118
|
+
"langcode": "zh",
|
|
114
119
|
"envs": {
|
|
115
120
|
"local": {
|
|
116
121
|
"baseUrl": "http://127.0.0.1:9080/maximo",
|
|
122
|
+
"langcode": "zh",
|
|
117
123
|
"apiKey": "your-api-key-here",
|
|
118
124
|
"maxauth": ""
|
|
119
125
|
},
|
|
120
126
|
"dev": {
|
|
121
127
|
"baseUrl": "https://mdev/maximo",
|
|
128
|
+
"langcode": "zh",
|
|
122
129
|
"apiKey": "your-api-key-here",
|
|
123
130
|
"maxauth": ""
|
|
124
131
|
},
|
|
125
132
|
"hd": {
|
|
126
133
|
"baseUrl": "http://xxxxx:9080/maximo",
|
|
134
|
+
"langcode": "zh",
|
|
127
135
|
"apiKey": "your-api-key-here",
|
|
128
136
|
"maxauth": ""
|
|
129
137
|
}
|
package/nodeutils/maximoTools.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import request from '../nodeutils/requestHttp.js'
|
|
2
2
|
import { readFileContent, readJsonFile, readXmlFile } from './fileUtils.js'
|
|
3
3
|
import logger from './logger.js';
|
|
4
|
+
import { getConfig } from './config.js';
|
|
5
|
+
import os from 'os'
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* 导入Maximo对象配置
|
|
@@ -35,7 +37,7 @@ export async function importMaxObject({fileName, logname}) {
|
|
|
35
37
|
method: 'post',
|
|
36
38
|
params: {
|
|
37
39
|
develop: true,
|
|
38
|
-
_langcode:
|
|
40
|
+
_langcode: getConfig().langcode,
|
|
39
41
|
},
|
|
40
42
|
data: fileContent // 将文件内容作为请求体发送
|
|
41
43
|
})
|
|
@@ -104,7 +106,7 @@ export async function importMaxPresentation({fileName, logname}) {
|
|
|
104
106
|
'Content-Type': 'application/xml'
|
|
105
107
|
},
|
|
106
108
|
params: {
|
|
107
|
-
_langcode:
|
|
109
|
+
_langcode: getConfig().langcode,
|
|
108
110
|
},
|
|
109
111
|
data: fileContent
|
|
110
112
|
})
|
|
@@ -168,7 +170,7 @@ export async function importMaxDomain({fileName, logname}) {
|
|
|
168
170
|
method: 'post',
|
|
169
171
|
params: {
|
|
170
172
|
develop: true,
|
|
171
|
-
_langcode:
|
|
173
|
+
_langcode: getConfig().langcode,
|
|
172
174
|
},
|
|
173
175
|
data: fileContent // 将文件内容作为请求体发送
|
|
174
176
|
})
|
|
@@ -206,6 +208,286 @@ export async function importMaxDomain({fileName, logname}) {
|
|
|
206
208
|
}
|
|
207
209
|
|
|
208
210
|
|
|
211
|
+
/**
|
|
212
|
+
* 保存脚本历史记录
|
|
213
|
+
* @param {Object} options - 配置选项
|
|
214
|
+
* @param {string} options.autoscript - 脚本名称
|
|
215
|
+
* @param {string} options.source - 脚本内容
|
|
216
|
+
* @param {string} options.version - 版本号
|
|
217
|
+
* @param {string} options.aliasname - 别名
|
|
218
|
+
* @param {string} options.hostname - 主机名
|
|
219
|
+
* @returns {Promise<boolean>} 是否保存成功
|
|
220
|
+
*/
|
|
221
|
+
export async function saveScriptHistory({autoscript, source, version = '', aliasname = '', hostname = ''}) {
|
|
222
|
+
try {
|
|
223
|
+
logger.info(`[${autoscript}]保存脚本历史记录...`);
|
|
224
|
+
|
|
225
|
+
const response = await request({
|
|
226
|
+
url: '/api/script/SKS_AUTOSCRIPT_HISTORY_SAVE',
|
|
227
|
+
method: 'post',
|
|
228
|
+
params: {
|
|
229
|
+
_langcode: getConfig().langcode,
|
|
230
|
+
},
|
|
231
|
+
data: {
|
|
232
|
+
autoscript,
|
|
233
|
+
source,
|
|
234
|
+
version,
|
|
235
|
+
aliasname,
|
|
236
|
+
hostname
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
logger.info(`[${autoscript}]脚本历史记录保存成功`);
|
|
241
|
+
return response !== null && response !== undefined;
|
|
242
|
+
} catch (error) {
|
|
243
|
+
logger.error(`[${autoscript}]保存脚本历史记录失败:`, error.message);
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 导入Maximo自动化脚本(1:1还原插件工具箱导入流程)
|
|
251
|
+
* @param {Object} options - 配置选项
|
|
252
|
+
* @param {string} options.fileName - JSON配置文件名(同目录下需有同名.js或.py文件)
|
|
253
|
+
* @param {string} options.logname - 日志打印名称(可选,默认使用autoscript值)
|
|
254
|
+
* @returns {Promise<boolean>} 是否导入成功
|
|
255
|
+
*/
|
|
256
|
+
export async function importMaxScript({fileName, logname}) {
|
|
257
|
+
try {
|
|
258
|
+
const jsonContent = readJsonFile(fileName);
|
|
259
|
+
|
|
260
|
+
if (!jsonContent) {
|
|
261
|
+
logger.error(`文件读取失败: ${fileName}`);
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const requiredFields = ['autoscript', 'description', 'scriptlanguage'];
|
|
266
|
+
const missingFields = requiredFields.filter(field => !jsonContent[field]);
|
|
267
|
+
if (missingFields.length > 0) {
|
|
268
|
+
logger.error(`配置文件缺少必需字段: ${missingFields.join(', ')}`);
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const autoscript = jsonContent.autoscript;
|
|
273
|
+
const scriptLanguage = jsonContent.scriptlanguage.toLowerCase();
|
|
274
|
+
const isPython = (scriptLanguage === 'python' || scriptLanguage === 'jython');
|
|
275
|
+
const scriptExt = isPython ? '.py' : '.js';
|
|
276
|
+
|
|
277
|
+
const actualLogname = logname || autoscript;
|
|
278
|
+
logger.info(`[${actualLogname}]成功读取配置文件: ${fileName}`);
|
|
279
|
+
logger.info(`[${actualLogname}]脚本名称: ${autoscript}`);
|
|
280
|
+
logger.info(`[${actualLogname}]脚本语言: ${scriptLanguage}`);
|
|
281
|
+
|
|
282
|
+
const dirname = fileName.substring(0, fileName.lastIndexOf('/')) || fileName.substring(0, fileName.lastIndexOf('\\')) || '';
|
|
283
|
+
const scriptFileName = dirname ? `${dirname}/${autoscript}${scriptExt}` : `${autoscript}${scriptExt}`;
|
|
284
|
+
|
|
285
|
+
const fileContent = readFileContent(scriptFileName);
|
|
286
|
+
|
|
287
|
+
if (!fileContent) {
|
|
288
|
+
logger.error(`[${actualLogname}]脚本文件读取失败: ${scriptFileName}`);
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
logger.info(`[${actualLogname}]成功读取脚本文件: ${scriptFileName}`);
|
|
293
|
+
logger.info(`[${actualLogname}]文件大小: ${fileContent.length} 字节`);
|
|
294
|
+
|
|
295
|
+
await saveScriptHistory({
|
|
296
|
+
autoscript: autoscript,
|
|
297
|
+
source: fileContent,
|
|
298
|
+
version: 'deploy',
|
|
299
|
+
aliasname: '_script_',
|
|
300
|
+
hostname: os.hostname()
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const ignoreFields = ['BINARYSCRIPTSOURCE', 'AUTOSCRIPTID'];
|
|
304
|
+
|
|
305
|
+
const customFields = {};
|
|
306
|
+
for (const [key, value] of Object.entries(jsonContent)) {
|
|
307
|
+
if (ignoreFields.includes(key)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (key === 'SOURCE') {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
customFields[key.toLowerCase()] = value;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
customFields.autoscript = autoscript;
|
|
317
|
+
customFields.description = jsonContent.description;
|
|
318
|
+
customFields.source = fileContent.replace(/\r\n/g, '\n');
|
|
319
|
+
customFields.scriptlanguage = jsonContent.scriptlanguage;
|
|
320
|
+
|
|
321
|
+
if (jsonContent.active !== undefined) {
|
|
322
|
+
customFields.active = jsonContent.active === true || jsonContent.active === 1 || jsonContent.active === '1';
|
|
323
|
+
} else {
|
|
324
|
+
customFields.active = true;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
logger.info(`[${actualLogname}]步骤1: 检查脚本是否存在...`);
|
|
328
|
+
const checkUrl = `api/os/MXAPIAUTOSCRIPT?lean=1&oslc.select=autoscript&oslc.where=autoscript="${autoscript}"`;
|
|
329
|
+
|
|
330
|
+
let scriptExists = false;
|
|
331
|
+
let scriptHref = null;
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
const checkResult = await request({
|
|
335
|
+
url: checkUrl,
|
|
336
|
+
method: 'GET'
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
if (checkResult && checkResult.member) {
|
|
340
|
+
const memberCount = checkResult.member.length;
|
|
341
|
+
if (memberCount === 1) {
|
|
342
|
+
scriptExists = true;
|
|
343
|
+
scriptHref = checkResult.member[0].href;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} catch (error) {
|
|
347
|
+
logger.error(`[${actualLogname}]检查脚本失败:`, error.message);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (scriptExists) {
|
|
351
|
+
logger.info(`[${actualLogname}]脚本已存在,将执行更新操作`);
|
|
352
|
+
} else {
|
|
353
|
+
logger.info(`[${actualLogname}]脚本不存在,将执行创建操作`);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
let deployUrl;
|
|
357
|
+
let deployMethod = 'POST';
|
|
358
|
+
|
|
359
|
+
var headers={};
|
|
360
|
+
if (scriptExists && scriptHref) {
|
|
361
|
+
deployUrl = scriptHref;
|
|
362
|
+
deployMethod = 'POST';
|
|
363
|
+
headers = {
|
|
364
|
+
'Content-Type': 'application/merge-patch+json',
|
|
365
|
+
'x-method-override': 'PATCH'
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
} else {
|
|
369
|
+
deployUrl = 'api/os/MXAPIAUTOSCRIPT';
|
|
370
|
+
headers = {
|
|
371
|
+
'Content-Type': 'application/json'
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const deployBody = {};
|
|
376
|
+
|
|
377
|
+
for (const key in customFields) {
|
|
378
|
+
if (customFields.hasOwnProperty(key)) {
|
|
379
|
+
if (key.toLowerCase() === 'autoscript' || key.toLowerCase() === 'description' || key.toLowerCase() === 'source') {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (key.toLowerCase().startsWith('sks:')) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (key.toLowerCase().startsWith('sks:')
|
|
386
|
+
|| key.toLowerCase() === 'changedate'
|
|
387
|
+
|| key.toLowerCase() === 'statusdate'
|
|
388
|
+
) {
|
|
389
|
+
// 跳过 sks: 开头的字段
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (key.toLowerCase() === 'launchpoints') {
|
|
394
|
+
const launchPointsTmp = [];
|
|
395
|
+
for (const launchPoint of customFields[key]) {
|
|
396
|
+
const launchPointTmp = {};
|
|
397
|
+
const ignoreFieldsLaunchpoints = ['eventtype'];
|
|
398
|
+
for (const lpKey in launchPoint) {
|
|
399
|
+
if (ignoreFieldsLaunchpoints.includes(lpKey.toLowerCase())) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if (lpKey.startsWith('sks:')) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (launchPoint.hasOwnProperty(lpKey)) {
|
|
406
|
+
const prefixedKey = `spi:${lpKey.toLowerCase()}`;
|
|
407
|
+
launchPointTmp[prefixedKey] = launchPoint[lpKey];
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
launchPointsTmp.push(launchPointTmp);
|
|
411
|
+
}
|
|
412
|
+
deployBody['spi:scriptlaunchpoint'] = launchPointsTmp;
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (key.toLowerCase() === 'variables') {
|
|
417
|
+
const variablesTmp = [];
|
|
418
|
+
for (const variable of customFields[key]) {
|
|
419
|
+
const variableTmp = {};
|
|
420
|
+
for (const lpKey in variable) {
|
|
421
|
+
if (variable.hasOwnProperty(lpKey)) {
|
|
422
|
+
const prefixedKey = `spi:${lpKey.toLowerCase()}`;
|
|
423
|
+
variableTmp[prefixedKey] = variable[lpKey];
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
variablesTmp.push(variableTmp);
|
|
427
|
+
}
|
|
428
|
+
deployBody['spi:autoscriptvars'] = variablesTmp;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const prefixedKey = `spi:${key.toLowerCase()}`;
|
|
433
|
+
deployBody[prefixedKey] = customFields[key];
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (!deployBody['spi:autoscript']) {
|
|
438
|
+
deployBody['spi:autoscript'] = autoscript;
|
|
439
|
+
}
|
|
440
|
+
if (!deployBody['spi:description']) {
|
|
441
|
+
deployBody['spi:description'] = customFields.description;
|
|
442
|
+
}
|
|
443
|
+
if (!deployBody['spi:scriptlanguage']) {
|
|
444
|
+
deployBody['spi:scriptlanguage'] = customFields.scriptlanguage;
|
|
445
|
+
}
|
|
446
|
+
if (deployBody['spi:active'] === undefined) {
|
|
447
|
+
deployBody['spi:active'] = customFields.active;
|
|
448
|
+
}
|
|
449
|
+
if (deployBody['spi:version'] === undefined || deployBody['spi:version'] === '') {
|
|
450
|
+
deployBody['spi:version'] = '1.0.0';
|
|
451
|
+
}
|
|
452
|
+
if (customFields.source) {
|
|
453
|
+
deployBody['spi:source'] = customFields.source;
|
|
454
|
+
} else {
|
|
455
|
+
deployBody['spi:source'] = '';
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
logger.info(`[${actualLogname}]步骤2: 发送${deployMethod}请求到: ${deployUrl}`);
|
|
459
|
+
const deployResult = await request({
|
|
460
|
+
url: deployUrl,
|
|
461
|
+
method: deployMethod,
|
|
462
|
+
headers: {
|
|
463
|
+
...headers
|
|
464
|
+
},
|
|
465
|
+
data: deployBody
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
logger.info(`[${actualLogname}]收到响应`);
|
|
469
|
+
|
|
470
|
+
if (deployResult !== null && deployResult !== undefined) {
|
|
471
|
+
logger.warn(`[${actualLogname}]导入成功`)
|
|
472
|
+
return true
|
|
473
|
+
} else {
|
|
474
|
+
logger.error(`[${actualLogname}]导入失败,响应为空或null`)
|
|
475
|
+
return false
|
|
476
|
+
}
|
|
477
|
+
} catch (error) {
|
|
478
|
+
logger.error(`请求出错:`, error.message)
|
|
479
|
+
if (error.response) {
|
|
480
|
+
// 服务器返回了错误状态码
|
|
481
|
+
} else if (error.request) {
|
|
482
|
+
logger.error(`请求已发出但无响应`)
|
|
483
|
+
} else {
|
|
484
|
+
logger.error(`错误详情:`, error)
|
|
485
|
+
}
|
|
486
|
+
return false
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
|
|
209
491
|
/**
|
|
210
492
|
* 导入Maximo AutoKey配置
|
|
211
493
|
* @param {Object} options - 配置选项
|
|
@@ -236,7 +518,7 @@ export async function importMaxAutoKey({fileName, logname}) {
|
|
|
236
518
|
method: 'post',
|
|
237
519
|
params: {
|
|
238
520
|
develop: true,
|
|
239
|
-
_langcode:
|
|
521
|
+
_langcode: getConfig().langcode,
|
|
240
522
|
},
|
|
241
523
|
data: fileContent
|
|
242
524
|
})
|
|
@@ -245,6 +527,67 @@ export async function importMaxAutoKey({fileName, logname}) {
|
|
|
245
527
|
logger.info(`[${logname}]响应类型:`, typeof response);
|
|
246
528
|
logger.info(`[${logname}]响应内容:`, response);
|
|
247
529
|
|
|
530
|
+
if (response !== null && response !== undefined) {
|
|
531
|
+
logger.warn(`[${logname}]导入成功`)
|
|
532
|
+
return true
|
|
533
|
+
} else {
|
|
534
|
+
logger.error(`[${logname}]导入失败,响应为空或null`)
|
|
535
|
+
logger.error(`[${logname}]响应值:`, response)
|
|
536
|
+
return false
|
|
537
|
+
}
|
|
538
|
+
} catch (error) {
|
|
539
|
+
logger.error(`[${logname}]请求出错:`, error.message)
|
|
540
|
+
if (error.response) {
|
|
541
|
+
// 服务器返回了错误状态码
|
|
542
|
+
} else if (error.request) {
|
|
543
|
+
logger.error(`[${logname}]请求已发出但无响应`)
|
|
544
|
+
} else {
|
|
545
|
+
logger.error(`[${logname}]错误详情:`, error)
|
|
546
|
+
}
|
|
547
|
+
return false
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* 导入Maximo应用信息配置
|
|
554
|
+
* @param {Object} options - 配置选项
|
|
555
|
+
* @param {string} options.fileName - 配置文件名(JSON或XML)
|
|
556
|
+
* @param {string} options.logname - 日志打印名称
|
|
557
|
+
* @returns {Promise<boolean>} 是否导入成功
|
|
558
|
+
*/
|
|
559
|
+
export async function importMaxAppInfo({fileName, logname}) {
|
|
560
|
+
if(!logname||logname===""||logname===null){
|
|
561
|
+
logname = fileName
|
|
562
|
+
}
|
|
563
|
+
try {
|
|
564
|
+
let fileContent = null;
|
|
565
|
+
fileContent = readFileContent(fileName);
|
|
566
|
+
|
|
567
|
+
if (!fileContent) {
|
|
568
|
+
logger.error(`[${logname}]文件读取失败: ${fileName}`);
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
logger.info(`[${logname}]成功读取文件: ${fileName}`);
|
|
573
|
+
logger.info(`[${logname}]文件大小: ${fileContent.length} 字节`);
|
|
574
|
+
logger.info(`[${logname}]准备导入应用信息: ${logname || '未指定'}`);
|
|
575
|
+
|
|
576
|
+
logger.info(`[${logname}]开始发送请求...`);
|
|
577
|
+
const response = await request({
|
|
578
|
+
url: '/api/script/SKS_IMP_MAXAPPINFO',
|
|
579
|
+
method: 'post',
|
|
580
|
+
params: {
|
|
581
|
+
develop: true,
|
|
582
|
+
_langcode: getConfig().langcode,
|
|
583
|
+
},
|
|
584
|
+
data: fileContent
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
logger.info(`[${logname}]收到响应`);
|
|
588
|
+
logger.info(`[${logname}]响应类型:`, typeof response);
|
|
589
|
+
logger.debug(`[${logname}]响应内容:`, response);
|
|
590
|
+
|
|
248
591
|
if (response !== null && response !== undefined) {
|
|
249
592
|
logger.warn(`[${logname}]导入成功`)
|
|
250
593
|
return true
|
package/nodeutils/requestHttp.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import https from 'https';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
3
6
|
import axios from 'axios';
|
|
4
7
|
import { getConfig } from './config.js';
|
|
5
8
|
import logger from './logger.js';
|
|
@@ -24,6 +27,78 @@ function limitLogOutput(data, maxLength = 200) {
|
|
|
24
27
|
}
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
function getLogDir() {
|
|
31
|
+
return path.join(os.homedir(), '.sks', 'nodeutils', 'logs');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function saveRequestLog(config, globalConfig) {
|
|
35
|
+
try {
|
|
36
|
+
const logDir = getLogDir();
|
|
37
|
+
if (!fs.existsSync(logDir)) {
|
|
38
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const method = config.method?.toUpperCase() || 'GET';
|
|
42
|
+
let url = `${config.url}`;
|
|
43
|
+
|
|
44
|
+
if (config.params && Object.keys(config.params).length > 0) {
|
|
45
|
+
const paramsStr = Object.entries(config.params)
|
|
46
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
47
|
+
.join('&');
|
|
48
|
+
url += url.includes('?') ? `&${paramsStr}` : `?${paramsStr}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let httpContent = `### ${method} ${url}\n`;
|
|
52
|
+
httpContent += `${method} ${url}\n`;
|
|
53
|
+
|
|
54
|
+
const skipHeaders = ['user-agent', 'content-length', 'host', 'accept-encoding', 'connection'];
|
|
55
|
+
Object.entries(config.headers || {}).forEach(([key, value]) => {
|
|
56
|
+
const lowerKey = key.toLowerCase();
|
|
57
|
+
if (!skipHeaders.includes(lowerKey)) {
|
|
58
|
+
httpContent += `${key}: ${value}\n`;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
httpContent += '\n';
|
|
63
|
+
if (config.data) {
|
|
64
|
+
if (typeof config.data === 'string') {
|
|
65
|
+
httpContent += config.data;
|
|
66
|
+
} else {
|
|
67
|
+
httpContent += JSON.stringify(config.data, null, 2);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
72
|
+
const fileName = `request-${method}-${timestamp}.http`;
|
|
73
|
+
const filePath = path.join(logDir, fileName);
|
|
74
|
+
fs.writeFileSync(filePath, httpContent, 'utf-8');
|
|
75
|
+
|
|
76
|
+
logger.error(`[HTTP Log] 请求日志已保存: ${filePath}`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger.error('[HTTP Log] 保存请求日志失败:', error.message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function saveResponseLog(response) {
|
|
83
|
+
try {
|
|
84
|
+
const logDir = getLogDir();
|
|
85
|
+
if (!fs.existsSync(logDir)) {
|
|
86
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
90
|
+
const method = response.config.method?.toUpperCase() || 'GET';
|
|
91
|
+
const fileName = `response-${method}-${timestamp}.json`;
|
|
92
|
+
const filePath = path.join(logDir, fileName);
|
|
93
|
+
|
|
94
|
+
fs.writeFileSync(filePath, JSON.stringify(response.data, null, 2), 'utf-8');
|
|
95
|
+
|
|
96
|
+
logger.error(`[HTTP Log] 响应日志已保存: ${filePath}`);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
logger.error('[HTTP Log] 保存响应日志失败:', error.message);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
27
102
|
// 创建axios实例
|
|
28
103
|
function createService() {
|
|
29
104
|
const config = getConfig();
|
|
@@ -62,8 +137,8 @@ function createService() {
|
|
|
62
137
|
if (!config.params) {
|
|
63
138
|
config.params = {};
|
|
64
139
|
}
|
|
65
|
-
if (!
|
|
66
|
-
config.params['_langcode'] = 'zh';
|
|
140
|
+
if (!config.params['_langcode']) {
|
|
141
|
+
config.params['_langcode'] = globalConfig.langcode || 'zh';
|
|
67
142
|
}
|
|
68
143
|
var url = `${config.method} ${globalConfig.baseUrl}${config.url}`;
|
|
69
144
|
if (config.params && Object.keys(config.params).length > 0) {
|
|
@@ -89,6 +164,9 @@ function createService() {
|
|
|
89
164
|
}
|
|
90
165
|
logger.info(httpContent);
|
|
91
166
|
logger.info('[Request] 请求准备完成,发送请求...');
|
|
167
|
+
|
|
168
|
+
saveRequestLog(config, globalConfig);
|
|
169
|
+
|
|
92
170
|
return config;
|
|
93
171
|
}, error => {
|
|
94
172
|
logger.debug(error);
|
|
@@ -98,7 +176,9 @@ function createService() {
|
|
|
98
176
|
// 响应拦截器
|
|
99
177
|
service.interceptors.response.use(res => {
|
|
100
178
|
logger.info('[Response] 收到响应,状态码:', res.status);
|
|
101
|
-
logger.
|
|
179
|
+
logger.debug('[Response] 响应数据:', res.data);
|
|
180
|
+
|
|
181
|
+
saveResponseLog(res);
|
|
102
182
|
|
|
103
183
|
// 未设置状态码则默认成功状态
|
|
104
184
|
const code = res.data?.code || res.status || 200;
|