neo-cmp-cli 1.5.0-beta.2 → 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 +1 -1
- package/src/cmpUtils/publishCmp.js +37 -29
- package/src/config/default.config.js +2 -2
- package/src/neo/NeoUMDContent.js +29 -0
- package/src/neo/neoService.js +141 -44
- package/src/neo/wrapperContent.js +2 -1
- package/src/plugins/AddNeoRequirePlugin.js +3 -2
- package/src/template/neo-custom-cmp-template/neo.config.js +2 -1
- package/src/template/neo-custom-cmp-template/package.json +1 -1
- package/src/template/neo-custom-cmp-template/src/components/entity-detail/index.tsx +2 -0
package/package.json
CHANGED
|
@@ -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(
|
|
97
|
+
console.error(`未找到自定义组件目录: ${assetsRoot}`);
|
|
98
98
|
return null;
|
|
99
99
|
}
|
|
100
100
|
const widgetName = _.camelCase(cmpType);
|
|
101
101
|
const modelFile = path.join(assetsRoot, `${widgetName}Model.js`);
|
|
102
102
|
|
|
103
|
-
let
|
|
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
|
-
|
|
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
|
-
|
|
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
124
|
console.error(`未找到自定义组件模型文件,请检查以下路径是否存在:`, modelFile);
|
|
130
125
|
return null;
|
|
131
126
|
}
|
|
132
127
|
|
|
133
|
-
|
|
134
|
-
|
|
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' }]
|
|
38
|
-
]
|
|
37
|
+
['import', { libraryName: 'antd', style: 'css' }] // 配置 antd 的样式按需引入
|
|
38
|
+
]
|
|
39
39
|
},
|
|
40
40
|
envParams: {
|
|
41
41
|
// 项目系统环境变量
|
|
@@ -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
|
+
}));
|
package/src/neo/neoService.js
CHANGED
|
@@ -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.
|
|
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/
|
|
13
|
+
saveAPI: '/rest/metadata/v3.0/ui/customComponents/actions/saveOrUpdateComponent' // 创建或者保存接口地址
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -101,26 +101,26 @@ class NeoService {
|
|
|
101
101
|
console.info('使用缓存的 token');
|
|
102
102
|
return this.tokenCache.token;
|
|
103
103
|
}
|
|
104
|
+
console.info('获取 token...');
|
|
104
105
|
|
|
105
|
-
|
|
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
126
|
console.error('获取 token 失败:响应中未包含 access_token', response.data);
|
|
@@ -133,11 +133,11 @@ class NeoService {
|
|
|
133
133
|
token: access_token,
|
|
134
134
|
expiresAt: Date.now() + (expiresIn - 60) * 1000
|
|
135
135
|
};
|
|
136
|
-
|
|
137
|
-
console.info('token 获取成功');
|
|
138
136
|
return access_token;
|
|
139
137
|
} catch (error) {
|
|
140
138
|
console.error('获取 token 失败:', error.message);
|
|
139
|
+
console.error('\ntoken 授权地址:', tokenUrl);
|
|
140
|
+
console.error('\ntoken 请求参数:', formData);
|
|
141
141
|
if (error.response) {
|
|
142
142
|
console.error('响应数据:', error.response.data);
|
|
143
143
|
}
|
|
@@ -177,59 +177,155 @@ class NeoService {
|
|
|
177
177
|
* 上传文件到 Neo 平台
|
|
178
178
|
* @param {string} filePath 文件路径
|
|
179
179
|
* @param {object} options 可选配置
|
|
180
|
-
* @param {string} options.fieldName 表单字段名,默认为 '
|
|
180
|
+
* @param {string} options.fieldName 表单字段名,默认为 'customComponentCode'
|
|
181
|
+
* @param {number} options.maxSize 最大文件大小(字节),默认 50MB
|
|
182
|
+
* @param {number} options.timeout 超时时间(毫秒),默认 60000
|
|
181
183
|
* @returns {Promise<string>} CDN 地址或文件 URL
|
|
182
184
|
*/
|
|
183
185
|
async uploadFile(filePath, options = {}) {
|
|
184
186
|
// 确保 token 有效
|
|
185
187
|
const token = await this.ensureValidToken();
|
|
186
188
|
|
|
189
|
+
// 验证文件路径
|
|
190
|
+
if (!filePath || typeof filePath !== 'string') {
|
|
191
|
+
throw new Error(`文件路径无效: ${filePath}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 检查文件是否存在
|
|
187
195
|
if (!fs.existsSync(filePath)) {
|
|
188
196
|
throw new Error(`文件不存在: ${filePath}`);
|
|
189
197
|
}
|
|
190
198
|
|
|
191
|
-
|
|
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)...`);
|
|
192
220
|
|
|
193
221
|
try {
|
|
222
|
+
// 创建 FormData
|
|
194
223
|
const formData = new FormData();
|
|
195
224
|
const fieldName = options.fieldName || 'customComponentCode';
|
|
196
|
-
|
|
225
|
+
|
|
226
|
+
// 使用文件流而不是读取整个文件到内存(对大文件更友好)
|
|
227
|
+
const fileContent = fs.createReadStream(filePath);
|
|
197
228
|
|
|
229
|
+
// 追加文件到 FormData,第三个参数指定文件名
|
|
230
|
+
formData.append(fieldName, fileContent, fileName);
|
|
231
|
+
|
|
232
|
+
// 构建完整的上传 API 地址
|
|
198
233
|
const fullUploadAPI = this.uploadAPI();
|
|
199
|
-
|
|
234
|
+
|
|
235
|
+
// 配置请求选项
|
|
236
|
+
const timeout = options.timeout || 60000; // 默认 60 秒
|
|
237
|
+
const requestConfig = {
|
|
200
238
|
headers: {
|
|
201
239
|
Authorization: `Bearer ${token}`,
|
|
240
|
+
'xsy-inner-source': 'bff',
|
|
241
|
+
// 无需手动设置 Content-Type,formData.getHeaders() 会自动设置正确的 multipart/form-data 和 boundary
|
|
202
242
|
...formData.getHeaders()
|
|
203
|
-
}
|
|
204
|
-
|
|
243
|
+
},
|
|
244
|
+
timeout,
|
|
245
|
+
// 确保 axios 正确处理大文件和流
|
|
246
|
+
maxContentLength: Infinity, // 不限制响应内容长度
|
|
247
|
+
maxBodyLength: Infinity // 不限制请求体长度(适用于文件上传)
|
|
248
|
+
};
|
|
205
249
|
|
|
206
|
-
//
|
|
250
|
+
// 发送上传请求
|
|
251
|
+
const response = await axios.post(fullUploadAPI, formData, requestConfig);
|
|
252
|
+
|
|
253
|
+
// 处理响应数据
|
|
207
254
|
let resultData;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
resultData = response.data.data;
|
|
214
|
-
} else {
|
|
215
|
-
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}`);
|
|
216
260
|
}
|
|
217
261
|
|
|
218
|
-
|
|
219
|
-
|
|
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}`);
|
|
220
285
|
}
|
|
221
286
|
|
|
222
|
-
|
|
223
|
-
|
|
287
|
+
// 验证返回的文件地址
|
|
288
|
+
if (!resultData) {
|
|
289
|
+
throw new Error(`返回的文件地址为空`);
|
|
224
290
|
}
|
|
225
291
|
|
|
226
|
-
|
|
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}`);
|
|
227
300
|
return fileUrl;
|
|
228
301
|
} catch (error) {
|
|
229
|
-
console.error(
|
|
302
|
+
console.error(`上传文件失败: ${error.message}`);
|
|
303
|
+
console.error(`文件路径: ${filePath}`);
|
|
304
|
+
|
|
305
|
+
// 输出详细的错误信息
|
|
230
306
|
if (error.response) {
|
|
231
|
-
|
|
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('请求已发送但未收到响应,请检查网络连接或代理配置。');
|
|
232
327
|
}
|
|
328
|
+
|
|
233
329
|
throw error;
|
|
234
330
|
}
|
|
235
331
|
}
|
|
@@ -274,7 +370,7 @@ class NeoService {
|
|
|
274
370
|
try {
|
|
275
371
|
// 上传文件
|
|
276
372
|
const fileUrl = await this.uploadFile(filePath);
|
|
277
|
-
|
|
373
|
+
|
|
278
374
|
if (file.indexOf('Model') > -1) {
|
|
279
375
|
curCmpInfo.modelAsset = fileUrl;
|
|
280
376
|
} else if (file.endsWith('.css')) {
|
|
@@ -282,16 +378,15 @@ class NeoService {
|
|
|
282
378
|
} else {
|
|
283
379
|
curCmpInfo.asset = fileUrl;
|
|
284
380
|
}
|
|
285
|
-
|
|
286
381
|
} catch (error) {
|
|
287
|
-
console.error(`文件上传失败(${file}):\n
|
|
382
|
+
console.error(`文件上传失败(${file}):\n`);
|
|
288
383
|
process.exit(1);
|
|
289
384
|
}
|
|
290
385
|
}
|
|
291
386
|
});
|
|
292
387
|
|
|
293
388
|
await Promise.all(uploadPromises);
|
|
294
|
-
|
|
389
|
+
|
|
295
390
|
if (curCmpInfo && curCmpInfo.cmpType) {
|
|
296
391
|
console.info('上传至 OSS 的文件信息:\n', curCmpInfo);
|
|
297
392
|
// 更新发布日志
|
|
@@ -302,7 +397,6 @@ class NeoService {
|
|
|
302
397
|
|
|
303
398
|
/**
|
|
304
399
|
* 更新自定义组件
|
|
305
|
-
* @param {string} updateAPI 更新接口地址(相对或绝对路径)
|
|
306
400
|
* @param {object} componentData 组件数据
|
|
307
401
|
* @returns {Promise<object>} 更新结果
|
|
308
402
|
*/
|
|
@@ -317,10 +411,12 @@ class NeoService {
|
|
|
317
411
|
console.info('正在更新自定义组件...');
|
|
318
412
|
|
|
319
413
|
try {
|
|
320
|
-
const fullUpdateAPI = this.
|
|
414
|
+
const fullUpdateAPI = this.saveAPI();
|
|
415
|
+
console.info('更新组件 API 地址:', fullUpdateAPI);
|
|
321
416
|
const response = await axios.post(fullUpdateAPI, componentData, {
|
|
322
417
|
headers: {
|
|
323
418
|
Authorization: `Bearer ${token}`,
|
|
419
|
+
'xsy-inner-source': 'bff',
|
|
324
420
|
'Content-Type': 'application/json'
|
|
325
421
|
}
|
|
326
422
|
});
|
|
@@ -365,6 +461,7 @@ class NeoService {
|
|
|
365
461
|
params,
|
|
366
462
|
headers: {
|
|
367
463
|
Authorization: `Bearer ${token}`,
|
|
464
|
+
'xsy-inner-source': 'bff',
|
|
368
465
|
...headers
|
|
369
466
|
}
|
|
370
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
|
|
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
|
|
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)
|
|
@@ -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">
|