neo-cmp-cli 1.5.6 → 1.6.0-beta.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.
Files changed (28) hide show
  1. package/README.md +62 -47
  2. package/package.json +1 -1
  3. package/src/cmpUtils/createCmpByTemplate.js +2 -2
  4. package/src/cmpUtils/createCmpByZip.js +87 -0
  5. package/src/cmpUtils/pullCmp.js +96 -0
  6. package/src/cmpUtils/pushCmp.js +76 -67
  7. package/src/module/index.js +54 -5
  8. package/src/module/main.js +7 -1
  9. package/src/neo/NeoUMDContent.js +1 -0
  10. package/src/neo/neoService.js +148 -40
  11. package/src/projectUtils/createCmpProjectZip.js +18 -18
  12. package/src/projectUtils/hasNeoProject.js +2 -2
  13. package/src/template/antd-custom-cmp-template/neo.config.js +7 -4
  14. package/src/template/antd-custom-cmp-template/package.json +1 -0
  15. package/src/template/echarts-custom-cmp-template/neo.config.js +7 -4
  16. package/src/template/echarts-custom-cmp-template/package.json +1 -0
  17. package/src/template/empty-custom-cmp-template/neo.config.js +7 -4
  18. package/src/template/empty-custom-cmp-template/package.json +1 -0
  19. package/src/template/neo-custom-cmp-template/neo.config.js +12 -9
  20. package/src/template/neo-custom-cmp-template/package.json +2 -1
  21. package/src/template/neo-custom-cmp-template/pushCmp.js +166 -0
  22. package/src/template/react-custom-cmp-template/neo.config.js +7 -4
  23. package/src/template/react-custom-cmp-template/package.json +1 -0
  24. package/src/template/react-ts-custom-cmp-template/neo.config.js +7 -4
  25. package/src/template/react-ts-custom-cmp-template/package.json +1 -0
  26. package/src/template/vue2-custom-cmp-template/neo.config.js +7 -4
  27. package/src/template/vue2-custom-cmp-template/package.json +1 -0
  28. package/src/utils/common.js +48 -0
package/README.md CHANGED
@@ -21,72 +21,82 @@ neo-cmp-cli 是 Neo 自定义组件开发工具,基于 [AKFun](https://github.
21
21
 
22
22
  ## 快速开始
23
23
 
24
- ### 方法一:全局安装自定义组件开发工具
25
- ##### 1) 全局安装
24
+ #### 1) 全局安装自定义组件开发工具
26
25
  ```bash
27
26
  yarn global add neo-cmp-cli
28
27
  # 或
29
28
  npm i -g neo-cmp-cli
30
29
  ```
31
- ##### 2) 创建自定义组件(默认 React+TS,可用 -t 指定模板,-n 指定自定义组件名称)
32
- ```bash
33
- neo init -t=react-ts
34
- ```
35
- ##### 3) 进入自定义组件项目根目录,安装依赖并运行
30
+
31
+ #### 2) 创建自定义组件项目
36
32
  ```bash
37
- # 创建自定义组件项目
33
+ # 方式一:创建空的自定义组件项目
38
34
  neo createProject
39
35
 
40
- # 也可以根据模板创建自定义组件项目
36
+ # 方式二:根据模板创建自定义组件项目(默认 React+TS,可用 -t 指定模板,-n 指定自定义组件名称)
41
37
  neo init
38
+ ```
39
+
40
+ #### 3) 进入自定义组件项目根目录,安装依赖并运行
41
+ ```bash
42
+ cd xxCmpProject
43
+ ```
42
44
 
45
+ #### 4) 创建自定义组件
46
+ ```bash
43
47
  # 在当前项目中创建一个自定义组件
44
48
  neo createCmp
49
+ ```
50
+ 默认在当前项目 src/components/ 目录下新增自定义组件。
45
51
 
52
+ #### 5) 本地预览自定义组件内容
53
+ ```bash
46
54
  # 预览自定义组件内容
47
55
  neo preview
48
-
49
- # 外链调试(在平台线上预览与调试)
50
- neo linkDebug
51
-
52
- # 构建并发布到 NeoCRM(需自行添加授权配置,并确保 package.json 的 name 唯一、version 不重复)
53
- neo pushCmp
54
56
  ```
57
+ 执行成功后,默认自动打开本地浏览器预览自定义组件内容。
55
58
 
56
- ### 方法二:在现有业务项目中使用自定义组件开发工具
57
- 此方式可用于将现有业务组件发布成平台可用自定义组件。
58
-
59
- ##### 1) 安装到当前项目,并添加开发依赖
60
- 使用以下安装命令时会自动将 neo-cmp-cli 添加成当前项目开发依赖
59
+ #### 6) 外链调试(在 NeoCRM 端预览与调试)
61
60
  ```bash
62
- yarn add neo-cmp-cli --dev
63
- # 或
64
- npm i neo-cmp-cli --save-dev
65
- ```
66
- ##### 2) 在 package.json 添加可用执行脚本
67
- ```bash
68
- "preview": "neo preview",
69
- "linkDebug": "neo linkDebug",
70
- "pushCmp": "neo pushCmp"
61
+ neo linkDebug
71
62
  ```
72
- ##### 3) 初始化配置文件
63
+ 需在NeoCRM / 页面设计器端启动 debug 模式,并添加控制台输出的外链脚本地址,方可在页面设计器端使用当前自定义组件。
64
+
65
+ #### 7) 构建并发布到 NeoCRM
73
66
  ```bash
74
- neo config init
67
+ neo pushCmp
75
68
  ```
76
- ##### 4) 开发调试和发布
77
- ```bash
78
- npm run preview
79
- npm run linkDebug
80
- npm run pushCmp
69
+ ##### 需自行添加授权配置,并确保 package.json 的 name 唯一、version 不重复。
70
+ ```javascript
71
+ module.exports = {
72
+ neoConfig: {
73
+ neoBaseURL: 'https://crm-cd.xiaoshouyi.com', // 平台根地址(默认:https://crm.xiaoshouyi.com)
74
+ tokenAPI: 'https://login-cd.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址(默认:https://login.xiaoshouyi.com/auc/oauth2/token)
75
+ // NeoCRM 授权配置
76
+ auth: {
77
+ client_id: 'xx', // 客户端 ID,从创建连接器的客户端信息中获取(Client_Id)
78
+ client_secret: 'xxx', // 客户端秘钥,从创建连接器的客户端信息中获取(Client_Secret)
79
+ username: 'xx', // 用户在销售易系统中的用户名
80
+ /**
81
+ * password 为 用户在销售易系统中的账号密码加上 8 位安全令牌。
82
+ * 例如,用户密码为 123456,安全令牌为 ABCDEFGH,则 password 的值应为 123456ABCDEFGH。
83
+ */
84
+ password: 'xx xx' // 用户账户密码 + 8 位安全令牌
85
+ },
86
+ },
87
+ }
81
88
  ```
89
+ 1、客户端 ID 和 客户端秘钥 需通过 创建连接器 获取,获取方式见:[https://doc.xiaoshouyi.com](https://doc.xiaoshouyi.com) / 创建连接器;
90
+ 2、如何获取 安全令牌 见:[https://doc.xiaoshouyi.com](https://doc.xiaoshouyi.com) / OAuth安全认证 / 密码模式 / 获取令牌;
91
+ 3、发布成功后即可在 NeoCRM 对应租户环境的页面设计器和表单设计器中使用此自定义组件。
82
92
 
83
93
  ## 常用命令说明
84
- - **neo init**: 交互式创建自定义组件(支持 -t、--name)。
85
- - **neo createProject**: 创建自定义组件项目(支持 --name)。
86
- - **neo createCmp**: 在当前项目中创建一个自定义组件(支持 --name)。
87
- - **neo preview**: 本地预览自定义组件内容(支持 --name),默认支持热更新与接口代理。
88
- - **neo linkDebug**: 外链调试模式,在平台端页面设计器中调试自定义组件。
89
- - **neo publish2oss**: 构建并上传到对象存储(支持 --name,可自定义配置对象存储)。
94
+ - **neo init**: 交互式创建自定义组件(支持 -t、--name);
95
+ - **neo createProject**: 创建自定义组件项目(支持 --name);
96
+ - **neo createCmp**: 在当前项目中创建一个自定义组件(支持 --name);
97
+ - **neo preview**: 本地预览自定义组件内容(支持 --name),默认支持热更新与接口代理;
98
+ - **neo linkDebug**: 外链调试模式,在平台端页面设计器中调试自定义组件;
99
+ - **neo publish2oss**: 构建并上传到对象存储(支持 --name,可自定义配置对象存储);
90
100
  - **neo pushCmp**: 构建并发布到NeoCRM平台(支持 --name,需自行添加授权配置)。
91
101
 
92
102
  ## 开发须知
@@ -150,14 +160,13 @@ neo linkDebug
150
160
  ##### 需自行添加授权配置
151
161
  ```javascript
152
162
  module.exports = {
153
- pushCmp: {
163
+ neoConfig: {
154
164
  neoBaseURL: 'https://crm-cd.xiaoshouyi.com', // 平台根地址(默认:https://crm.xiaoshouyi.com)
155
165
  tokenAPI: 'https://login-cd.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址(默认:https://login.xiaoshouyi.com/auc/oauth2/token)
156
166
  // NeoCRM 授权配置
157
- authConfig: {
167
+ auth: {
158
168
  /**
159
- * 客户端 ID 和 客户端秘钥 需通过 创建连接器 获取,
160
- * 详细见:https://doc.xiaoshouyi.com / 创建连接器。
169
+ * 客户端 ID 和 客户端秘钥 需通过 创建连接器 获取
161
170
  */
162
171
  client_id: 'xx', // 客户端 ID,从创建连接器的客户端信息中获取(Client_Id)
163
172
  client_secret: 'xxx', // 客户端秘钥,从创建连接器的客户端信息中获取(Client_Secret)
@@ -165,7 +174,6 @@ module.exports = {
165
174
  /**
166
175
  * password 为 用户在销售易系统中的账号密码加上 8 位安全令牌。
167
176
  * 例如,用户密码为 123456,安全令牌为 ABCDEFGH,则 password 的值应为 123456ABCDEFGH。
168
- * 如何获取 安全令牌请见:https://doc.xiaoshouyi.com / OAuth安全认证 / 密码模式 / 获取令牌。
169
177
  */
170
178
  password: 'xx xx' // 用户账户密码 + 8 位安全令牌
171
179
  },
@@ -176,8 +184,12 @@ module.exports = {
176
184
  ##### 支持发布指定自定义组件
177
185
  执行 `neo pushCmp --name=xxCmp`
178
186
 
187
+ ##### 线上 NeoCRM 端使用
188
+ 发布成功后,即可在对应租户环境下的页面设计器和表单设计器中使用此自定义组件。
189
+
179
190
  #### 7)发布自定义组件至CDN
180
191
  执行 `neo publish2oss` 即可构建对应自定义组件,并自动将构建后资源上传到对象存储(OSS)中。
192
+ 备注:请优先使用 neo pushCmp。
181
193
 
182
194
  ##### 发布前请确保
183
195
  - **package.json 的 name 唯一**
@@ -207,6 +219,9 @@ module.exports = {
207
219
  ##### 支持发布指定自定义组件
208
220
  执行 `neo publish2oss --name=xxCmp`
209
221
 
222
+ ##### 特别说明
223
+ 此发布方式只是将自定义组件构建产物发布到 CDN 上,如要使用自定义组件还需要手动添加到指定租户上(NeoCRM 管理端 / 自定义组件管理页)。
224
+
210
225
  ## 项目工程配置说明(neo.config.js)
211
226
  neo-cmp-cli 默认提供完整配置;
212
227
  如需自定义,使用 `neo config init` 生成 `neo.config.js` 并按需修改。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo-cmp-cli",
3
- "version": "1.5.6",
3
+ "version": "1.6.0-beta.1",
4
4
  "description": "前端脚手架:自定义组件开发工具,支持react 和 vue2.0技术栈。",
5
5
  "keywords": [
6
6
  "neo-cli",
@@ -29,12 +29,12 @@ module.exports = function (cmpName, componentBaseDir = './src/components') {
29
29
  const finalCmpPath = path.resolve(process.cwd(), componentBaseDir, finalCmpName);
30
30
 
31
31
  if (!hasNeoProject()) {
32
- console.error(`${consoleTag}创建自定义组件失败,当前目录(${process.cwd()})还不是 neo 项目。`);
32
+ console.error(`${consoleTag}当前(${process.cwd()})还不是自定义组件项目,请先创建一个自定义组件项目(neo init / neo createProject)。`);
33
33
  process.exit(1);
34
34
  }
35
35
 
36
36
  if (hasCmpTypeByDir(finalCmpName)) {
37
- console.error(`${consoleTag}创建自定义组件失败,当前已经存在${finalCmpName}自定义组件。`);
37
+ console.error(`${consoleTag}创建自定义组件失败,当前项目已经存在${finalCmpName}自定义组件。`);
38
38
  process.exit(1);
39
39
  }
40
40
 
@@ -0,0 +1,87 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const axios = require('axios');
4
+ const ora = require('ora');
5
+ const AdmZip = require('adm-zip');
6
+ const { consoleTag } = require('../utils/neoParams'); // 输出标记
7
+ const hasCmpTypeByDir = require('./hasCmpTypeByDir');
8
+ const hasNeoProject = require('../projectUtils/hasNeoProject');
9
+
10
+ /**
11
+ * 从 zip 包中创建自定义组件
12
+ * @param {*} cmpZipUrl 自定义组件源码文件地址(zip包地址)
13
+ * @param {*} cmpName 自定义组件名称
14
+ * @param {*} componentBaseDir 自定义组件目录
15
+ */
16
+ module.exports = async function (cmpZipUrl, cmpName, componentBaseDir = './src/components') {
17
+ const finalCmpName = cmpName || 'neoCustomCmp';
18
+
19
+ if (!hasNeoProject()) {
20
+ console.error(
21
+ `${consoleTag}当前(${process.cwd()})还不是自定义组件项目,请先创建一个自定义组件项目(neo init / neo createProject)。`
22
+ );
23
+ process.exit(1);
24
+ }
25
+
26
+ if (hasCmpTypeByDir(finalCmpName)) {
27
+ console.error(`${consoleTag}当前项目已经存在${finalCmpName}自定义组件。`);
28
+ process.exit(1);
29
+ }
30
+
31
+ // 创建临时目录
32
+ const tempDir = path.join(process.cwd(), '.neo-cli', 'zip-source');
33
+
34
+ // 下载源码文件并解析到 src/components 目录下
35
+ try {
36
+ await fs.ensureDir(tempDir); // 如果目录不存在,会自动创建(包括所有必要的父目录)
37
+
38
+ // 下载 zip 文件
39
+ const spinner = ora(`${consoleTag}正在下载组件源码...`).start();
40
+ const zipFilePath = path.join(tempDir, `${finalCmpName}.zip`);
41
+
42
+ const response = await axios({
43
+ url: cmpZipUrl,
44
+ method: 'GET',
45
+ responseType: 'arraybuffer'
46
+ });
47
+
48
+ // 保存 zip 文件到临时目录
49
+ await fs.writeFile(zipFilePath, response.data);
50
+
51
+ // 解压 zip 文件
52
+ spinner.text(`${consoleTag}正在解压组件源码...`);
53
+ const zip = new AdmZip(zipFilePath);
54
+ const extractPath = path.join(tempDir, finalCmpName);
55
+ zip.extractAllTo(extractPath, true);
56
+
57
+ // 查找解压后的 src/components 目录
58
+ const cmpSourcePath = path.join(extractPath, componentBaseDir, finalCmpName);
59
+
60
+ if (!fs.existsSync(cmpSourcePath)) {
61
+ spinner.stopAndFail(`${consoleTag}解压后的 zip 包中未找到 ${finalCmpName} 组件源码目录。`);
62
+ await fs.remove(tempDir);
63
+ process.exit(1);
64
+ }
65
+
66
+ // 确保目标目录存在
67
+ const targetComponentsDir = path.resolve(process.cwd(), componentBaseDir, finalCmpName);
68
+ await fs.ensureDir(targetComponentsDir);
69
+
70
+ // 复制 src/components 目录下的所有内容到目标目录
71
+ await fs
72
+ .copy(cmpSourcePath, targetComponentsDir)
73
+ .catch((err) => spinner.stopAndFail(`${consoleTag}自定义组件模板下载失败:`, err));
74
+
75
+ // 清理临时目录
76
+ await fs.remove(tempDir);
77
+ spinner.succeed(`${consoleTag}已成功从 zip 包解析自定义组件(${finalCmpName})!`);
78
+
79
+ return true;
80
+ } catch (error) {
81
+ spinner.stopAndFail(`${consoleTag}从 zip 包创建自定义组件失败(${finalCmpName}):`, error.message);
82
+ // 清理临时目录
83
+ await fs.remove(tempDir);
84
+
85
+ return false;
86
+ }
87
+ };
@@ -0,0 +1,96 @@
1
+ const _ = require('lodash');
2
+ const { catchCurPackageJson } = require('../utils/pathUtils');
3
+ const getConfigObj = require('../utils/getConfigObj');
4
+ const ora = require('ora');
5
+ const NeoService = require('../neo/neoService');
6
+ const { getFramework } = require('../utils/common');
7
+ const getCmpTypeByDir = require('../cmpUtils/getCmpTypeByDir.js');
8
+ const createCmpByZip = require('../cmpUtils/createCmpByZip.js');
9
+
10
+ // 获取当前项目的package文件
11
+ const currentPackageJsonDir = catchCurPackageJson();
12
+ const currentPackageJson = getConfigObj(currentPackageJsonDir);
13
+ const framework = getFramework(currentPackageJson.framework);
14
+
15
+ /**
16
+ * 从 NeoCRM 拉取自定义组件
17
+ * @param {string} cmpType 自定义组件类型
18
+ * @param {object} authConfig 授权配置
19
+ */
20
+ const pullCmp = async (cmpType, authConfig, _neoService) => {
21
+
22
+ if (!authConfig) {
23
+ console.error('未找到 NeoCRM 平台授权配置(neo.config.js / authConfig)。');
24
+ return;
25
+ }
26
+
27
+ const cmpTypes = getCmpTypeByDir(); // 获取当前项目目录中已存在的自定义组件类型
28
+ if (cmpTypes.indexOf(cmpType) > -1) {
29
+ console.error(`当前项目目录中已存在${cmpType}自定义组件。(./src/components 目录下)`);
30
+ process.exit(1);
31
+ }
32
+
33
+ const spinner = ora('正在拉取组件...').start();
34
+
35
+ try {
36
+ let neoService = _neoService;
37
+ let cmpList = [], cmpInfoMap = {};
38
+ let cmpInfo = null;
39
+
40
+ if (_neoService) {
41
+ // 使用传入的 neoService 实例
42
+ cmpList = _neoService.cmpList || [];
43
+ cmpInfoMap = _neoService.cmpInfoMap || {};
44
+ } else {
45
+ // 创建新的 neoService 实例
46
+ neoService = new NeoService(authConfig);
47
+
48
+ // 获取自定义组件列表
49
+ spinner.text('正在获取自定义组件列表...');
50
+ cmpList = await neoService.getCustomCmpList();
51
+ cmpInfoMap = neoService.cmpInfoMap || {};
52
+ }
53
+
54
+ if (cmpList.length === 0) {
55
+ spinner.stopAndFail('拉取失败,当前租户暂无任何自定义组件。');
56
+ process.exit(1);
57
+ }
58
+
59
+ // 获取自定义组件信息
60
+ spinner.text(`正在查找 ${cmpType} 组件信息...`);
61
+ cmpInfo = neoService.getCmpInfoByCmpType(cmpType);
62
+ if (!cmpInfo) {
63
+ spinner.stopAndFail(`拉取失败,当前租户不存在${cmpType}自定义组件。`);
64
+ process.exit(1);
65
+ }
66
+
67
+ // 判断拉取的组件和当前项目是否为同一技术栈
68
+ if (cmpInfo.framework !== framework) {
69
+ spinner.stopAndFail(`拉取失败,${cmpType}自定义组件与当前项目技术栈不一致。`);
70
+ process.exit(1);
71
+ }
72
+
73
+ // 获取当前源码
74
+ if (!cmpInfo.codeLib) {
75
+ spinner.stopAndFail(`拉取失败,${cmpType}自定义组件未记录对应的源码文件。`);
76
+ process.exit(1);
77
+ }
78
+
79
+ // 下载源码文件并解析到 src/components 目录下
80
+ const codeLib = cmpInfo.codeLib; // 源码文件地址(zip包地址)
81
+
82
+ // 将zip 包里面的自定义组件源码解析到 src/components 目录下
83
+ const cmpResult = await createCmpByZip(codeLib, cmpType, './src/components');
84
+ if (!cmpResult) {
85
+ spinner.stopAndFail(`拉取失败,${cmpType}自定义组件源码解析失败,请检查源码文件是否正确。`);
86
+ process.exit(1);
87
+ }
88
+
89
+ spinner.succeed(`已成功拉取${cmpType}自定义组件!\n`);
90
+ } catch (error) {
91
+ spinner.fail(`拉取自定义组件失败: ${error.message}`);
92
+ throw error;
93
+ }
94
+ };
95
+
96
+ module.exports = pullCmp;
@@ -5,49 +5,13 @@ const { catchCurPackageJson } = require('../utils/pathUtils');
5
5
  const getConfigObj = require('../utils/getConfigObj');
6
6
  const ora = require('ora');
7
7
  const NeoService = require('../neo/neoService');
8
- const { consoleTag } = require('../utils/neoParams');
8
+ const { getFramework } = require('../utils/common');
9
9
  const createCmpProjectZip = require('../projectUtils/createCmpProjectZip');
10
10
 
11
11
  // 获取当前项目的package文件
12
12
  const currentPackageJsonDir = catchCurPackageJson();
13
13
  const currentPackageJson = getConfigObj(currentPackageJsonDir);
14
14
 
15
- /**
16
- * 获取技术栈标识
17
- * 目的:兼容用户非标准写法
18
- * 0: React, 1: vue2, 2: jQuery, 3: vue3
19
- */
20
- function getFramework(_framework) {
21
- let defaultFramework = '0'; // 默认 React 技术栈
22
- if (!_framework) {
23
- return defaultFramework;
24
- }
25
- let curFramework = _framework.toLowerCase().trim();
26
- switch (curFramework) {
27
- case 'jquery':
28
- case 'jq':
29
- curFramework = '2';
30
- break;
31
- case 'vue2':
32
- case 'vue 2':
33
- case 'vue2.0':
34
- case 'vue 2.0':
35
- curFramework = '1';
36
- break;
37
- case 'vue':
38
- case 'vue3':
39
- case 'vue 3':
40
- case 'vue3.0':
41
- case 'vue 3.0':
42
- curFramework = '3';
43
- console.error(`${consoleTag} 暂不支持 vue3.0 技术栈。`);
44
- break;
45
- default:
46
- curFramework = '0';
47
- }
48
- return curFramework;
49
- }
50
-
51
15
  /**
52
16
  * 构建组件数据映射
53
17
  * @param {string} assetsRoot 构建产物的目录
@@ -61,7 +25,7 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
61
25
  }
62
26
 
63
27
  const { cmpType } = cmpInfo;
64
-
28
+
65
29
  if (!assetsRoot || !fs.existsSync(assetsRoot)) {
66
30
  console.error(`未找到自定义组件目录: ${assetsRoot}`);
67
31
  return null;
@@ -76,7 +40,7 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
76
40
  globalThis.window = {
77
41
  console: console,
78
42
  neoRequire: () => {},
79
- postMessage: () => {},
43
+ postMessage: () => {}
80
44
  // 可以添加其他常用的 window 属性
81
45
  };
82
46
  }
@@ -88,13 +52,14 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
88
52
  let modelModule = require(modelFile);
89
53
  // 获取导出的模型类(可能是 default 导出或命名导出)
90
54
  // const CatchCustomCmpModelClass = modelModule.default || modelModule;
91
- }
92
- else {
55
+ } else {
93
56
  console.error(`未找到自定义组件模型文件,请检查以下路径是否存在:`, modelFile);
94
57
  return null;
95
58
  }
96
59
  if (!window.NEOEditorCustomModels) {
97
- console.error(`模型文件未导出有效模型方法(CatchCustomCmpModelClass),模型文件地址: ${modelFile} `);
60
+ console.error(
61
+ `模型文件未导出有效模型方法(CatchCustomCmpModelClass),模型文件地址: ${modelFile} `
62
+ );
98
63
  return null;
99
64
  }
100
65
 
@@ -116,6 +81,7 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
116
81
  ...cmpInfo,
117
82
  plugin: cmpInfo.modelAsset,
118
83
  version: currentPackageJson.version || '1.0.0',
84
+ // 技术栈标识: 从 package.json / framework 字段获取,没有则默认 为 react ts 技术栈
119
85
  framework: currentPackageJson.framework ? getFramework(currentPackageJson.framework) : '0', // 0: React, 1: vue2, 2: jQuery, 3: vue3
120
86
  // 从模型实例中提取并设置组件信息
121
87
  label: modelInstance.label || cmpType,
@@ -128,9 +94,11 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
128
94
  events: modelInstance.events || [],
129
95
  actions: modelInstance.actions || [],
130
96
  // 如果模型实例中有其他属性,也可以添加
131
- exposedToDesigner: modelInstance.exposedToDesigner !== undefined ? modelInstance.exposedToDesigner : true,
97
+ exposedToDesigner:
98
+ modelInstance.exposedToDesigner !== undefined ? modelInstance.exposedToDesigner : true,
132
99
  namespace: modelInstance.namespace || 'neo-cmp-cli',
133
- enableDuplicate: modelInstance.enableDuplicate !== undefined ? modelInstance.enableDuplicate : true
100
+ enableDuplicate:
101
+ modelInstance.enableDuplicate !== undefined ? modelInstance.enableDuplicate : true
134
102
  };
135
103
 
136
104
  console.log(`自定义组件模型信息(${cmpType}):`, curCmpInfo);
@@ -152,15 +120,13 @@ const buildComponentData = async (assetsRoot, cmpInfo) => {
152
120
  /**
153
121
  * 发布组件到 NeoCRM
154
122
  * @param {object} config 配置信息
155
- * @param {string} assetsRoot 构建产物的目录
123
+ * @param {string} cmpType 自定义组件类型
156
124
  */
157
125
  const pushCmp = async (config, cmpType) => {
158
- const {
159
- authConfig: credentials
160
- } = config;
126
+ const { auth: credentials } = config;
161
127
 
162
128
  if (!credentials) {
163
- console.error('未找到 NeoCRM 平台授权配置(neo.config.js / pushCmp / authConfig)。');
129
+ console.error('未找到 NeoCRM 平台授权配置(neo.config.js / neoConfig)');
164
130
  return;
165
131
  }
166
132
 
@@ -168,33 +134,76 @@ const pushCmp = async (config, cmpType) => {
168
134
 
169
135
  try {
170
136
  // 步骤 1: 初始化 NeoService
171
- spinner.text = '发布自定义组件:初始化 NeoService...';
172
- const neoService = new NeoService(config);
137
+ let neoService = new NeoService(config);
173
138
 
174
139
  // 步骤 2: 打包源码文件(打包单个自定义组件源码)
175
- spinner.text = '发布自定义组件:打包源码文件(含单个自定义组件源码)...';
176
- createCmpProjectZip(cmpType, process.cwd(), config.assetsRoot);
140
+ spinner.start(`[1/4] 打包源码文件(含单个自定义组件源码)...`);
141
+ let zipPath;
142
+ try {
143
+ zipPath = createCmpProjectZip(cmpType, process.cwd(), config.assetsRoot);
144
+ if (!zipPath) {
145
+ spinner.fail('[1/4] 源码文件打包失败,未返回 zip 文件路径。');
146
+ } else {
147
+ spinner.succeed(`[1/4] 源码文件打包完成: ${path.basename(zipPath)}。`);
148
+ }
149
+ } catch (error) {
150
+ spinner.fail(`[1/4] 源码文件打包失败。`);
151
+ }
177
152
 
178
153
  // 步骤 3: 上传构建后资源文件
179
- spinner.text = '发布自定义组件:上传自定义组件构建产物到 OSS...';
180
- const cmpInfo = await neoService.publish2oss(cmpType);
181
-
182
- // 步骤 5: 构建组件数据
183
- spinner.text = '发布自定义组件:构建组件数据...';
184
- const componentInfo = await buildComponentData(config.assetsRoot, cmpInfo);
185
- if (!componentInfo) {
186
- throw new Error(`构建组件数据失败,未获取到自定义组件模型信息。(${cmpType})`);
154
+ spinner.start(`[2/4] 上传自定义组件构建产物到 OSS...`);
155
+ let cmpInfo;
156
+ try {
157
+ cmpInfo = await neoService.publish2oss(cmpType);
158
+ if (!cmpInfo || !cmpInfo.cmpType) {
159
+ spinner.fail('[2/4] 上传构建产物失败,未获取到组件信息。');
160
+ } else {
161
+ spinner.succeed(`[2/4] 构建产物上传完成。`);
162
+ }
163
+ } catch (error) {
164
+ spinner.fail(`[2/4] 构建产物上传失败。`);
187
165
  }
188
166
 
189
- // 步骤 6: 保存组件信息
190
- spinner.text = '发布自定义组件:保存组件信息...';
191
- await neoService.updateCustomComponent(componentInfo);
167
+ // 步骤 4: 构建组件数据
168
+ spinner.start(`[3/4] 构建组件数据...`);
169
+ let componentInfo;
170
+ try {
171
+ componentInfo = await buildComponentData(config.assetsRoot, cmpInfo);
172
+ if (!componentInfo) {
173
+ spinner.fail(`[3/4] 未获取到自定义组件模型信息(${cmpType})。`);
174
+ } else {
175
+ spinner.succeed(`[3/4] 组件数据构建完成。`);
176
+ }
177
+ } catch (error) {
178
+ spinner.fail(`[3/4] 组件数据构建失败: `, error.message);
179
+ }
192
180
 
193
- spinner.succeed('自定义组件发布成功!\n', componentInfo);
181
+ // 步骤 5: 保存组件信息
182
+ spinner.start(`[4/4] 保存组件信息到 NeoCRM 平台...`);
183
+ try {
184
+ await neoService.updateCustomComponent(componentInfo);
185
+ spinner.succeed(`[4/4] 组件信息保存成功`);
186
+ } catch (error) {
187
+ spinner.fail(`[4/4] 组件信息保存失败`);
188
+ }
189
+
190
+ // 最终成功提示
191
+ console.log('\n✅ 自定义组件发布成功!');
192
+ console.log('\n组件信息:', componentInfo);
194
193
  } catch (error) {
195
- spinner.fail(`自定义组件发布失败: ${error.message}`);
194
+ // 内层 catch 已经处理了步骤错误并显示了 spinner 失败状态
195
+ // 这里处理未预期的错误(如果 spinner 还在运行)
196
+ try {
197
+ // ora 的 spinner 对象可能没有 isSpinning 属性,使用 try-catch 安全访问
198
+ if (spinner && spinner.isSpinning) {
199
+ spinner.fail(`❌ 自定义组件发布失败: ${error.message}`);
200
+ }
201
+ } catch {
202
+ // 如果访问失败或 spinner 已停止,直接输出错误信息
203
+ console.error(`\n❌ 自定义组件发布失败: ${error.message}`);
204
+ }
196
205
  throw error;
197
206
  }
198
207
  };
199
208
 
200
- module.exports = pushCmp;
209
+ module.exports = pushCmp;