neo-cmp-cli 1.5.0-beta.1 → 1.5.0-beta.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo-cmp-cli",
3
- "version": "1.5.0-beta.1",
3
+ "version": "1.5.0-beta.3",
4
4
  "description": "前端脚手架:自定义组件开发工具,支持react 和 vue2.0技术栈。",
5
5
  "keywords": [
6
6
  "neo-cli",
@@ -83,9 +83,9 @@ function getFramework(_framework) {
83
83
  * 构建组件数据映射
84
84
  * @param {string} assetsRoot 构建产物的目录
85
85
  * @param {object} cmpInfo 自定义组件信息
86
- * @returns {object} 自定义组件数据(含自定义组件模型信息)
86
+ * @returns {Promise<object|null>} 自定义组件数据(含自定义组件模型信息)
87
87
  */
88
- const buildComponentData = (assetsRoot, cmpInfo) => {
88
+ const buildComponentData = async (assetsRoot, cmpInfo) => {
89
89
  if (!cmpInfo || !cmpInfo.cmpType) {
90
90
  console.error('自定义组件信息或组件名称不能为空');
91
91
  return null;
@@ -94,51 +94,52 @@ const buildComponentData = (assetsRoot, cmpInfo) => {
94
94
  const { cmpType } = cmpInfo;
95
95
 
96
96
  if (!assetsRoot || !fs.existsSync(assetsRoot)) {
97
- console.error(`未找到自定义组件资源目录: ${assetsRoot}`);
97
+ console.error(`未找到自定义组件目录: ${assetsRoot}`);
98
98
  return null;
99
99
  }
100
- const widgetName = _.kebabCase(cmpType);
100
+ const widgetName = _.camelCase(cmpType);
101
101
  const modelFile = path.join(assetsRoot, `${widgetName}Model.js`);
102
102
 
103
- let ModelClass = null;
103
+ let CatchCustomCmpModelClass = null;
104
+
105
+ // 为 Node.js 环境设置全局 window 对象(模型文件可能需要)
106
+ // 使用 globalThis 以确保在 Node.js 和浏览器环境中都能工作
107
+ const originalWindow = globalThis.window;
108
+ if (!globalThis.window) {
109
+ globalThis.window = {
110
+ console: console,
111
+ neoRequire: () => {},
112
+ // 可以添加其他常用的 window 属性
113
+ };
114
+ }
104
115
 
105
116
  try {
106
117
  // 加载自定义组件模型资源文件
107
118
  if (fs.existsSync(modelFile)) {
108
- // 清除 require 缓存,确保每次都加载最新内容
109
- const resolvedPath = require.resolve(modelFile);
110
- if (require.cache[resolvedPath]) {
111
- delete require.cache[resolvedPath];
112
- }
113
- const modelModule = require(modelFile);
119
+ let modelModule = require(modelFile);
114
120
  // 获取导出的模型类(可能是 default 导出或命名导出)
115
- ModelClass = modelModule.default || modelModule;
116
- // 如果是命名导出,尝试查找类名(例如 EntityCardListModel)
117
- if (typeof ModelClass !== 'function' && typeof modelModule === 'object') {
118
- // 查找所有导出的类
119
- const exportedClasses = Object.values(modelModule).filter(
120
- (item) => typeof item === 'function'
121
- );
122
- if (exportedClasses.length > 0) {
123
- ModelClass = exportedClasses[0];
124
- }
125
- }
121
+ CatchCustomCmpModelClass = modelModule.default || modelModule;
126
122
  }
127
- // 如果资源文件不存在,报错
128
123
  else {
129
- console.error(`未找到自定义组件模型文件,请检查以下路径是否存在:`);
124
+ console.error(`未找到自定义组件模型文件,请检查以下路径是否存在:`, modelFile);
130
125
  return null;
131
126
  }
132
127
 
133
- // 如果 ModelClass 是函数(类),则实例化
134
- if (typeof ModelClass !== 'function') {
135
- console.error(`模型文件 ${modelFile} 未导出有效的模型类`);
128
+ if (!CatchCustomCmpModelClass || typeof CatchCustomCmpModelClass !== 'function') {
129
+ console.error(`模型文件未导出有效模型方法(CatchCustomCmpModelClass),模型文件地址: ${modelFile} `);
136
130
  return null;
137
131
  }
138
132
 
133
+ // 先获取对应的模型类
134
+ const ModelClass = new CatchCustomCmpModelClass(cmpType);
139
135
  // 实例化模型类
140
136
  const modelInstance = new ModelClass();
141
137
 
138
+ if (!modelInstance) {
139
+ console.error(`模型文件未导出有效模型实例(${cmpType}),模型文件地址: ${modelFile} `);
140
+ return null;
141
+ }
142
+
142
143
  // 构建组件数据,合并模型实例的信息
143
144
  const curCmpInfo = {
144
145
  ...cmpInfo,
@@ -160,11 +161,19 @@ const buildComponentData = (assetsRoot, cmpInfo) => {
160
161
  enableDuplicate: modelInstance.enableDuplicate !== undefined ? modelInstance.enableDuplicate : true
161
162
  };
162
163
 
164
+ console.log('自定义组件模型信息(${cmpType}):', curCmpInfo);
163
165
  return curCmpInfo;
164
166
  } catch (error) {
165
167
  console.error(`自定义组件模型文件解析失败 (${modelFile || '未知路径'}):`, error.message);
166
168
  console.error(error.stack);
167
169
  return null;
170
+ } finally {
171
+ // 恢复原始的 window 对象(如果之前存在)
172
+ if (originalWindow === undefined) {
173
+ delete globalThis.window;
174
+ } else {
175
+ globalThis.window = originalWindow;
176
+ }
168
177
  }
169
178
  };
170
179
 
@@ -202,9 +211,9 @@ const publishCmp = async (config, cmpType) => {
202
211
 
203
212
  // 步骤 4: 构建组件数据
204
213
  spinner.text = '发布自定义组件:构建组件数据...';
205
- const componentInfo = buildComponentData(config.assetsRoot, cmpInfo);
214
+ const componentInfo = await buildComponentData(config.assetsRoot, cmpInfo);
206
215
  if (!componentInfo) {
207
- throw new Error('构建组件数据失败,无法继续发布');
216
+ throw new Error(`构建组件数据失败,未获取到自定义组件模型信息。(${cmpType})`);
208
217
  }
209
218
 
210
219
  // 步骤 5: 保存组件信息
@@ -218,5 +227,4 @@ const publishCmp = async (config, cmpType) => {
218
227
  }
219
228
  };
220
229
 
221
- module.exports = publishCmp;
222
-
230
+ module.exports = publishCmp;
@@ -34,8 +34,8 @@ const defaultNEOConfig = {
34
34
  template: resolveByDirname('../initData/defaultTemplate.html'), // 默认使用neo-widget提供的页面模板(会启动页面设计器)
35
35
  sassResources: [],
36
36
  babelPlugins: [
37
- ['import', { libraryName: 'antd', style: 'css' }], // 配置 antd 的样式按需引入
38
- ],
37
+ ['import', { libraryName: 'antd', style: 'css' }] // 配置 antd 的样式按需引入
38
+ ]
39
39
  },
40
40
  envParams: {
41
41
  // 项目系统环境变量
@@ -132,6 +132,18 @@ const defaultNEOConfig = {
132
132
  bucket: 'neo-widgets' // 存储桶名称
133
133
  },
134
134
  assetsRoot: resolve('dist') // 上传指定目录下的脚本文件
135
+ },
136
+ publishCmp: {
137
+ output: {
138
+ filename: '[name].js',
139
+ library: {
140
+ type: 'var', // webpack 5 中生成 IIFE 格式的 type 配置
141
+ export: 'default'
142
+ },
143
+ globalObject: 'this' // 定义全局变量,兼容node和浏览器运行,避免出现"window is not defined"的情况
144
+ },
145
+ cssExtract: false, // 不额外提取css文件
146
+ assetsRoot: resolve('dist') // 上传指定目录下的脚本文件
135
147
  }
136
148
  };
137
149
 
@@ -0,0 +1,29 @@
1
+ /**
2
+ * 内置 UMD 模块,用于在 Node cli 端加载自定义组件模型
3
+ * 特别说明:这个文件内容会通过 AddNeoRequirePlugin 插入的构建代码中。
4
+ */
5
+ (function (root, factory) {
6
+ // AMD 环境检测
7
+ if (typeof define === 'function' && define.amd) {
8
+ define([], factory);
9
+ }
10
+ // CommonJS 环境检测
11
+ else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
12
+ module.exports = factory();
13
+ }
14
+ // 浏览器全局变量
15
+ else {
16
+ root.NeoCustomCmpModel = factory();
17
+ }
18
+ }(typeof self !== 'undefined' ? self : this, function () {
19
+ 'use strict';
20
+
21
+ const getCustomModels = (cmpType) => {
22
+ // 自定义组件模型列表
23
+ const NEOEditorCustomModels = window.NEOEditorCustomModels || {};
24
+ return NEOEditorCustomModels[cmpType] || {};
25
+ }
26
+
27
+ // 导出模块
28
+ return getCustomModels;
29
+ }));
@@ -8,9 +8,9 @@ const updatePublishLog = require('../cmpUtils/updatePublishLog');
8
8
  // NeoCRM 平台默认 API 配置
9
9
  const NeoCrmAPI = {
10
10
  neoBaseURL: 'https://crm.xiaoshouyi.com', // 平台根地址
11
- tokenAPI: 'https://login.crm.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址
11
+ tokenAPI: 'https://login.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址
12
12
  uploadAPI: '/rest/metadata/v3.0/ui/customComponents/actions/upload', // 文件上传接口地址
13
- saveAPI: '/rest/metadata/v3.0/ui/customComponents/actions/saveComponent' // 组件信息保存接口地址
13
+ saveAPI: '/rest/metadata/v3.0/ui/customComponents/actions/saveOrUpdateComponent' // 创建或者保存接口地址
14
14
  };
15
15
 
16
16
  /**
@@ -101,29 +101,30 @@ class NeoService {
101
101
  console.info('使用缓存的 token');
102
102
  return this.tokenCache.token;
103
103
  }
104
+ console.info('获取 token...');
104
105
 
105
- console.info('正在获取 token...');
106
+ // 构建表单数据格式的请求参数
107
+ const formData = new URLSearchParams();
108
+ formData.append('grant_type', 'password');
109
+ formData.append('client_id', this.authorization.client_id);
110
+ formData.append('client_secret', this.authorization.client_secret);
111
+ formData.append('username', this.authorization.username);
112
+ formData.append('password', this.authorization.password);
113
+
114
+ const tokenUrl = this.buildFullUrl(this.tokenAPI);
106
115
 
107
116
  try {
108
- // 构建请求参数
109
- const params = new URLSearchParams();
110
- params.append('grant_type', 'password');
111
- params.append('client_id', this.authorization.client_id);
112
- params.append('client_secret', this.authorization.client_secret);
113
- params.append('username', this.authorization.username);
114
- params.append('password', this.authorization.password);
115
-
116
- const tokenUrl = this.buildFullUrl(this.tokenAPI);
117
- const response = await axios.post(tokenUrl, params, {
117
+ const response = await axios.post(tokenUrl, formData.toString(), {
118
118
  headers: {
119
119
  'Content-Type': 'application/x-www-form-urlencoded'
120
120
  }
121
121
  });
122
122
 
123
- const { access_token, expires_in } = response.data;
123
+ const { access_token, expires_in } = response.data || {};
124
124
 
125
125
  if (!access_token) {
126
- throw new Error('获取 token 失败:响应中未包含 access_token');
126
+ console.error('获取 token 失败:响应中未包含 access_token', response.data);
127
+ process.exit(1);
127
128
  }
128
129
 
129
130
  // 缓存 token(提前 60 秒过期,避免边缘情况)
@@ -132,15 +133,15 @@ class NeoService {
132
133
  token: access_token,
133
134
  expiresAt: Date.now() + (expiresIn - 60) * 1000
134
135
  };
135
-
136
- console.info('token 获取成功');
137
136
  return access_token;
138
137
  } catch (error) {
139
138
  console.error('获取 token 失败:', error.message);
139
+ console.error('\ntoken 授权地址:', tokenUrl);
140
+ console.error('\ntoken 请求参数:', formData);
140
141
  if (error.response) {
141
142
  console.error('响应数据:', error.response.data);
142
143
  }
143
- throw error;
144
+ process.exit(1);
144
145
  }
145
146
  }
146
147
 
@@ -163,7 +164,9 @@ class NeoService {
163
164
  * @returns {Promise<string>} 有效的 token
164
165
  */
165
166
  async ensureValidToken() {
166
- if (this.isTokenExpired()) {
167
+ if (!this.tokenCache.token) {
168
+ return await this.getToken();
169
+ } else if (this.isTokenExpired()) {
167
170
  console.info('token 已过期,正在刷新...');
168
171
  return await this.refreshToken();
169
172
  }
@@ -174,59 +177,155 @@ class NeoService {
174
177
  * 上传文件到 Neo 平台
175
178
  * @param {string} filePath 文件路径
176
179
  * @param {object} options 可选配置
177
- * @param {string} options.fieldName 表单字段名,默认为 'file'
180
+ * @param {string} options.fieldName 表单字段名,默认为 'customComponentCode'
181
+ * @param {number} options.maxSize 最大文件大小(字节),默认 50MB
182
+ * @param {number} options.timeout 超时时间(毫秒),默认 60000
178
183
  * @returns {Promise<string>} CDN 地址或文件 URL
179
184
  */
180
185
  async uploadFile(filePath, options = {}) {
181
186
  // 确保 token 有效
182
187
  const token = await this.ensureValidToken();
183
188
 
189
+ // 验证文件路径
190
+ if (!filePath || typeof filePath !== 'string') {
191
+ throw new Error(`文件路径无效: ${filePath}`);
192
+ }
193
+
194
+ // 检查文件是否存在
184
195
  if (!fs.existsSync(filePath)) {
185
196
  throw new Error(`文件不存在: ${filePath}`);
186
197
  }
187
198
 
188
- console.info('正在上传文件...');
199
+ // 检查文件状态
200
+ const fileStat = fs.statSync(filePath);
201
+ if (!fileStat.isFile()) {
202
+ throw new Error(`路径不是文件: ${filePath}`);
203
+ }
204
+
205
+ // 检查文件大小
206
+ const maxSize = options.maxSize || 50 * 1024 * 1024; // 默认 50MB
207
+ if (fileStat.size > maxSize) {
208
+ const sizeMB = (fileStat.size / 1024 / 1024).toFixed(2);
209
+ const maxSizeMB = (maxSize / 1024 / 1024).toFixed(2);
210
+ throw new Error(`文件大小超过限制: ${sizeMB}MB > ${maxSizeMB}MB`);
211
+ }
212
+
213
+ if (fileStat.size === 0) {
214
+ throw new Error(`文件为空: ${filePath}`);
215
+ }
216
+
217
+ const fileName = path.basename(filePath);
218
+ const fileSizeKB = (fileStat.size / 1024).toFixed(2);
219
+ console.info(`正在上传文件: ${fileName} (${fileSizeKB}KB)...`);
189
220
 
190
221
  try {
222
+ // 创建 FormData
191
223
  const formData = new FormData();
192
224
  const fieldName = options.fieldName || 'customComponentCode';
193
- formData.append(fieldName, fs.createReadStream(filePath));
225
+
226
+ // 使用文件流而不是读取整个文件到内存(对大文件更友好)
227
+ const fileContent = fs.createReadStream(filePath);
194
228
 
229
+ // 追加文件到 FormData,第三个参数指定文件名
230
+ formData.append(fieldName, fileContent, fileName);
231
+
232
+ // 构建完整的上传 API 地址
195
233
  const fullUploadAPI = this.uploadAPI();
196
- const response = await axios.post(fullUploadAPI, formData, {
234
+
235
+ // 配置请求选项
236
+ const timeout = options.timeout || 60000; // 默认 60 秒
237
+ const requestConfig = {
197
238
  headers: {
198
239
  Authorization: `Bearer ${token}`,
240
+ 'xsy-inner-source': 'bff',
241
+ // 无需手动设置 Content-Type,formData.getHeaders() 会自动设置正确的 multipart/form-data 和 boundary
199
242
  ...formData.getHeaders()
200
- }
201
- });
243
+ },
244
+ timeout,
245
+ // 确保 axios 正确处理大文件和流
246
+ maxContentLength: Infinity, // 不限制响应内容长度
247
+ maxBodyLength: Infinity // 不限制请求体长度(适用于文件上传)
248
+ };
202
249
 
203
- // 处理不同的响应格式
250
+ // 发送上传请求
251
+ const response = await axios.post(fullUploadAPI, formData, requestConfig);
252
+
253
+ // 处理响应数据
204
254
  let resultData;
205
- if (typeof response.data === 'string') {
206
- resultData = response.data;
207
- } else if (response.data && response.data.data) {
208
- resultData = response.data.data;
209
- } else if (response.data && response.data.code === 200) {
210
- resultData = response.data.data;
211
- } else {
212
- resultData = response.data;
255
+ const responseData = response.data;
256
+
257
+ // 检查响应状态码
258
+ if (response.status !== 200 && response.status !== 201) {
259
+ throw new Error(`上传失败: HTTP ${response.status}`);
213
260
  }
214
261
 
215
- if (response.data && response.data.code && response.data.code !== 200) {
216
- throw new Error(`上传失败: ${response.data.message || '未知错误'}`);
262
+ // 处理不同的响应格式
263
+ if (typeof responseData === 'string') {
264
+ // 如果响应是字符串,直接使用
265
+ resultData = responseData.trim();
266
+ } else if (responseData && typeof responseData === 'object') {
267
+ // 检查是否有错误码
268
+ if (responseData.code !== undefined && responseData.code !== 200 && responseData.code !== 0) {
269
+ const errorMsg = responseData.message || responseData.msg || '未知错误';
270
+ throw new Error(`上传失败: ${errorMsg} (code: ${responseData.code})`);
271
+ }
272
+
273
+ // 提取数据
274
+ if (responseData.data !== undefined) {
275
+ resultData = responseData.data;
276
+ } else if (responseData.url !== undefined) {
277
+ resultData = responseData.url;
278
+ } else if (responseData.fileUrl !== undefined) {
279
+ resultData = responseData.fileUrl;
280
+ } else {
281
+ resultData = responseData;
282
+ }
283
+ } else {
284
+ throw new Error(`响应数据格式不正确: ${typeof responseData}`);
217
285
  }
218
286
 
219
- if (!resultData || (typeof resultData !== 'string' && !resultData.url)) {
220
- throw new Error(`返回的文件地址格式不正确: ${JSON.stringify(resultData)}`);
287
+ // 验证返回的文件地址
288
+ if (!resultData) {
289
+ throw new Error(`返回的文件地址为空`);
221
290
  }
222
291
 
223
- const fileUrl = typeof resultData === 'string' ? resultData : resultData.url;
292
+ // 格式化文件 URL
293
+ let fileUrl;
294
+ if (typeof resultData === 'string') {
295
+ fileUrl = resultData;
296
+ } else if (resultData && typeof resultData === 'object' && resultData.url) {
297
+ fileUrl = resultData.url;
298
+ }
299
+ console.info(`文件上传成功: ${fileName} -> ${fileUrl}`);
224
300
  return fileUrl;
225
301
  } catch (error) {
226
- console.error('上传文件失败:', error.message);
302
+ console.error(`上传文件失败: ${error.message}`);
303
+ console.error(`文件路径: ${filePath}`);
304
+
305
+ // 输出详细的错误信息
227
306
  if (error.response) {
228
- console.error('响应数据:', error.response.data);
307
+ const status = error.response.status;
308
+ const statusText = error.response.statusText;
309
+ const responseData = error.response.data;
310
+ const requestUrl = error.config?.url || this.uploadAPI();
311
+
312
+ console.error(`\n========== 上传请求详情 ==========`);
313
+ console.error(`请求 URL: ${requestUrl}`);
314
+ console.error(`HTTP 状态码: ${status} ${statusText}`);
315
+ console.error(`响应数据:`, responseData);
316
+ console.error(`==================================\n`);
317
+
318
+ if (status === 404) {
319
+ throw new Error(
320
+ `上传 API 不存在 (404): ${requestUrl}\n` +
321
+ `请检查 neo.config.js 中的 neoBaseURL 配置是否正确,或者 API 路径是否存在。\n` +
322
+ `当前配置的 API 路径: ${NeoCrmAPI.uploadAPI}`
323
+ );
324
+ }
325
+ } else if (error.request) {
326
+ console.error('请求已发送但未收到响应,请检查网络连接或代理配置。');
229
327
  }
328
+
230
329
  throw error;
231
330
  }
232
331
  }
@@ -238,7 +337,7 @@ class NeoService {
238
337
  * @param {array} fileExtensions 需要上传的文件类型,默认 ['.js', '.css']
239
338
  */
240
339
  async publish2oss(cmpType, fileExtensions = ['.js', '.css']) {
241
- if (!fs.existsSync(cmpType)) {
340
+ if (!cmpType) {
242
341
  console.error(`自定义组件名称不能为空: ${cmpType}`);
243
342
  return;
244
343
  }
@@ -262,7 +361,7 @@ class NeoService {
262
361
  // const fileExt = path.extname(file);
263
362
  const fileInfo = path.parse(filePath);
264
363
  if (fileStat.isFile() && fileExtensions.includes(fileInfo.ext)) {
265
- let widgetName = _.kebabCase(cmpType);
364
+ let widgetName = _.camelCase(cmpType);
266
365
 
267
366
  if (file.indexOf(widgetName) < 0) {
268
367
  return;
@@ -271,7 +370,7 @@ class NeoService {
271
370
  try {
272
371
  // 上传文件
273
372
  const fileUrl = await this.uploadFile(filePath);
274
-
373
+
275
374
  if (file.indexOf('Model') > -1) {
276
375
  curCmpInfo.modelAsset = fileUrl;
277
376
  } else if (file.endsWith('.css')) {
@@ -279,15 +378,15 @@ class NeoService {
279
378
  } else {
280
379
  curCmpInfo.asset = fileUrl;
281
380
  }
282
-
283
381
  } catch (error) {
284
- console.error(`文件上传失败(${file}):\n`, error);
382
+ console.error(`文件上传失败(${file}):\n`);
383
+ process.exit(1);
285
384
  }
286
385
  }
287
386
  });
288
387
 
289
388
  await Promise.all(uploadPromises);
290
-
389
+
291
390
  if (curCmpInfo && curCmpInfo.cmpType) {
292
391
  console.info('上传至 OSS 的文件信息:\n', curCmpInfo);
293
392
  // 更新发布日志
@@ -298,7 +397,6 @@ class NeoService {
298
397
 
299
398
  /**
300
399
  * 更新自定义组件
301
- * @param {string} updateAPI 更新接口地址(相对或绝对路径)
302
400
  * @param {object} componentData 组件数据
303
401
  * @returns {Promise<object>} 更新结果
304
402
  */
@@ -313,10 +411,12 @@ class NeoService {
313
411
  console.info('正在更新自定义组件...');
314
412
 
315
413
  try {
316
- const fullUpdateAPI = this.updateAPI();
414
+ const fullUpdateAPI = this.saveAPI();
415
+ console.info('更新组件 API 地址:', fullUpdateAPI);
317
416
  const response = await axios.post(fullUpdateAPI, componentData, {
318
417
  headers: {
319
418
  Authorization: `Bearer ${token}`,
419
+ 'xsy-inner-source': 'bff',
320
420
  'Content-Type': 'application/json'
321
421
  }
322
422
  });
@@ -332,7 +432,7 @@ class NeoService {
332
432
  if (error.response) {
333
433
  console.error('响应数据:', error.response.data);
334
434
  }
335
- throw error;
435
+ process.exit(1);
336
436
  }
337
437
  }
338
438
 
@@ -361,6 +461,7 @@ class NeoService {
361
461
  params,
362
462
  headers: {
363
463
  Authorization: `Bearer ${token}`,
464
+ 'xsy-inner-source': 'bff',
364
465
  ...headers
365
466
  }
366
467
  });
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * 注入 neoRequire 函数
3
3
  * 备注:用于实现和 Neo 平台共享依赖
4
+ * 特别说明:这个文件只是用于说明 AddNeoRequirePlugin 中会插入的代码内容,实际内容内置在 AddNeoRequirePlugin 方法中。
4
5
  */
5
6
  (function(NeoCustomCmpFileFactory) {
6
7
  if (!window.neoRequire) {
@@ -12,4 +13,4 @@
12
13
  * 这里放自定义组件相关内容代码
13
14
  * 备注: 自定义组件代码中的 require 函数 已被替换成 neoRequire 函数(require === neoRequire)。
14
15
  */
15
- });
16
+ });
@@ -1,5 +1,4 @@
1
1
  const { ConcatSource } = require('webpack-sources');
2
-
3
2
  /**
4
3
  * 注入 neoRequire 函数
5
4
  * 备注:用于实现和 Neo 平台共享依赖
@@ -163,7 +162,9 @@ class AddNeoRequirePlugin {
163
162
  })(function(require) {
164
163
  `;
165
164
 
166
- const Footer = `})`;
165
+ const NeoUMDContent = fs.readFileSync(path.join(__dirname, '../neo/NeoUMDContent.js'), 'utf8');
166
+
167
+ const Footer = `}); \n${NeoUMDContent}`;
167
168
 
168
169
  // 创建新的资源
169
170
  const newSource = new ConcatSource(Header, content, Footer);
@@ -127,9 +127,10 @@ module.exports = {
127
127
  */
128
128
  },
129
129
  publishCmp: {
130
+ libraryName: 'NeoCustomCmpModel', // 构建第三方功能包时最后导出的引用变量名
130
131
  // 用于构建并发布至 NeoCRM 的相关配置
131
132
  neoBaseURL: 'https://crm-cd.xiaoshouyi.com', // 平台根地址(默认:https://crm.xiaoshouyi.com)
132
- tokenAPI: 'https://login.crm-cd.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址(默认:https://login.crm.xiaoshouyi.com/auc/oauth2/token)
133
+ tokenAPI: 'https://login-cd.xiaoshouyi.com/auc/oauth2/token', // Token 获取接口地址(默认:https://login.xiaoshouyi.com/auc/oauth2/token)
133
134
  // NeoCRM 授权配置
134
135
  authorization: {
135
136
  client_id: authConfig.client_id || 'xx', // 客户端 ID,从创建连接器的客户端信息中获取(Client_Id)
@@ -53,7 +53,7 @@
53
53
  "@types/react": "^16.9.11",
54
54
  "@types/react-dom": "^16.9.15",
55
55
  "@types/axios": "^0.14.0",
56
- "neo-cmp-cli": "^1.5.1",
56
+ "neo-cmp-cli": "^1.5.0-beta.2",
57
57
  "husky": "^4.2.5",
58
58
  "lint-staged": "^10.2.9",
59
59
  "prettier": "^2.0.5"
@@ -278,6 +278,8 @@ export default class EntityDetail extends React.PureComponent<
278
278
 
279
279
  return (
280
280
  <div className="entity-detail-container">
281
+ <img src="https://custom-widget2.oss-cn-beijing.aliyuncs.com/img.png" alt="logo" />
282
+ <img src="https://publicfront-1253467224.cos.ap-beijing.myqcloud.com/customComponent/crm-cd/tenant/3392331536784858/1761882606360/img.png" alt="logo" />
281
283
  {showTitle && (
282
284
  <div className="detail-header">
283
285
  <div className="header-content">