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 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';
@@ -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
  }
@@ -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: 'zh',
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: 'zh',
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: 'zh',
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: 'zh',
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
@@ -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 (!(config.url.concat('_langcode') || config.params['_langcode'])) {
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.info('[Response] 响应数据:', res.data);
179
+ logger.debug('[Response] 响应数据:', res.data);
180
+
181
+ saveResponseLog(res);
102
182
 
103
183
  // 未设置状态码则默认成功状态
104
184
  const code = res.data?.code || res.status || 200;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sks-maximo-utils",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Maximo helper tools for updating table structures and data",
5
5
  "type": "module",
6
6
  "main": "index.js",