neo-cmp-cli 1.7.5-beta.1 → 1.7.5-beta.2
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/package.json +1 -1
- package/src/config/auth.config.js +7 -5
- package/src/module/index.js +21 -21
- package/src/module/main.js +6 -5
- package/src/module/neoInitByCopy.js +4 -3
- package/src/neo/neoLogin.js +79 -24
- package/src/neo/neoService.js +15 -8
package/package.json
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
const curConfig = require('../config/index'); // 获取当前项目根目录下的配置文件
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const neoConfig = curConfig.neoConfig || {};
|
|
4
|
+
const authConfig = neoConfig.auth || {};
|
|
4
5
|
|
|
5
6
|
// NeoCRM 跨 Pod 授权配置
|
|
6
7
|
module.exports = {
|
|
7
|
-
loginURL:
|
|
8
|
-
tokenAPI:
|
|
8
|
+
loginURL: neoConfig.loginURL || 'https://login-cd.xiaoshouyi.com/auc/oauth2/auth', // 登录 URL,从创建连接器的客户端信息中获取(Login_Url)
|
|
9
|
+
tokenAPI: neoConfig.tokenAPI || 'https://login-cd.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址(默认:https://login.xiaoshouyi.com/auc/oauth2/token)
|
|
10
|
+
redirectUri: neoConfig.redirectUri || 'http://localhost:1028', // 固定端口号,用于接收授权码
|
|
9
11
|
// 重定向 URI,动态生成
|
|
10
12
|
getRedirectURI: (port) => {
|
|
11
13
|
return `http://localhost:${port}`;
|
|
12
14
|
},
|
|
13
15
|
// 获取 授权码 相关配置
|
|
14
16
|
response_type: 'code', // 认证类型;此参数值必须为 code
|
|
15
|
-
client_id: '04c8b45c4dbe36426a660bf70d3fe3e7', // 客户端 ID,跨 Pod 级链接器【内置】
|
|
17
|
+
client_id: authConfig.client_id || '04c8b45c4dbe36426a660bf70d3fe3e7', // 客户端 ID,跨 Pod 级链接器【内置】
|
|
16
18
|
scope: 'all', // 固定值:all
|
|
17
19
|
oauthType: 'standard', // 固定值:standard
|
|
18
20
|
access_type: 'offline', // 此参数值为 online 时,不产生 refresh_token ;此参数值为 offline 时,返回refresh_token
|
|
19
21
|
|
|
20
22
|
// 获取 令牌 相关配置
|
|
21
|
-
client_secret: '370817d1336a3737f95c671eea39a23b', // 客户端秘钥,跨 Pod 级链接器【内置】
|
|
23
|
+
client_secret: authConfig.client_secret || '370817d1336a3737f95c671eea39a23b', // 客户端秘钥,跨 Pod 级链接器【内置】
|
|
22
24
|
grant_type: 'authorization_code' // 授权类型;此参数值必须为 authorization_code
|
|
23
25
|
};
|
package/src/module/index.js
CHANGED
|
@@ -12,10 +12,10 @@ const mainAction = require('./main.js'); // 入口文件
|
|
|
12
12
|
const getCmpTypeByDir = require('../utils/cmpUtils/getCmpTypeByDir.js');
|
|
13
13
|
const NeoService = require('../neo/neoService.js');
|
|
14
14
|
const NeoLoginService = require('../neo/neoLogin.js');
|
|
15
|
-
const authConfig = require('../config/auth.config.js');
|
|
16
15
|
const curConfig = require('../config/index'); // 获取当前项目根目录下的配置文件
|
|
17
16
|
const hasNeoProject = require('../utils/projectUtils/hasNeoProject.js');
|
|
18
17
|
const consoleTag = require('../utils/neoParams').consoleTag;
|
|
18
|
+
const { errorLog, successLog } = require('../utils/common');
|
|
19
19
|
// neo 的 package 文件
|
|
20
20
|
const neoPackage = require('../../package.json');
|
|
21
21
|
|
|
@@ -59,7 +59,7 @@ yargs
|
|
|
59
59
|
(argv) => {
|
|
60
60
|
if (argv.type && argv.name) {
|
|
61
61
|
if (hasNeoProject()) {
|
|
62
|
-
|
|
62
|
+
errorLog(
|
|
63
63
|
`${consoleTag}创建自定义组件失败,当前目录(${process.cwd()})已经是一个自定义组件项目,请勿重复创建。`
|
|
64
64
|
);
|
|
65
65
|
process.exit(1);
|
|
@@ -137,7 +137,7 @@ yargs
|
|
|
137
137
|
// 验证项目名称是否合法
|
|
138
138
|
const { isValid, errors } = validateProjectName(ans.name);
|
|
139
139
|
if (!isValid) {
|
|
140
|
-
|
|
140
|
+
errorLog(errors.join('\n'));
|
|
141
141
|
process.exit(1);
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -174,10 +174,10 @@ yargs
|
|
|
174
174
|
},
|
|
175
175
|
async () => {
|
|
176
176
|
try {
|
|
177
|
-
const loginService = new NeoLoginService(
|
|
177
|
+
const loginService = new NeoLoginService(curConfig.neoConfig);
|
|
178
178
|
await loginService.login();
|
|
179
179
|
} catch (error) {
|
|
180
|
-
|
|
180
|
+
errorLog(`\n登录失败: ${error.message}`);
|
|
181
181
|
process.exit(1);
|
|
182
182
|
}
|
|
183
183
|
}
|
|
@@ -193,10 +193,10 @@ yargs
|
|
|
193
193
|
},
|
|
194
194
|
async () => {
|
|
195
195
|
try {
|
|
196
|
-
const loginService = new NeoLoginService(
|
|
196
|
+
const loginService = new NeoLoginService(curConfig.neoConfig);
|
|
197
197
|
await loginService.logout();
|
|
198
198
|
} catch (error) {
|
|
199
|
-
|
|
199
|
+
errorLog(`\n登出失败: ${error.message}`);
|
|
200
200
|
process.exit(1);
|
|
201
201
|
}
|
|
202
202
|
}
|
|
@@ -232,12 +232,12 @@ yargs
|
|
|
232
232
|
// 验证项目名称是否合法
|
|
233
233
|
const { isValid, errors } = validateProjectName(ans.name);
|
|
234
234
|
if (!isValid) {
|
|
235
|
-
|
|
235
|
+
errorLog(errors.join('\n'));
|
|
236
236
|
process.exit(1);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
if (!ans.name) {
|
|
240
|
-
|
|
240
|
+
errorLog('自定义组件项目名称不能为空。');
|
|
241
241
|
process.exit(1);
|
|
242
242
|
} else {
|
|
243
243
|
mainAction.createCmpProjectByTemplate(ans.name);
|
|
@@ -273,7 +273,7 @@ yargs
|
|
|
273
273
|
|
|
274
274
|
inquirer.prompt(questions).then((ans) => {
|
|
275
275
|
if (!ans.name) {
|
|
276
|
-
|
|
276
|
+
errorLog('自定义组件名称不能为空。');
|
|
277
277
|
process.exit(1);
|
|
278
278
|
} else {
|
|
279
279
|
mainAction.createCmpByTemplate(ans.name);
|
|
@@ -305,7 +305,7 @@ yargs
|
|
|
305
305
|
const spinner = ora('正在拉取线上自定义组件列表...').start();
|
|
306
306
|
const cmpList = await neoService.getCustomCmpList();
|
|
307
307
|
if (cmpList.length === 0) {
|
|
308
|
-
|
|
308
|
+
errorLog('当前租户暂无任何自定义组件。');
|
|
309
309
|
process.exit(1);
|
|
310
310
|
}
|
|
311
311
|
spinner.stop('线上自定义组件列表拉取成功。');
|
|
@@ -323,7 +323,7 @@ yargs
|
|
|
323
323
|
];
|
|
324
324
|
inquirer.prompt(questions).then((ans) => {
|
|
325
325
|
if (!ans.cmpType) {
|
|
326
|
-
|
|
326
|
+
errorLog('自定义组件名称不能为空。');
|
|
327
327
|
process.exit(1);
|
|
328
328
|
} else {
|
|
329
329
|
mainAction.pullCmp(ans.cmpType, neoService);
|
|
@@ -354,7 +354,7 @@ yargs
|
|
|
354
354
|
const spinner = ora('正在获取线上自定义组件列表...').start();
|
|
355
355
|
const cmpList = await neoService.getCustomCmpList();
|
|
356
356
|
if (cmpList.length === 0) {
|
|
357
|
-
|
|
357
|
+
errorLog('当前租户暂无任何自定义组件。');
|
|
358
358
|
process.exit(1);
|
|
359
359
|
}
|
|
360
360
|
spinner.stop('线上自定义组件列表获取成功。');
|
|
@@ -372,7 +372,7 @@ yargs
|
|
|
372
372
|
];
|
|
373
373
|
inquirer.prompt(questions).then((ans) => {
|
|
374
374
|
if (!ans.cmpType) {
|
|
375
|
-
|
|
375
|
+
errorLog('自定义组件名称不能为空。');
|
|
376
376
|
process.exit(1);
|
|
377
377
|
} else {
|
|
378
378
|
mainAction.deleteCmp(ans.cmpType, neoService);
|
|
@@ -400,7 +400,7 @@ yargs
|
|
|
400
400
|
} else {
|
|
401
401
|
const cmpTypes = getCmpTypeByDir();
|
|
402
402
|
if (cmpTypes.length === 0) {
|
|
403
|
-
|
|
403
|
+
errorLog('当前自定义组件目录中未找到自定义组件。(./src/components 目录下)');
|
|
404
404
|
process.exit(1);
|
|
405
405
|
}
|
|
406
406
|
const cmpTypeChoices = cmpTypes.map((cmpType) => ({
|
|
@@ -417,7 +417,7 @@ yargs
|
|
|
417
417
|
];
|
|
418
418
|
inquirer.prompt(questions).then((ans) => {
|
|
419
419
|
if (!ans.cmpType) {
|
|
420
|
-
|
|
420
|
+
errorLog('未选择要预览的自定义组件。');
|
|
421
421
|
process.exit(1);
|
|
422
422
|
}
|
|
423
423
|
mainAction.previewCmp(ans.cmpType);
|
|
@@ -496,7 +496,7 @@ yargs
|
|
|
496
496
|
} else {
|
|
497
497
|
const cmpTypes = getCmpTypeByDir();
|
|
498
498
|
if (cmpTypes.length === 0) {
|
|
499
|
-
|
|
499
|
+
errorLog('当前自定义组件目录中未找到自定义组件。(./src/components 目录下)');
|
|
500
500
|
process.exit(1);
|
|
501
501
|
}
|
|
502
502
|
const cmpTypeChoices = cmpTypes.map((cmpType) => ({
|
|
@@ -513,7 +513,7 @@ yargs
|
|
|
513
513
|
];
|
|
514
514
|
inquirer.prompt(questions).then((ans) => {
|
|
515
515
|
if (!ans.cmpType) {
|
|
516
|
-
|
|
516
|
+
errorLog('未选择要发布的自定义组件。');
|
|
517
517
|
process.exit(1);
|
|
518
518
|
}
|
|
519
519
|
mainAction.publish2oss(ans.cmpType);
|
|
@@ -540,7 +540,7 @@ yargs
|
|
|
540
540
|
} else {
|
|
541
541
|
const cmpTypes = getCmpTypeByDir();
|
|
542
542
|
if (cmpTypes.length === 0) {
|
|
543
|
-
|
|
543
|
+
errorLog('当前自定义组件目录中未找到自定义组件。(./src/components 目录下)');
|
|
544
544
|
process.exit(1);
|
|
545
545
|
}
|
|
546
546
|
const cmpTypeChoices = cmpTypes.map((cmpType) => ({
|
|
@@ -557,7 +557,7 @@ yargs
|
|
|
557
557
|
];
|
|
558
558
|
inquirer.prompt(questions).then((ans) => {
|
|
559
559
|
if (!ans.cmpType) {
|
|
560
|
-
|
|
560
|
+
errorLog('未选择要发布的自定义组件。');
|
|
561
561
|
process.exit(1);
|
|
562
562
|
}
|
|
563
563
|
mainAction.pushCmp(ans.cmpType);
|
|
@@ -628,7 +628,7 @@ yargs
|
|
|
628
628
|
.alias('v', 'version')
|
|
629
629
|
.strict()
|
|
630
630
|
.fail((msg, err, yargs) => {
|
|
631
|
-
|
|
631
|
+
errorLog(`\n运行命令时发生错误: ${msg}。\n`);
|
|
632
632
|
console.log(titleTip('当前可用命令列表:'));
|
|
633
633
|
console.log('');
|
|
634
634
|
// 定义所有可用命令及其描述
|
package/src/module/main.js
CHANGED
|
@@ -19,6 +19,7 @@ const createCmpProjectByTemplate = require('../utils/projectUtils/createCmpProje
|
|
|
19
19
|
const pullCmp = require('../utils/cmpUtils/pullCmp');
|
|
20
20
|
const deleteCmp = require('../utils/cmpUtils/deleteCmp');
|
|
21
21
|
const openProject = require('../utils/projectUtils/openProject');
|
|
22
|
+
const { errorLog, successLog } = require('../utils/common');
|
|
22
23
|
|
|
23
24
|
const getValue = (originValue, defaultValue) => {
|
|
24
25
|
return originValue !== undefined ? originValue : defaultValue;
|
|
@@ -109,7 +110,7 @@ function setupEntries(config, options) {
|
|
|
109
110
|
console.info('已自动生成 entry 入口配置:', entries);
|
|
110
111
|
}
|
|
111
112
|
} catch (error) {
|
|
112
|
-
|
|
113
|
+
errorLog(error.message);
|
|
113
114
|
process.exit(1);
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -155,7 +156,7 @@ module.exports = {
|
|
|
155
156
|
createCmpByTemplate,
|
|
156
157
|
dev: () => {
|
|
157
158
|
if (!curConfig.dev) {
|
|
158
|
-
|
|
159
|
+
errorLog('未找到 dev 相关配置。');
|
|
159
160
|
process.exit(1);
|
|
160
161
|
}
|
|
161
162
|
akfun.dev(curConfig, consoleTag);
|
|
@@ -163,11 +164,11 @@ module.exports = {
|
|
|
163
164
|
previewCmp: (cmpName) => {
|
|
164
165
|
// 预览组件本身内容
|
|
165
166
|
if (!cmpName) {
|
|
166
|
-
|
|
167
|
+
errorLog('请输入要预览的组件名称。');
|
|
167
168
|
process.exit(1);
|
|
168
169
|
}
|
|
169
170
|
if (!curConfig.preview) {
|
|
170
|
-
|
|
171
|
+
errorLog('未找到 preview 相关配置。');
|
|
171
172
|
process.exit(1);
|
|
172
173
|
}
|
|
173
174
|
curConfig.dev = Object.assign(curConfig.dev, curConfig.preview); // 将 preview 设置给 dev
|
|
@@ -178,7 +179,7 @@ module.exports = {
|
|
|
178
179
|
linkDebug: () => {
|
|
179
180
|
// 外链调试模式
|
|
180
181
|
if (!curConfig.linkDebug) {
|
|
181
|
-
|
|
182
|
+
errorLog('未找到 debug 相关配置。');
|
|
182
183
|
process.exit(1);
|
|
183
184
|
}
|
|
184
185
|
// 将 linkDebug 设置给 dev
|
|
@@ -4,6 +4,7 @@ const { consoleTag } = require('../utils/neoParams'); // 输出标记
|
|
|
4
4
|
const { replaceInPackage } = require('../utils/replaceInPackage');
|
|
5
5
|
const { resetPackageVersion } = require('../utils/resetPackageVersion');
|
|
6
6
|
const autoEntryRootDir = require('../utils/autoEntryRootDir');
|
|
7
|
+
const { errorLog } = require('../utils/common');
|
|
7
8
|
|
|
8
9
|
const templateList = {
|
|
9
10
|
react: {
|
|
@@ -14,7 +15,7 @@ const templateList = {
|
|
|
14
15
|
projectName: 'react-ts-custom-cmp-template',
|
|
15
16
|
dir: path.resolve(__dirname, '../template/react-ts-custom-cmp-template')
|
|
16
17
|
},
|
|
17
|
-
|
|
18
|
+
antd: {
|
|
18
19
|
projectName: 'antd-custom-cmp-template',
|
|
19
20
|
dir: path.resolve(__dirname, '../template/antd-custom-cmp-template')
|
|
20
21
|
},
|
|
@@ -22,7 +23,7 @@ const templateList = {
|
|
|
22
23
|
projectName: 'echarts-custom-cmp-template',
|
|
23
24
|
dir: path.resolve(__dirname, '../template/echarts-custom-cmp-template')
|
|
24
25
|
},
|
|
25
|
-
|
|
26
|
+
neo: {
|
|
26
27
|
projectName: 'neo-custom-cmp-template',
|
|
27
28
|
dir: path.resolve(__dirname, '../template/neo-custom-cmp-template')
|
|
28
29
|
},
|
|
@@ -54,7 +55,7 @@ const neoInitByCopy = function (type, projectName) {
|
|
|
54
55
|
// 自动切换到项目根目录
|
|
55
56
|
autoEntryRootDir(finalProjectPath);
|
|
56
57
|
})
|
|
57
|
-
.catch((err) =>
|
|
58
|
+
.catch((err) => errorLog(`${consoleTag}自定义组件模板下载失败:`, err));
|
|
58
59
|
};
|
|
59
60
|
|
|
60
61
|
module.exports = neoInitByCopy;
|
package/src/neo/neoLogin.js
CHANGED
|
@@ -5,6 +5,7 @@ const ora = require('ora');
|
|
|
5
5
|
const http = require('http');
|
|
6
6
|
const url = require('url');
|
|
7
7
|
const open = require('open');
|
|
8
|
+
const net = require('net');
|
|
8
9
|
const portfinder = require('portfinder');
|
|
9
10
|
const { errorLog, successLog } = require('../utils/common');
|
|
10
11
|
const neoAuthConfig = require('../config/auth.config');
|
|
@@ -119,7 +120,7 @@ class NeoLoginService {
|
|
|
119
120
|
* @returns {string} 回调地址
|
|
120
121
|
*/
|
|
121
122
|
getRedirectURI(port) {
|
|
122
|
-
return `http://localhost:${port}
|
|
123
|
+
return `http://localhost:${port}`;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
/**
|
|
@@ -153,20 +154,71 @@ class NeoLoginService {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
/**
|
|
158
|
+
* 检测端口是否被占用
|
|
159
|
+
* @param {number} port 端口号
|
|
160
|
+
* @returns {Promise<boolean>} true 表示端口被占用,false 表示端口可用
|
|
161
|
+
*/
|
|
162
|
+
async isPortInUse(port) {
|
|
163
|
+
return new Promise((resolve) => {
|
|
164
|
+
const server = net.createServer();
|
|
165
|
+
|
|
166
|
+
server.once('error', (err) => {
|
|
167
|
+
if (err.code === 'EADDRINUSE') {
|
|
168
|
+
resolve(true); // 端口被占用
|
|
169
|
+
} else {
|
|
170
|
+
resolve(false); // 其他错误,假设端口可用
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
server.once('listening', () => {
|
|
175
|
+
// 端口可用,立即关闭服务器
|
|
176
|
+
server.once('close', () => {
|
|
177
|
+
resolve(false); // 端口可用
|
|
178
|
+
});
|
|
179
|
+
server.close();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
server.listen(port);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
156
186
|
/**
|
|
157
187
|
* 启动本地服务器接收授权码(code)
|
|
158
188
|
* @returns {Promise<{redirectUri: string, codePromise: Promise<string>}>} 回调地址和授权码Promise
|
|
159
189
|
*/
|
|
160
190
|
async startCallbackServer() {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
stopPort: 9999 // 结束端口
|
|
165
|
-
});
|
|
191
|
+
let redirectUri = neoAuthConfig.redirectUri;
|
|
192
|
+
let redirectUrl = new URL(redirectUri);
|
|
193
|
+
let port = parseInt(redirectUrl.port, 10);
|
|
166
194
|
|
|
167
|
-
//
|
|
168
|
-
const
|
|
169
|
-
|
|
195
|
+
// 检测端口是否被占用
|
|
196
|
+
const portInUse = await this.isPortInUse(port);
|
|
197
|
+
|
|
198
|
+
if (portInUse) {
|
|
199
|
+
consoleError(
|
|
200
|
+
`\n警告: 端口 ${port} 已被占用,请调整 redirectUri 配置项,使其指向一个未被占用的端口。`
|
|
201
|
+
);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
/*
|
|
204
|
+
// 使用 portfinder 查找可用端口
|
|
205
|
+
try {
|
|
206
|
+
port = await portfinder.getPortPromise({
|
|
207
|
+
port: port, // 从配置的端口开始查找
|
|
208
|
+
stopPort: 9999 // 结束端口
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// 更新 redirectUri 和 redirectUrl
|
|
212
|
+
redirectUri = this.getRedirectURI(port);
|
|
213
|
+
redirectUrl = new URL(redirectUri);
|
|
214
|
+
console.log(`已找到可用端口: ${port}`);
|
|
215
|
+
console.log(`回调地址已更新为: ${redirectUri}`);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
errorLog(`无法找到可用端口: ${error.message}`);
|
|
218
|
+
throw new Error(`端口 ${port} 已被占用,且无法找到可用端口`);
|
|
219
|
+
}
|
|
220
|
+
*/
|
|
221
|
+
}
|
|
170
222
|
|
|
171
223
|
const codePromise = new Promise((resolve, reject) => {
|
|
172
224
|
const server = http.createServer((req, res) => {
|
|
@@ -200,9 +252,8 @@ class NeoLoginService {
|
|
|
200
252
|
<head><title>授权成功</title></head>
|
|
201
253
|
<body>
|
|
202
254
|
<h1>授权成功!</h1>
|
|
203
|
-
<p
|
|
255
|
+
<p>已获取授权码</p>
|
|
204
256
|
<p>您可以关闭此窗口</p>
|
|
205
|
-
<script>window.close();</script>
|
|
206
257
|
</body>
|
|
207
258
|
</html>
|
|
208
259
|
`);
|
|
@@ -302,7 +353,7 @@ class NeoLoginService {
|
|
|
302
353
|
* @returns {Promise<object>} 新的 Token 数据
|
|
303
354
|
*/
|
|
304
355
|
async refreshToken(refreshToken) {
|
|
305
|
-
const spinner = ora('
|
|
356
|
+
const spinner = ora('正在刷新授权信息(token)...').start();
|
|
306
357
|
|
|
307
358
|
try {
|
|
308
359
|
const formData = new URLSearchParams();
|
|
@@ -320,16 +371,16 @@ class NeoLoginService {
|
|
|
320
371
|
const tokenData = response.data;
|
|
321
372
|
|
|
322
373
|
if (!tokenData || !tokenData.access_token) {
|
|
323
|
-
errorLog('
|
|
374
|
+
errorLog('刷新授权信息失败:响应中未包含 access_token', spinner);
|
|
324
375
|
errorLog(`响应数据: ${JSON.stringify(tokenData)}`);
|
|
325
376
|
return null;
|
|
326
377
|
}
|
|
327
378
|
|
|
328
|
-
successLog('
|
|
379
|
+
successLog('刷新授权信息成功(token)。', spinner);
|
|
329
380
|
return tokenData;
|
|
330
381
|
} catch (error) {
|
|
331
|
-
errorLog('
|
|
332
|
-
errorLog(`\n
|
|
382
|
+
errorLog('刷新授权信息失败', spinner);
|
|
383
|
+
errorLog(`\n刷新授权信息失败: ${error.message}`);
|
|
333
384
|
if (error.response) {
|
|
334
385
|
errorLog(`响应数据: ${JSON.stringify(error.response.data)}`);
|
|
335
386
|
}
|
|
@@ -366,11 +417,15 @@ class NeoLoginService {
|
|
|
366
417
|
this.saveToken(tokenData);
|
|
367
418
|
|
|
368
419
|
console.log('\n========== 登录成功 ==========\n');
|
|
369
|
-
console.log(
|
|
420
|
+
console.log(`已缓存授权信息到: ${this.tokenFile}`);
|
|
370
421
|
console.log(`实例地址: ${tokenData.instance_uri || '未返回'}`);
|
|
371
422
|
console.log(`租户 ID: ${tokenData.tenant_id || '未返回'}`);
|
|
372
|
-
console.log(
|
|
373
|
-
console.log(
|
|
423
|
+
console.log(`授权信息有效期(access_token): ${tokenData.expires_in || 7200} 秒`);
|
|
424
|
+
console.log(
|
|
425
|
+
`自动刷新授权信息有效期(refresh_token): ${
|
|
426
|
+
tokenData.refresh_token_expires_in || 2592000
|
|
427
|
+
} 秒`
|
|
428
|
+
);
|
|
374
429
|
console.log('');
|
|
375
430
|
|
|
376
431
|
return tokenData;
|
|
@@ -393,7 +448,7 @@ class NeoLoginService {
|
|
|
393
448
|
|
|
394
449
|
try {
|
|
395
450
|
this.clearToken();
|
|
396
|
-
successLog(
|
|
451
|
+
successLog(`已清除授权信息,下次登录需要重新授权。`);
|
|
397
452
|
console.log('\n登出成功!\n');
|
|
398
453
|
} catch (error) {
|
|
399
454
|
errorLog(`登出失败: ${error.message}`);
|
|
@@ -409,16 +464,16 @@ class NeoLoginService {
|
|
|
409
464
|
const tokenData = this.readToken();
|
|
410
465
|
|
|
411
466
|
if (!tokenData) {
|
|
412
|
-
errorLog('
|
|
467
|
+
errorLog('未找到授权信息,请先执行 neo login 进行登录。');
|
|
413
468
|
process.exit(1);
|
|
414
469
|
}
|
|
415
470
|
|
|
416
471
|
// 检查 token 是否过期
|
|
417
472
|
if (this.isTokenExpired(tokenData)) {
|
|
418
|
-
console.log('
|
|
473
|
+
console.log('授权信息已过期,正在尝试刷新...');
|
|
419
474
|
|
|
420
475
|
if (!tokenData.refresh_token) {
|
|
421
|
-
errorLog('
|
|
476
|
+
errorLog('自动刷新授权信息失败,请重新登录(neo login)。');
|
|
422
477
|
process.exit(1);
|
|
423
478
|
}
|
|
424
479
|
|
|
@@ -426,7 +481,7 @@ class NeoLoginService {
|
|
|
426
481
|
const newTokenData = await this.refreshToken(tokenData.refresh_token);
|
|
427
482
|
|
|
428
483
|
if (!newTokenData) {
|
|
429
|
-
errorLog('
|
|
484
|
+
errorLog('刷新授权信息失败,请重新登录 (neo login)');
|
|
430
485
|
process.exit(1);
|
|
431
486
|
}
|
|
432
487
|
|
package/src/neo/neoService.js
CHANGED
|
@@ -66,25 +66,29 @@ class NeoService {
|
|
|
66
66
|
// 设置授权类型,默认为 oauth2
|
|
67
67
|
this.authType = authType || 'oauth2';
|
|
68
68
|
|
|
69
|
-
if (!auth) {
|
|
70
|
-
|
|
69
|
+
if (this.authType === 'password' && !auth) {
|
|
70
|
+
errorLog('密码授权模式时,neo.config.js / neoConfig / auth 配置不能为空');
|
|
71
|
+
process.exit(1);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
// 根据授权类型验证必需的配置项
|
|
74
75
|
if (this.authType === 'password') {
|
|
75
76
|
if (!auth.client_id || !auth.client_secret || !auth.username || !auth.password) {
|
|
76
|
-
|
|
77
|
+
errorLog(
|
|
77
78
|
'neo.config.js / neoConfig / auth 配置不完整(password 模式),需要包含 client_id、client_secret、username、password'
|
|
78
79
|
);
|
|
80
|
+
process.exit(1);
|
|
79
81
|
}
|
|
80
82
|
} else if (this.authType === 'oauth2') {
|
|
81
83
|
if (!loginURL || !tokenAPI) {
|
|
82
|
-
|
|
84
|
+
errorLog(
|
|
83
85
|
'neo.config.js / neoConfig 配置不完整(oauth2 模式),需要包含 loginURL、tokenAPI 配置。'
|
|
84
86
|
);
|
|
87
|
+
process.exit(1);
|
|
85
88
|
}
|
|
86
89
|
} else {
|
|
87
|
-
|
|
90
|
+
errorLog(`不支持的授权类型: ${this.authType},可选值:oauth2、password`);
|
|
91
|
+
process.exit(1);
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
this.assetsRoot = assetsRoot || resolve('dist');
|
|
@@ -594,7 +598,8 @@ class NeoService {
|
|
|
594
598
|
const { code, message } = response.data || {};
|
|
595
599
|
|
|
596
600
|
if (code && code !== 200) {
|
|
597
|
-
|
|
601
|
+
errorLog(`获取自定义组件列表失败: ${message || '未知错误'}`);
|
|
602
|
+
process.exit(1);
|
|
598
603
|
}
|
|
599
604
|
|
|
600
605
|
this.updateCustomCmpList(response.data.data || []);
|
|
@@ -620,7 +625,8 @@ class NeoService {
|
|
|
620
625
|
const token = await this.ensureValidToken();
|
|
621
626
|
|
|
622
627
|
if (!cmpType) {
|
|
623
|
-
|
|
628
|
+
errorLog('自定义组件名称不能为空。');
|
|
629
|
+
process.exit(1);
|
|
624
630
|
}
|
|
625
631
|
|
|
626
632
|
let fullDeleteAPI = this.buildFullUrl(NeoCrmAPI.delete);
|
|
@@ -636,7 +642,8 @@ class NeoService {
|
|
|
636
642
|
const { code, message } = response.data || {};
|
|
637
643
|
|
|
638
644
|
if (code && code !== 200) {
|
|
639
|
-
|
|
645
|
+
errorLog(`删除自定义组件失败: ${message || '未知错误'}`);
|
|
646
|
+
process.exit(1);
|
|
640
647
|
}
|
|
641
648
|
|
|
642
649
|
return response.data;
|