neo-cmp-cli 1.2.8 → 1.2.10
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 +20 -14
- package/package.json +1 -1
- package/src/cmpUtils/getEntries.js +8 -2
- package/src/cmpUtils/getEntriesWithAutoRegister.js +8 -2
- package/src/cmpUtils/updatePublishLog.js +33 -0
- package/src/module/index.js +7 -5
- package/src/module/main.js +3 -4
- package/src/oss/publish2oss.js +3 -0
- package/src/template/antd-custom-cmp-template/package.json +1 -1
- package/src/template/develop/neo-custom-cmp-template/package.json +1 -1
- package/src/template/echarts-custom-cmp-template/package.json +1 -1
- package/src/template/neo-custom-cmp-template/neo.config.js +1 -1
- package/src/template/neo-custom-cmp-template/package.json +4 -3
- package/src/template/neo-custom-cmp-template/src/components/contact-card-list/index.tsx +8 -9
- package/src/template/neo-custom-cmp-template/src/components/contact-form/README.md +1 -1
- package/src/template/neo-custom-cmp-template/src/components/contact-form/index.tsx +8 -8
- package/src/template/neo-custom-cmp-template/src/components/xobject-table/README.md +0 -5
- package/src/template/neo-custom-cmp-template/src/components/xobject-table/index.tsx +14 -20
- package/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/README.md +108 -0
- package/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/index.tsx +729 -0
- package/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/model.ts +122 -0
- package/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/style.scss +304 -0
- package/src/template/neo-custom-cmp-template/src/utils/queryObjectData.ts +23 -12
- package/src/template/neo-custom-cmp-template/tsconfig.json +1 -1
- package/src/template/react-custom-cmp-template/package.json +1 -1
- package/src/template/react-ts-custom-cmp-template/package.json +1 -1
- package/src/template/vue2-custom-cmp-template/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,10 @@ neo-cmp-cli 是 Neo 自定义组件开发工具,基于 [AKFun](https://github.
|
|
|
13
13
|
### 模板类型(neo init 可选)
|
|
14
14
|
- **React 模板**: [react-custom-cmp-template](https://github.com/wibetter/react-custom-cmp-template)
|
|
15
15
|
- **React + TS 模板**: [react-ts-custom-cmp-template](https://github.com/wibetter/react-ts-custom-cmp-template)
|
|
16
|
-
- **
|
|
16
|
+
- **Antd 模板**: [antd-custom-cmp-template](https://github.com/wibetter/antd-custom-cmp-template) Antd 自定义组件
|
|
17
|
+
- **Neo 模板**: [neo-custom-cmp-template](https://github.com/wibetter/neo-custom-cmp-template) 支持使用 Neo 实体数据源(内置 Neo Open API 使用示例)
|
|
18
|
+
- **Echarts 模板**: [echarts-custom-cmp-template](https://github.com/wibetter/echarts-custom-cmp-template) Echarts 图表自定义组件
|
|
19
|
+
- **Vue2 模板**: [vue2-custom-cmp-template](https://github.com/wibetter/vue2-custom-cmp-template) Vue2.0 自定义组件
|
|
17
20
|
|
|
18
21
|
## 快速开始
|
|
19
22
|
|
|
@@ -68,11 +71,24 @@ npm run publish2oss
|
|
|
68
71
|
```
|
|
69
72
|
|
|
70
73
|
## 常用命令
|
|
71
|
-
- **neo init**:
|
|
74
|
+
- **neo init**: 交互式创建自定义组件(支持 -t、--name)。
|
|
72
75
|
- **neo preview**: 本地预览自定义组件内容,默认支持热更新与接口代理。
|
|
73
|
-
- **neo linkDebug**:
|
|
76
|
+
- **neo linkDebug**: 外链调试模式,在平台端页面设计器中调试自定义组件。
|
|
74
77
|
- **neo build2lib**: 产出 UMD/ESM 库文件(可配置)。
|
|
75
|
-
- **neo publish2oss**:
|
|
78
|
+
- **neo publish2oss**: 构建并上传到对象存储(可自定义配置对象存储)。
|
|
79
|
+
|
|
80
|
+
## 内置自动识别自定义组件
|
|
81
|
+
- **自动生成入口配置**: 当 `entry` 未配置时,会自动从 `src/components` 扫描并识别自定义组件,`src/components` 下的子目录名称作为自定义组件的 cmpType,并以其目录下的 `.ts/.tsx/.js/.jsx` 结尾的文件作为组件内容文件,model.[tj]s 作为模型内容文件;
|
|
82
|
+
- **自动生成相关注册文件并注入**: 自动生成自定义组件注册文件和模型注册文件,并注入到构建脚本中,无需用户关注 [neo-register](https://www.npmjs.com/package/neo-register)。
|
|
83
|
+
|
|
84
|
+
## 发布到对象存储(OSS)
|
|
85
|
+
执行 `npm run publish2oss` 即可构建并上传到对象存储。发布前请确保:
|
|
86
|
+
- **package.json 的 name 唯一**
|
|
87
|
+
- **version 不重复**
|
|
88
|
+
- 已按需配置对象存储参数(支持自定义)
|
|
89
|
+
|
|
90
|
+
支持发布指定自定义组件:
|
|
91
|
+
执行 `npm run publish2oss --cmpType=xxCmp`
|
|
76
92
|
|
|
77
93
|
## 配置说明(neo.config.js)
|
|
78
94
|
neo-cmp-cli 默认提供完整配置;如需自定义,使用 `neo config init` 生成 `neo.config.js` 并按需修改。
|
|
@@ -222,15 +238,5 @@ module.exports = {
|
|
|
222
238
|
}
|
|
223
239
|
```
|
|
224
240
|
|
|
225
|
-
## 多页面与模板
|
|
226
|
-
- **多页面入口**: 当 `entry` 仅配置一个且对应文件不存在时,会自动从 `src/pages` 扫描以 `.ts/.tsx/.js/.jsx` 结尾的文件作为入口,匹配同名 HTML 作为模板。
|
|
227
|
-
- **模板选择**: 优先使用 `./src/index.html`;不存在时使用内置默认模板。多页面时若存在同名 HTML,将其作为页面模板。
|
|
228
|
-
|
|
229
|
-
## 发布到对象存储(OSS)
|
|
230
|
-
执行 `npm run publish2oss` 即可构建并上传到对象存储。发布前请确保:
|
|
231
|
-
- **package.json 的 name 唯一**
|
|
232
|
-
- **version 不重复**
|
|
233
|
-
- 已按需配置对象存储参数(支持自定义)
|
|
234
|
-
|
|
235
241
|
---
|
|
236
242
|
如需更多细节与高级用法,请参考模板项目与源码注释。
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@ const { resolveToCurrentRoot } = require('../utils/pathUtils');
|
|
|
8
8
|
* @param {*} defaultComponentsDir 默认组件目录
|
|
9
9
|
* @returns 组件入口文件
|
|
10
10
|
*/
|
|
11
|
-
module.exports = (defaultComponentsDir = './src/components') => {
|
|
11
|
+
module.exports = (defaultComponentsDir = './src/components', cmpType) => {
|
|
12
12
|
const widgetEntries = {};
|
|
13
13
|
const linkDebugEntries = {
|
|
14
14
|
index: []
|
|
@@ -24,7 +24,13 @@ module.exports = (defaultComponentsDir = './src/components') => {
|
|
|
24
24
|
|
|
25
25
|
try {
|
|
26
26
|
// 读取指定目录下的所有文件
|
|
27
|
-
|
|
27
|
+
let widgetDirs = [];
|
|
28
|
+
if (cmpType) {
|
|
29
|
+
// 如果传入了 cmpType,则只读取指定组件目录
|
|
30
|
+
widgetDirs = [cmpType];
|
|
31
|
+
} else {
|
|
32
|
+
widgetDirs = fs.readdirSync(componentsBaseDir);
|
|
33
|
+
}
|
|
28
34
|
|
|
29
35
|
// 遍历所有目录
|
|
30
36
|
widgetDirs.forEach((dir) => {
|
|
@@ -9,7 +9,7 @@ const getCmpModelRegister = require('./getCmpModelRegister');
|
|
|
9
9
|
* @param {*} defaultComponentsDir 默认组件目录
|
|
10
10
|
* @returns 组件入口文件
|
|
11
11
|
*/
|
|
12
|
-
module.exports = (defaultComponentsDir = './src/components') => {
|
|
12
|
+
module.exports = (defaultComponentsDir = './src/components', cmpType) => {
|
|
13
13
|
const widgetEntries = {};
|
|
14
14
|
const linkDebugEntries = {
|
|
15
15
|
index: []
|
|
@@ -31,7 +31,13 @@ module.exports = (defaultComponentsDir = './src/components') => {
|
|
|
31
31
|
|
|
32
32
|
try {
|
|
33
33
|
// 读取指定目录下的所有文件
|
|
34
|
-
|
|
34
|
+
let widgetDirs = [];
|
|
35
|
+
if (cmpType) {
|
|
36
|
+
// 如果传入了 cmpType,则只读取指定组件目录
|
|
37
|
+
widgetDirs = [cmpType];
|
|
38
|
+
} else {
|
|
39
|
+
widgetDirs = fs.readdirSync(componentsBaseDir);
|
|
40
|
+
}
|
|
35
41
|
|
|
36
42
|
// 遍历所有目录
|
|
37
43
|
widgetDirs.forEach((dir) => {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { resolveToCurrentRoot } = require('../utils/pathUtils');
|
|
5
|
+
const getCmpRegister = require('./getCmpRegister');
|
|
6
|
+
const getCmpModelRegister = require('./getCmpModelRegister');
|
|
7
|
+
/**
|
|
8
|
+
* 更新发布日志
|
|
9
|
+
*/
|
|
10
|
+
module.exports = (curHistoryData) => {
|
|
11
|
+
// 创建存放 cli 的临时目录
|
|
12
|
+
const cliTempDir = resolveToCurrentRoot('./.neo-cli');
|
|
13
|
+
if (!fs.existsSync(cliTempDir)) {
|
|
14
|
+
fs.mkdirSync(cliTempDir);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const historyFile = `${cliTempDir}/history.json`;
|
|
18
|
+
let historyData = {};
|
|
19
|
+
if (fs.existsSync(historyFile)) {
|
|
20
|
+
// 读取历史文件
|
|
21
|
+
try {
|
|
22
|
+
historyData = JSON.parse(fs.readFileSync(historyFile, 'utf8'));
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('读取历史文件失败:', error);
|
|
25
|
+
historyData = {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const historyKey = new Date().toString();
|
|
29
|
+
historyData[historyKey] = curHistoryData;
|
|
30
|
+
|
|
31
|
+
// 更新历史文件
|
|
32
|
+
fs.writeFileSync(historyFile, JSON.stringify(historyData, null, 2));
|
|
33
|
+
};
|
package/src/module/index.js
CHANGED
|
@@ -76,13 +76,11 @@ yargs
|
|
|
76
76
|
value: 'echarts',
|
|
77
77
|
short: 'echarts'
|
|
78
78
|
},
|
|
79
|
-
/*
|
|
80
79
|
{
|
|
81
80
|
name: 'Neo 自定义组件',
|
|
82
81
|
value: 'neo',
|
|
83
82
|
short: 'neo'
|
|
84
83
|
},
|
|
85
|
-
*/
|
|
86
84
|
{
|
|
87
85
|
name: 'react 自定义组件',
|
|
88
86
|
value: 'react',
|
|
@@ -234,16 +232,20 @@ yargs
|
|
|
234
232
|
}
|
|
235
233
|
)
|
|
236
234
|
.command(
|
|
237
|
-
'publish2oss',
|
|
235
|
+
'publish2oss [options]',
|
|
238
236
|
'发布到oss',
|
|
239
237
|
(yargs) => {
|
|
240
238
|
yargs
|
|
241
239
|
.reset()
|
|
242
|
-
.usage(titleTip('Usage') + ': $0
|
|
240
|
+
.usage(titleTip('Usage') + ': $0 publish2oss [options]')
|
|
241
|
+
.option('cmpType', {
|
|
242
|
+
alias: 't',
|
|
243
|
+
describe: '自定义组件名称'
|
|
244
|
+
})
|
|
243
245
|
.alias('h', 'help');
|
|
244
246
|
},
|
|
245
247
|
(argv) => {
|
|
246
|
-
mainAction.publish2oss(); // 构建并发布脚本到oss
|
|
248
|
+
mainAction.publish2oss(argv.cmpType); // 构建并发布脚本到oss
|
|
247
249
|
}
|
|
248
250
|
)
|
|
249
251
|
.command(
|
package/src/module/main.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const akfun = require('akfun');
|
|
2
|
-
const path = require('path');
|
|
3
2
|
const _ = require('lodash');
|
|
4
3
|
const neoInit = require('./neoInit');
|
|
5
4
|
const neoInitByCopy = require('./neoInitByCopy');
|
|
@@ -180,7 +179,7 @@ module.exports = {
|
|
|
180
179
|
|
|
181
180
|
akfun.build('lib', curConfig, consoleTag);
|
|
182
181
|
}, // 构建脚本:生产环境
|
|
183
|
-
publish2oss: () => {
|
|
182
|
+
publish2oss: (cmpType) => {
|
|
184
183
|
// 将 publish2oss 相关配置设置给 build2lib
|
|
185
184
|
const publish2ossConfig = curConfig.publish2oss;
|
|
186
185
|
curConfig.build2lib = Object.assign(curConfig.build2lib, publish2ossConfig);
|
|
@@ -193,12 +192,12 @@ module.exports = {
|
|
|
193
192
|
let entries = {};
|
|
194
193
|
if (curConfig.build2lib.disableAutoRegister) {
|
|
195
194
|
// disableAutoRegister 为 true 时,仅自动生成入口文件(不自动注册)
|
|
196
|
-
const { widgetEntries, cmpTypes } = getEntries(curConfig.componentsDir);
|
|
195
|
+
const { widgetEntries, cmpTypes } = getEntries(curConfig.componentsDir, cmpType);
|
|
197
196
|
entries = widgetEntries;
|
|
198
197
|
curCmpTypes = cmpTypes;
|
|
199
198
|
} else {
|
|
200
199
|
// 自动生成入口文件(并自动创建对应的注册文件)
|
|
201
|
-
const { widgetEntries, cmpTypes } = getEntriesWithAutoRegister(curConfig.componentsDir);
|
|
200
|
+
const { widgetEntries, cmpTypes } = getEntriesWithAutoRegister(curConfig.componentsDir, cmpType);
|
|
202
201
|
entries = widgetEntries;
|
|
203
202
|
curCmpTypes = cmpTypes;
|
|
204
203
|
}
|
package/src/oss/publish2oss.js
CHANGED
|
@@ -3,6 +3,7 @@ const fs = require('fs');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { catchCurPackageJson } = require('../utils/pathUtils');
|
|
5
5
|
const getConfigObj = require('../utils/getConfigObj');
|
|
6
|
+
const updatePublishLog = require('../cmpUtils/updatePublishLog');
|
|
6
7
|
|
|
7
8
|
// 获取当前项目的package文件
|
|
8
9
|
const currentPackageJsonDir = catchCurPackageJson();
|
|
@@ -94,6 +95,8 @@ const publish2oss = (ossType, ossConfig, assetsRoot, fileExtensions = ['.js', '.
|
|
|
94
95
|
const widgetFilesMap = getResultFilesByWidgetName(results);
|
|
95
96
|
if (widgetFilesMap) {
|
|
96
97
|
console.info('上传至 OSS 的文件信息:\n', widgetFilesMap);
|
|
98
|
+
// 更新发布日志
|
|
99
|
+
updatePublishLog(widgetFilesMap);
|
|
97
100
|
}
|
|
98
101
|
})
|
|
99
102
|
.catch((error) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neo-custom-cmp-template",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "neo自定义组件模板(react&ts技术栈)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"自定义组件模板",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"react-dom": "^16.9.0",
|
|
44
44
|
"axios": "^0.27.2",
|
|
45
45
|
"antd": "^4.9.4",
|
|
46
|
-
"lodash": "^4.17.21"
|
|
46
|
+
"lodash": "^4.17.21",
|
|
47
|
+
"neo-open-api": "^1.0.2"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@commitlint/cli": "^8.3.5",
|
|
@@ -51,7 +52,7 @@
|
|
|
51
52
|
"@types/react": "^16.9.11",
|
|
52
53
|
"@types/react-dom": "^16.9.15",
|
|
53
54
|
"@types/axios": "^0.14.0",
|
|
54
|
-
"neo-cmp-cli": "^1.2.
|
|
55
|
+
"neo-cmp-cli": "^1.2.9",
|
|
55
56
|
"husky": "^4.2.5",
|
|
56
57
|
"lint-staged": "^10.2.9",
|
|
57
58
|
"prettier": "^2.0.5"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Card, Row, Col, Spin, Empty, Avatar, Button } from 'antd';
|
|
3
3
|
import { UserOutlined, PhoneOutlined, ReloadOutlined } from '@ant-design/icons';
|
|
4
|
-
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import { xObject } from 'neo-open-api'; // Neo Open API
|
|
5
6
|
import './style.scss';
|
|
6
7
|
|
|
7
8
|
interface ContactCardListProps {
|
|
@@ -47,16 +48,15 @@ export default class ContactCardList extends React.PureComponent<
|
|
|
47
48
|
this.setState({ loading: true, error: null });
|
|
48
49
|
|
|
49
50
|
try {
|
|
50
|
-
// 使用
|
|
51
|
-
const
|
|
51
|
+
// 使用 Neo Open API 获取 customContact__c 数据
|
|
52
|
+
const result = await xObject.query({
|
|
52
53
|
xObjectApiKey: 'customContact__c',
|
|
53
54
|
fields: ['id', 'name', 'phone__c'],
|
|
54
55
|
});
|
|
55
56
|
|
|
56
|
-
if (
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const totalSize = curResult.totalSize || 0;
|
|
57
|
+
if (result?.status) {
|
|
58
|
+
const records = result.data || [];
|
|
59
|
+
const totalSize = result.totalSize || 0;
|
|
60
60
|
this.setState({
|
|
61
61
|
contactList: records,
|
|
62
62
|
totalSize,
|
|
@@ -64,12 +64,11 @@ export default class ContactCardList extends React.PureComponent<
|
|
|
64
64
|
});
|
|
65
65
|
} else {
|
|
66
66
|
this.setState({
|
|
67
|
-
error:
|
|
67
|
+
error: result?.msg || '获取联系人数据失败',
|
|
68
68
|
loading: false,
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
} catch (error: any) {
|
|
72
|
-
console.error('获取联系人数据失败:', error);
|
|
73
72
|
this.setState({
|
|
74
73
|
error: error.message || '获取联系人数据失败',
|
|
75
74
|
loading: false,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Form, Input, Select, Button, message, Card } from 'antd';
|
|
3
|
-
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import { xObject } from 'neo-open-api'; // Neo Open API
|
|
4
5
|
const { Option } = Select;
|
|
5
6
|
|
|
6
7
|
import './style.scss';
|
|
@@ -39,11 +40,10 @@ export default class ContactForm extends React.PureComponent<
|
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
// 获取业务类型列表
|
|
42
|
-
getEntityTypeList('customContact__c').then((res: any) => {
|
|
43
|
-
if (res && res.
|
|
44
|
-
const result = res.data || {};
|
|
43
|
+
xObject.getEntityTypeList('customContact__c').then((res: any) => {
|
|
44
|
+
if (res && res.status) {
|
|
45
45
|
this.setState({
|
|
46
|
-
entityTypeList:
|
|
46
|
+
entityTypeList: res.data || [],
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
});
|
|
@@ -115,19 +115,19 @@ export default class ContactForm extends React.PureComponent<
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// 调用 API 提交数据
|
|
118
|
-
const response: any = await
|
|
118
|
+
const response: any = await xObject.create('customContact__c', {
|
|
119
119
|
method: 'POST',
|
|
120
120
|
data: submitData,
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
if (response && response.
|
|
123
|
+
if (response && response.status) {
|
|
124
124
|
message.success('联系人创建成功!');
|
|
125
125
|
// 成功后重置表单
|
|
126
126
|
setTimeout(() => {
|
|
127
127
|
this.resetForm();
|
|
128
128
|
}, 1000);
|
|
129
129
|
} else {
|
|
130
|
-
message.error('创建联系人失败:', response.
|
|
130
|
+
message.error('创建联系人失败:', response.msg);
|
|
131
131
|
}
|
|
132
132
|
} catch (error: any) {
|
|
133
133
|
message.error('创建联系人失败:', error);
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
# XObject 数据表格组件
|
|
2
2
|
基于 XObject 的数据表格组件,支持增删改查操作,表格列根据 `getXObjectDesc` 返回的 fields 动态生成。
|
|
3
3
|
|
|
4
|
-
- 对应的生成指令
|
|
5
|
-
```
|
|
6
|
-
@utils/ 请根据这里提供的方法,参照 @contact-card-list/ 使用 antd 组件 写一个 表格组件,展示属性配置 xobject 对应的 业务数据列表,支持创建、编辑、删除操作。其中表格展示的列 根据 getXObjectDesc 返回的 fields 生成,表格的 Title 根据 其返回的 label 显示。另外 请使用 propsSchemaCreator 生成自定义组件的属性配置,支持 xobject 选择配置,其中 xobject 的选项 使用 getEntityList获取。
|
|
7
|
-
```
|
|
8
|
-
|
|
9
4
|
## 功能特性
|
|
10
5
|
|
|
11
6
|
- 📊 **动态表格列**:根据 XObject 字段描述自动生成表格列
|
|
@@ -29,14 +29,14 @@ import {
|
|
|
29
29
|
ReloadOutlined,
|
|
30
30
|
} from '@ant-design/icons';
|
|
31
31
|
import moment from 'moment';
|
|
32
|
-
import { queryXObjectData } from '
|
|
32
|
+
import { queryXObjectData } from '$utils/queryObjectData';
|
|
33
33
|
import {
|
|
34
34
|
getEntityTypeList,
|
|
35
35
|
getXObjectDesc,
|
|
36
36
|
createXObject,
|
|
37
37
|
updateXObject,
|
|
38
38
|
deleteXObject,
|
|
39
|
-
} from '
|
|
39
|
+
} from '$utils/xobjects';
|
|
40
40
|
import './style.scss';
|
|
41
41
|
|
|
42
42
|
const { Option } = Select;
|
|
@@ -142,6 +142,14 @@ export default class XObjectTable extends React.PureComponent<
|
|
|
142
142
|
entityTypeList: [],
|
|
143
143
|
};
|
|
144
144
|
|
|
145
|
+
if (this.props.xObjectApiKey) {
|
|
146
|
+
// 初始化字段列表、加载数据和业务类型列表
|
|
147
|
+
this.loadFieldList().then(() => {
|
|
148
|
+
this.loadData();
|
|
149
|
+
});
|
|
150
|
+
this.getEntityTypeList();
|
|
151
|
+
}
|
|
152
|
+
|
|
145
153
|
// 绑定方法上下文
|
|
146
154
|
this.loadData = this.loadData.bind(this);
|
|
147
155
|
this.loadFieldList = this.loadFieldList.bind(this);
|
|
@@ -153,18 +161,6 @@ export default class XObjectTable extends React.PureComponent<
|
|
|
153
161
|
this.handleTableChange = this.handleTableChange.bind(this);
|
|
154
162
|
}
|
|
155
163
|
|
|
156
|
-
/**
|
|
157
|
-
* 组件挂载后执行
|
|
158
|
-
* 初始化字段列表、加载数据和业务类型列表
|
|
159
|
-
*/
|
|
160
|
-
async componentDidMount() {
|
|
161
|
-
if (this.props.xObjectApiKey) {
|
|
162
|
-
await this.loadFieldList();
|
|
163
|
-
this.loadData();
|
|
164
|
-
this.getEntityTypeList();
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
164
|
/**
|
|
169
165
|
* 获取业务类型列表
|
|
170
166
|
* 用于下拉选择框的选项数据
|
|
@@ -297,16 +293,15 @@ export default class XObjectTable extends React.PureComponent<
|
|
|
297
293
|
try {
|
|
298
294
|
// 获取所有字段的 API Key
|
|
299
295
|
const fields = this.state.fieldList.map((field) => field.apiKey);
|
|
300
|
-
const
|
|
296
|
+
const result = await queryXObjectData({
|
|
301
297
|
xObjectApiKey,
|
|
302
298
|
fields,
|
|
303
299
|
page,
|
|
304
300
|
pageSize,
|
|
305
301
|
});
|
|
306
302
|
|
|
307
|
-
if (
|
|
308
|
-
const
|
|
309
|
-
const records = result.records || [];
|
|
303
|
+
if (result && result.status) {
|
|
304
|
+
const records = result.data || [];
|
|
310
305
|
const totalSize = result.totalSize || 0;
|
|
311
306
|
|
|
312
307
|
this.setState({
|
|
@@ -320,12 +315,11 @@ export default class XObjectTable extends React.PureComponent<
|
|
|
320
315
|
});
|
|
321
316
|
} else {
|
|
322
317
|
this.setState({
|
|
323
|
-
error:
|
|
318
|
+
error: result?.msg || '获取数据失败',
|
|
324
319
|
loading: false,
|
|
325
320
|
});
|
|
326
321
|
}
|
|
327
322
|
} catch (error: any) {
|
|
328
|
-
console.error('获取数据失败:', error);
|
|
329
323
|
this.setState({
|
|
330
324
|
error: error.message || '获取数据失败',
|
|
331
325
|
loading: false,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# XObject 数据表格组件
|
|
2
|
+
基于 XObject 的数据表格组件,支持增删改查操作,表格列根据 `getXObjectDesc` 返回的 fields 动态生成。
|
|
3
|
+
|
|
4
|
+
## 功能特性
|
|
5
|
+
|
|
6
|
+
- 📊 **动态表格列**:根据 XObject 字段描述自动生成表格列
|
|
7
|
+
- ➕ **新增记录**:支持通过弹窗表单新增数据记录
|
|
8
|
+
- ✏️ **编辑记录**:支持编辑现有数据记录
|
|
9
|
+
- 🗑️ **删除记录**:支持删除数据记录,带确认提示
|
|
10
|
+
- 🔄 **数据刷新**:支持手动刷新数据
|
|
11
|
+
- 📄 **分页支持**:支持分页显示,可配置每页显示条数
|
|
12
|
+
- 🎨 **响应式设计**:适配不同屏幕尺寸
|
|
13
|
+
- ⚙️ **属性配置**:支持通过编辑器配置组件属性
|
|
14
|
+
|
|
15
|
+
## 组件属性
|
|
16
|
+
|
|
17
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
18
|
+
|--------|------|--------|------|
|
|
19
|
+
| title | string | '数据表格' | 表格标题 |
|
|
20
|
+
| xObjectApiKey | string | '' | 数据对象的 API Key |
|
|
21
|
+
| pageSize | number | 10 | 每页显示条数 |
|
|
22
|
+
| showPagination | boolean | true | 是否显示分页 |
|
|
23
|
+
| showAddButton | boolean | true | 是否显示新增按钮 |
|
|
24
|
+
| showEditButton | boolean | true | 是否显示编辑按钮 |
|
|
25
|
+
| showDeleteButton | boolean | true | 是否显示删除按钮 |
|
|
26
|
+
|
|
27
|
+
## 使用方法
|
|
28
|
+
|
|
29
|
+
### 1. 在编辑器中使用
|
|
30
|
+
|
|
31
|
+
1. 从组件面板拖拽 "XObject 数据表格" 组件到页面
|
|
32
|
+
2. 在右侧属性面板中选择要操作的数据对象
|
|
33
|
+
3. 配置其他属性(可选)
|
|
34
|
+
4. 保存并预览
|
|
35
|
+
|
|
36
|
+
### 2. 代码中使用
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import XObjectTable from './components/xobject-table';
|
|
40
|
+
|
|
41
|
+
// 使用组件
|
|
42
|
+
<XObjectTable
|
|
43
|
+
title="联系人列表"
|
|
44
|
+
xObjectApiKey="customContact__c"
|
|
45
|
+
pageSize={20}
|
|
46
|
+
showPagination={true}
|
|
47
|
+
showAddButton={true}
|
|
48
|
+
showEditButton={true}
|
|
49
|
+
showDeleteButton={true}
|
|
50
|
+
/>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 技术实现
|
|
54
|
+
|
|
55
|
+
### 核心依赖
|
|
56
|
+
|
|
57
|
+
- **Ant Design**:UI 组件库
|
|
58
|
+
- **React**:前端框架
|
|
59
|
+
- **TypeScript**:类型支持
|
|
60
|
+
|
|
61
|
+
### 主要方法
|
|
62
|
+
|
|
63
|
+
- `getXObjectDesc()`:获取 XObject 字段描述
|
|
64
|
+
- `getEntityList()`:获取实体列表
|
|
65
|
+
- `queryXObjectData()`:查询数据列表
|
|
66
|
+
- `createXObject()`:创建数据记录
|
|
67
|
+
- `updateXObject()`:更新数据记录
|
|
68
|
+
- `deleteXObject()`:删除数据记录
|
|
69
|
+
|
|
70
|
+
### 数据流程
|
|
71
|
+
|
|
72
|
+
1. **初始化**:组件挂载时获取实体列表和字段描述
|
|
73
|
+
2. **列生成**:根据字段描述动态生成表格列
|
|
74
|
+
3. **数据加载**:使用 `queryXObjectData` 获取数据列表
|
|
75
|
+
4. **操作处理**:通过对应的 API 方法处理增删改操作
|
|
76
|
+
|
|
77
|
+
## 样式定制
|
|
78
|
+
|
|
79
|
+
组件提供了完整的 SCSS 样式文件,支持以下定制:
|
|
80
|
+
|
|
81
|
+
- 表格样式(边框、悬停效果等)
|
|
82
|
+
- 按钮样式(颜色、大小、间距等)
|
|
83
|
+
- 弹窗样式(表单布局、输入框样式等)
|
|
84
|
+
- 响应式设计(移动端适配)
|
|
85
|
+
|
|
86
|
+
## 注意事项
|
|
87
|
+
|
|
88
|
+
1. **权限要求**:确保用户有对应 XObject 的读写权限
|
|
89
|
+
2. **字段类型**:目前支持 text、textarea、select 等基础字段类型
|
|
90
|
+
3. **必填字段**:表单会根据字段的 required 属性进行验证
|
|
91
|
+
4. **错误处理**:组件内置了完善的错误处理和用户提示
|
|
92
|
+
|
|
93
|
+
## 扩展开发
|
|
94
|
+
|
|
95
|
+
如需扩展功能,可以:
|
|
96
|
+
|
|
97
|
+
1. **添加字段类型支持**:在 `renderForm()` 方法中添加新的字段类型
|
|
98
|
+
2. **自定义操作列**:修改 `generateColumns()` 方法中的操作列配置
|
|
99
|
+
3. **添加批量操作**:扩展表格功能支持批量删除等操作
|
|
100
|
+
4. **自定义样式**:修改 `style.scss` 文件定制组件外观
|
|
101
|
+
|
|
102
|
+
## 更新日志
|
|
103
|
+
|
|
104
|
+
### v1.0.0
|
|
105
|
+
- 初始版本发布
|
|
106
|
+
- 支持基础的增删改查功能
|
|
107
|
+
- 支持动态列生成
|
|
108
|
+
- 支持属性配置面板
|