neo-cmp-cli 1.2.12 → 1.2.13
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/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/README.md +1 -1
- package/src/template/neo-custom-cmp-template/package.json +2 -2
- package/src/template/neo-custom-cmp-template/src/assets/img/detail.svg +1 -0
- package/src/template/neo-custom-cmp-template/src/components/contact-card-list/README.md +2 -7
- package/src/template/neo-custom-cmp-template/src/components/contact-card-list/index.tsx +13 -1
- package/src/template/neo-custom-cmp-template/src/components/contact-form/index.tsx +2 -3
- package/src/template/neo-custom-cmp-template/src/components/entity-detail/README.md +193 -0
- package/src/template/neo-custom-cmp-template/src/components/entity-detail/index.tsx +325 -0
- package/src/template/neo-custom-cmp-template/src/components/entity-detail/model.ts +125 -0
- package/src/template/neo-custom-cmp-template/src/components/entity-detail/style.scss +292 -0
- package/src/template/neo-custom-cmp-template/src/components/object-card-list/README.md +61 -0
- package/src/template/neo-custom-cmp-template/src/components/object-card-list/index.tsx +201 -0
- package/src/template/neo-custom-cmp-template/src/components/object-card-list/model.ts +66 -0
- package/src/template/neo-custom-cmp-template/src/components/object-card-list/style.scss +260 -0
- package/src/template/neo-custom-cmp-template/src/components/xobject-table/README.md +3 -11
- package/src/template/neo-custom-cmp-template/src/components/xobject-table/index.tsx +76 -58
- package/src/template/neo-custom-cmp-template/src/components/xobject-table/model.ts +21 -3
- 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/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/README.md +0 -108
- package/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/index.tsx +0 -729
- package/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/model.ts +0 -122
- package/src/template/neo-custom-cmp-template/src/components/xobject-table-v2/style.scss +0 -304
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 实体数据详情组件对接编辑器的描述文件
|
|
3
|
+
* @description 定义组件在 Neo 平台编辑器中的配置信息
|
|
4
|
+
*/
|
|
5
|
+
export class EntityDetailModel {
|
|
6
|
+
/**
|
|
7
|
+
* 组件类型标识
|
|
8
|
+
* 用于标识组件的唯一性,在构建时根据当前组件目录名称自动生成
|
|
9
|
+
* 注意:此字段在构建时会被自动替换,不需要手动设置
|
|
10
|
+
*/
|
|
11
|
+
// cmpType: string = 'entity-detail';
|
|
12
|
+
|
|
13
|
+
/** 组件名称,用于设置在编辑器左侧组件面板中展示的名称 */
|
|
14
|
+
label: string = '实体数据详情';
|
|
15
|
+
|
|
16
|
+
/** 组件描述,用于设置在编辑器左侧组件面板中展示的描述 */
|
|
17
|
+
description: string = '展示实体数据详情信息,支持多列布局和字段类型识别';
|
|
18
|
+
|
|
19
|
+
/** 分类标签,用于设置在编辑器左侧组件面板哪个分类中展示(可设置多个分类标签) */
|
|
20
|
+
tags: string[] = ['自定义组件'];
|
|
21
|
+
|
|
22
|
+
/** 组件图标,用于设置在编辑器左侧组件面板中展示的图标 */
|
|
23
|
+
iconSrc: string = 'https://custom-widgets.bj.bcebos.com/detail.svg';
|
|
24
|
+
|
|
25
|
+
/** 初次插入页面的默认属性数据 */
|
|
26
|
+
defaultComProps = {
|
|
27
|
+
title: '实体数据详情',
|
|
28
|
+
xObjectDetailApi: {
|
|
29
|
+
xObjectApiKey: 'account',
|
|
30
|
+
objectId: '',
|
|
31
|
+
},
|
|
32
|
+
columnCount: 3,
|
|
33
|
+
showTitle: true,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** 设计器端预览时展示的默认数据 */
|
|
37
|
+
previewComProps = {
|
|
38
|
+
title: '实体数据详情',
|
|
39
|
+
columnCount: 3,
|
|
40
|
+
showTitle: true,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 组件属性配置模式
|
|
45
|
+
* 定义组件在编辑器中可配置的属性
|
|
46
|
+
*/
|
|
47
|
+
propsSchema = [
|
|
48
|
+
{
|
|
49
|
+
type: 'text',
|
|
50
|
+
name: 'title',
|
|
51
|
+
label: '标题',
|
|
52
|
+
value: '实体数据详情',
|
|
53
|
+
placeholder: '请输入标题',
|
|
54
|
+
description: '组件顶部显示的标题',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'switch',
|
|
58
|
+
name: 'showTitle',
|
|
59
|
+
label: '显示标题栏',
|
|
60
|
+
value: true,
|
|
61
|
+
description: '是否显示组件顶部的标题和刷新按钮',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: 'xObjectDetailApi', // 用于选取对象业务详情数据的配置项
|
|
65
|
+
name: 'xObjectDetailApi',
|
|
66
|
+
label: '业务详情数据',
|
|
67
|
+
},
|
|
68
|
+
/*
|
|
69
|
+
{
|
|
70
|
+
type: 'xObjectEntityList', // 用于选取实体的配置项
|
|
71
|
+
name: 'xObjectDetailApi.xObjectApiKey',
|
|
72
|
+
label: '实体对象',
|
|
73
|
+
helpText: '请选择要展示详情的实体对象',
|
|
74
|
+
custom: false,
|
|
75
|
+
value: 'account'
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
name: 'xObjectDetailApi.objectId',
|
|
80
|
+
label: '数据ID',
|
|
81
|
+
value: '',
|
|
82
|
+
placeholder: '请输入数据ID或使用上下文变量',
|
|
83
|
+
description: '要展示的数据记录ID,支持变量:${recordId}',
|
|
84
|
+
},
|
|
85
|
+
*/
|
|
86
|
+
{
|
|
87
|
+
type: 'select',
|
|
88
|
+
name: 'columnCount',
|
|
89
|
+
label: '列数',
|
|
90
|
+
value: 3,
|
|
91
|
+
options: [
|
|
92
|
+
{
|
|
93
|
+
label: '1列',
|
|
94
|
+
value: 1,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
label: '2列',
|
|
98
|
+
value: 2,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
label: '3列',
|
|
102
|
+
value: 3,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
label: '4列',
|
|
106
|
+
value: 4,
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
description: '详情页面的列数布局',
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 支持函数式写法:propsSchemaCreator
|
|
115
|
+
* com 为组件实例,优先级比 propsSchema 高
|
|
116
|
+
* 可以根据组件实例动态生成属性配置
|
|
117
|
+
*/
|
|
118
|
+
/*
|
|
119
|
+
propsSchemaCreator = (com: any) => {
|
|
120
|
+
return [];
|
|
121
|
+
};
|
|
122
|
+
*/
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default EntityDetailModel;
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
.entity-detail-container {
|
|
2
|
+
position: relative;
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
height: 100%;
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
margin: 6px 12px;
|
|
8
|
+
padding: 16px;
|
|
9
|
+
background-color: #fff;
|
|
10
|
+
border-radius: 8px;
|
|
11
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
12
|
+
|
|
13
|
+
.detail-header {
|
|
14
|
+
flex-shrink: 0;
|
|
15
|
+
margin-bottom: 16px;
|
|
16
|
+
|
|
17
|
+
.header-content {
|
|
18
|
+
display: flex;
|
|
19
|
+
justify-content: space-between;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: 16px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.header-title {
|
|
25
|
+
margin: 0 !important;
|
|
26
|
+
font-family: PingFangSC-Medium, -apple-system, BlinkMacSystemFont,
|
|
27
|
+
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
28
|
+
font-size: 18px;
|
|
29
|
+
font-weight: 500;
|
|
30
|
+
line-height: 1.4;
|
|
31
|
+
color: #262626;
|
|
32
|
+
flex: 1;
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: 8px;
|
|
36
|
+
|
|
37
|
+
.title-icon {
|
|
38
|
+
color: #1890ff;
|
|
39
|
+
font-size: 20px;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.refresh-button {
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
border-radius: 6px;
|
|
46
|
+
font-size: 13px;
|
|
47
|
+
height: 32px;
|
|
48
|
+
padding: 4px 12px;
|
|
49
|
+
box-shadow: 0 2px 4px rgba(24, 144, 255, 0.2);
|
|
50
|
+
transition: all 0.3s ease;
|
|
51
|
+
|
|
52
|
+
&:hover {
|
|
53
|
+
box-shadow: 0 4px 8px rgba(24, 144, 255, 0.3);
|
|
54
|
+
transform: translateY(-1px);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&:active {
|
|
58
|
+
transform: translateY(0);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.anticon {
|
|
62
|
+
font-size: 12px;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.detail-content {
|
|
68
|
+
flex: 1;
|
|
69
|
+
overflow-y: auto;
|
|
70
|
+
overflow-x: hidden;
|
|
71
|
+
|
|
72
|
+
.error-container {
|
|
73
|
+
display: flex;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
align-items: center;
|
|
76
|
+
min-height: 300px;
|
|
77
|
+
padding: 20px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.detail-column-card {
|
|
81
|
+
height: 100%;
|
|
82
|
+
background: #fafafa;
|
|
83
|
+
border-radius: 8px;
|
|
84
|
+
|
|
85
|
+
.ant-card-body {
|
|
86
|
+
padding: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ant-descriptions {
|
|
90
|
+
background: transparent;
|
|
91
|
+
|
|
92
|
+
&.ant-descriptions-bordered {
|
|
93
|
+
.ant-descriptions-item-label {
|
|
94
|
+
font-weight: 500;
|
|
95
|
+
background-color: #f5f5f5;
|
|
96
|
+
color: #262626;
|
|
97
|
+
font-size: 14px;
|
|
98
|
+
padding: 12px 16px;
|
|
99
|
+
border-right: 1px solid #e8e8e8;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ant-descriptions-item-content {
|
|
103
|
+
background-color: #ffffff;
|
|
104
|
+
color: #595959;
|
|
105
|
+
font-size: 14px;
|
|
106
|
+
padding: 12px 16px;
|
|
107
|
+
word-break: break-word;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.ant-descriptions-row {
|
|
111
|
+
border-bottom: 1px solid #e8e8e8;
|
|
112
|
+
|
|
113
|
+
&:last-child {
|
|
114
|
+
border-bottom: none;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 空状态样式
|
|
123
|
+
.ant-empty {
|
|
124
|
+
padding: 60px 20px;
|
|
125
|
+
|
|
126
|
+
.ant-empty-description {
|
|
127
|
+
color: #8c8c8c;
|
|
128
|
+
font-size: 14px;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Tag 样式优化
|
|
133
|
+
.ant-tag {
|
|
134
|
+
margin: 0;
|
|
135
|
+
border-radius: 4px;
|
|
136
|
+
font-size: 13px;
|
|
137
|
+
padding: 2px 8px;
|
|
138
|
+
line-height: 20px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 链接样式
|
|
142
|
+
a {
|
|
143
|
+
color: #1890ff;
|
|
144
|
+
text-decoration: none;
|
|
145
|
+
transition: color 0.3s;
|
|
146
|
+
|
|
147
|
+
&:hover {
|
|
148
|
+
color: #40a9ff;
|
|
149
|
+
text-decoration: underline;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
&:active {
|
|
153
|
+
color: #096dd9;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 响应式设计
|
|
158
|
+
@media (max-width: 1200px) {
|
|
159
|
+
.detail-content {
|
|
160
|
+
.ant-col-md-8 {
|
|
161
|
+
max-width: 50%;
|
|
162
|
+
flex: 0 0 50%;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@media (max-width: 768px) {
|
|
168
|
+
margin: 4px 8px;
|
|
169
|
+
padding: 12px;
|
|
170
|
+
|
|
171
|
+
.detail-header {
|
|
172
|
+
margin-bottom: 12px;
|
|
173
|
+
|
|
174
|
+
.header-content {
|
|
175
|
+
gap: 12px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.header-title {
|
|
179
|
+
font-size: 16px;
|
|
180
|
+
|
|
181
|
+
.title-icon {
|
|
182
|
+
font-size: 18px;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.refresh-button {
|
|
187
|
+
height: 28px;
|
|
188
|
+
padding: 2px 8px;
|
|
189
|
+
font-size: 12px;
|
|
190
|
+
|
|
191
|
+
.anticon {
|
|
192
|
+
font-size: 11px;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.detail-content {
|
|
198
|
+
.ant-col-md-8,
|
|
199
|
+
.ant-col-md-12 {
|
|
200
|
+
max-width: 100%;
|
|
201
|
+
flex: 0 0 100%;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.detail-column-card {
|
|
205
|
+
margin-bottom: 16px;
|
|
206
|
+
|
|
207
|
+
.ant-descriptions {
|
|
208
|
+
&.ant-descriptions-bordered {
|
|
209
|
+
.ant-descriptions-item-label,
|
|
210
|
+
.ant-descriptions-item-content {
|
|
211
|
+
font-size: 13px;
|
|
212
|
+
padding: 10px 12px;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@media (max-width: 480px) {
|
|
221
|
+
margin: 2px 4px;
|
|
222
|
+
padding: 8px;
|
|
223
|
+
|
|
224
|
+
.detail-header {
|
|
225
|
+
.header-content {
|
|
226
|
+
flex-direction: column;
|
|
227
|
+
align-items: stretch;
|
|
228
|
+
gap: 8px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.header-title {
|
|
232
|
+
font-size: 15px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.refresh-button {
|
|
236
|
+
width: 100%;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.detail-content {
|
|
241
|
+
.detail-column-card {
|
|
242
|
+
.ant-descriptions {
|
|
243
|
+
&.ant-descriptions-bordered {
|
|
244
|
+
.ant-descriptions-item-label,
|
|
245
|
+
.ant-descriptions-item-content {
|
|
246
|
+
font-size: 12px;
|
|
247
|
+
padding: 8px 10px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.ant-descriptions-item-label {
|
|
251
|
+
width: 30%;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 加载状态样式
|
|
261
|
+
.ant-spin-container {
|
|
262
|
+
min-height: 200px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.ant-spin-nested-loading {
|
|
266
|
+
> div > .ant-spin {
|
|
267
|
+
max-height: none;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 自定义滚动条样式
|
|
272
|
+
.entity-detail-container .detail-content {
|
|
273
|
+
&::-webkit-scrollbar {
|
|
274
|
+
width: 6px;
|
|
275
|
+
height: 6px;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
&::-webkit-scrollbar-track {
|
|
279
|
+
background: #f0f0f0;
|
|
280
|
+
border-radius: 3px;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
&::-webkit-scrollbar-thumb {
|
|
284
|
+
background: #bfbfbf;
|
|
285
|
+
border-radius: 3px;
|
|
286
|
+
transition: background 0.3s;
|
|
287
|
+
|
|
288
|
+
&:hover {
|
|
289
|
+
background: #8c8c8c;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# ObjectCardList 数据卡片列表组件
|
|
2
|
+
数据卡片列表组件用于展示数据信息,以卡片形式展示每个数据的姓名和手机号。组件使用 Ant Design 的 Card 组件,具有良好的视觉效果和交互体验。
|
|
3
|
+
|
|
4
|
+
## 功能特性
|
|
5
|
+
|
|
6
|
+
- 📱 响应式设计,支持多种屏幕尺寸
|
|
7
|
+
- 🎨 美观的卡片布局,支持悬停效果
|
|
8
|
+
- 🔄 自动加载数据,支持错误重试
|
|
9
|
+
- 📊 使用 neo-open-api 获取 customContact__c 数据
|
|
10
|
+
- 🎯 展示数据姓名和手机号信息
|
|
11
|
+
- 💫 加载状态和空状态处理
|
|
12
|
+
|
|
13
|
+
## 组件属性
|
|
14
|
+
|
|
15
|
+
| 属性名 | 类型 | 默认值 | 描述 |
|
|
16
|
+
|--------|------|--------|------|
|
|
17
|
+
| title | string | '数据卡片列表' | 组件标题 |
|
|
18
|
+
| data | any | - | 组件数据,包含用户信息和系统信息 |
|
|
19
|
+
|
|
20
|
+
## 数据源
|
|
21
|
+
|
|
22
|
+
组件通过 `neo-open-api` 工具函数获取数据:
|
|
23
|
+
|
|
24
|
+
- **数据表**: `customContact__c`
|
|
25
|
+
- **字段**: `id`, `name`, `phone__c`
|
|
26
|
+
|
|
27
|
+
## 样式特性
|
|
28
|
+
|
|
29
|
+
- 使用 Flexbox 布局,支持响应式设计
|
|
30
|
+
- 卡片悬停效果,提升用户体验
|
|
31
|
+
- 渐变色头像,美观大方
|
|
32
|
+
- 支持移动端适配
|
|
33
|
+
|
|
34
|
+
## 使用示例
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import ObjectCardList from './components/object-card-list';
|
|
38
|
+
|
|
39
|
+
// 在页面中使用
|
|
40
|
+
<ObjectCardList
|
|
41
|
+
title="我的数据"
|
|
42
|
+
data={amisData}
|
|
43
|
+
/>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 技术栈
|
|
47
|
+
|
|
48
|
+
- React 16.9+
|
|
49
|
+
- TypeScript
|
|
50
|
+
- Ant Design 4.9+
|
|
51
|
+
- SCSS
|
|
52
|
+
|
|
53
|
+
## 文件结构
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
object-card-list/
|
|
57
|
+
├── index.tsx # 主组件文件
|
|
58
|
+
├── model.ts # 组件配置和编辑器属性定义
|
|
59
|
+
├── style.scss # 组件样式文件
|
|
60
|
+
└── README.md # 组件说明文档
|
|
61
|
+
```
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Card, Row, Col, Spin, Empty, Avatar, Button } from 'antd';
|
|
3
|
+
import { UserOutlined, PhoneOutlined, ReloadOutlined } from '@ant-design/icons';
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import { xObject } from 'neo-open-api'; // Neo Open API
|
|
6
|
+
import './style.scss';
|
|
7
|
+
|
|
8
|
+
interface ObjectCardListProps {
|
|
9
|
+
title: string;
|
|
10
|
+
xObjectDataApi?: any;
|
|
11
|
+
data?: any;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ContactData {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
phone__c: string;
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ObjectCardListState {
|
|
22
|
+
objectDataList: ContactData[];
|
|
23
|
+
totalSize: number;
|
|
24
|
+
loading: boolean;
|
|
25
|
+
error: string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default class ObjectCardList extends React.PureComponent<
|
|
29
|
+
ObjectCardListProps,
|
|
30
|
+
ObjectCardListState
|
|
31
|
+
> {
|
|
32
|
+
constructor(props: ObjectCardListProps) {
|
|
33
|
+
super(props);
|
|
34
|
+
|
|
35
|
+
this.state = {
|
|
36
|
+
objectDataList: [],
|
|
37
|
+
totalSize: 0,
|
|
38
|
+
loading: false,
|
|
39
|
+
error: null,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
this.loadObjectData = this.loadObjectData.bind(this);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
componentDidMount() {
|
|
46
|
+
this.loadObjectData();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
componentDidUpdate(prevProps: ObjectCardListProps) {
|
|
50
|
+
const { xObjectDataApi } = this.props;
|
|
51
|
+
if (
|
|
52
|
+
xObjectDataApi?.xObjectApiKey !==
|
|
53
|
+
prevProps.xObjectDataApi?.xObjectApiKey ||
|
|
54
|
+
xObjectDataApi?.fields !== prevProps.xObjectDataApi?.fields
|
|
55
|
+
) {
|
|
56
|
+
this.loadObjectData();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async loadObjectData() {
|
|
61
|
+
this.setState({ loading: true, error: null });
|
|
62
|
+
const { xObjectDataApi } = this.props;
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
// 使用 Neo Open API 获取 customContact__c 数据
|
|
66
|
+
if (xObjectDataApi) {
|
|
67
|
+
const result = await xObject.query(xObjectDataApi);
|
|
68
|
+
|
|
69
|
+
if (result?.status) {
|
|
70
|
+
const records = result.data || [];
|
|
71
|
+
const totalSize = result.totalSize || 0;
|
|
72
|
+
this.setState({
|
|
73
|
+
objectDataList: records,
|
|
74
|
+
totalSize,
|
|
75
|
+
loading: false,
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
this.setState({
|
|
79
|
+
error: result?.msg || '获取数据数据失败',
|
|
80
|
+
loading: false,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch (error: any) {
|
|
85
|
+
this.setState({
|
|
86
|
+
error: error.message || '获取数据数据失败',
|
|
87
|
+
loading: false,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
renderObjectCard(object: ContactData, index: number) {
|
|
93
|
+
return (
|
|
94
|
+
<Col xs={24} sm={12} md={8} lg={6} xl={6} key={object.id || index}>
|
|
95
|
+
<Card
|
|
96
|
+
className="object-card"
|
|
97
|
+
hoverable
|
|
98
|
+
size="small"
|
|
99
|
+
style={{ marginBottom: 16 }}
|
|
100
|
+
>
|
|
101
|
+
<div className="object-card-content">
|
|
102
|
+
<div className="object-avatar">
|
|
103
|
+
<Avatar
|
|
104
|
+
size={48}
|
|
105
|
+
icon={<UserOutlined />}
|
|
106
|
+
className="avatar-icon"
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
<div className="object-info">
|
|
110
|
+
<div className="object-name">
|
|
111
|
+
<UserOutlined className="info-icon" />
|
|
112
|
+
<span className="name-text">
|
|
113
|
+
{object.name ||
|
|
114
|
+
object.accountName ||
|
|
115
|
+
object.productName ||
|
|
116
|
+
'未知姓名'}
|
|
117
|
+
</span>
|
|
118
|
+
</div>
|
|
119
|
+
<div className="object-phone">
|
|
120
|
+
<PhoneOutlined className="info-icon" />
|
|
121
|
+
<span className="phone-text">
|
|
122
|
+
{object.phone__c ||
|
|
123
|
+
object.phone ||
|
|
124
|
+
object.phoneNumber ||
|
|
125
|
+
'未填写手机号'}
|
|
126
|
+
</span>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</Card>
|
|
131
|
+
</Col>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
render() {
|
|
136
|
+
const { title } = this.props;
|
|
137
|
+
const { objectDataList, loading, error } = this.state;
|
|
138
|
+
const curAmisData = this.props.data || {};
|
|
139
|
+
const systemInfo = curAmisData.__NeoSystemInfo || {};
|
|
140
|
+
console.log('this.props:', this.props);
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div className="object-card-list-container">
|
|
144
|
+
<div className="card-list-header">
|
|
145
|
+
<div className="header-content">
|
|
146
|
+
<h3 className="header-title">
|
|
147
|
+
{title || '数据卡片列表'}
|
|
148
|
+
{systemInfo.tenantName ? `【${systemInfo.tenantName}】` : ''}
|
|
149
|
+
</h3>
|
|
150
|
+
<Button
|
|
151
|
+
type="primary"
|
|
152
|
+
icon={<ReloadOutlined />}
|
|
153
|
+
onClick={this.loadObjectData}
|
|
154
|
+
loading={loading}
|
|
155
|
+
className="refresh-button"
|
|
156
|
+
size="small"
|
|
157
|
+
>
|
|
158
|
+
刷新
|
|
159
|
+
</Button>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div className="card-list-content">
|
|
164
|
+
<Spin spinning={loading} tip="加载数据数据中...">
|
|
165
|
+
{error ? (
|
|
166
|
+
<div className="error-container">
|
|
167
|
+
<Empty
|
|
168
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
169
|
+
description={
|
|
170
|
+
<div>
|
|
171
|
+
<div style={{ color: '#ff4d4f', marginBottom: 8 }}>
|
|
172
|
+
{error}
|
|
173
|
+
</div>
|
|
174
|
+
<button
|
|
175
|
+
className="retry-button"
|
|
176
|
+
onClick={this.loadObjectData}
|
|
177
|
+
>
|
|
178
|
+
重新加载
|
|
179
|
+
</button>
|
|
180
|
+
</div>
|
|
181
|
+
}
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
) : objectDataList.length === 0 ? (
|
|
185
|
+
<Empty
|
|
186
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
187
|
+
description="暂无数据数据"
|
|
188
|
+
/>
|
|
189
|
+
) : (
|
|
190
|
+
<Row gutter={[16, 16]}>
|
|
191
|
+
{objectDataList.map((object, index) =>
|
|
192
|
+
this.renderObjectCard(object, index),
|
|
193
|
+
)}
|
|
194
|
+
</Row>
|
|
195
|
+
)}
|
|
196
|
+
</Spin>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|