neo-cmp-cli 1.13.0 → 1.13.2
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 +2 -2
- package/dist/index2.js +1 -1
- package/dist/module/neoInitByCopy.js +1 -1
- package/dist/neo/env.js +1 -1
- package/dist/neo/neoService.js +1 -1
- package/dist/package.json.js +1 -1
- package/dist/utils/projectUtils/getEntries.js +1 -1
- package/docs/Web/347/253/257 NeoEntityGrid /344/275/277/347/224/250/350/257/264/346/230/216.md" +4 -0
- package/package.json +1 -1
- package/template/antd-custom-cmp-template/package.json +1 -1
- package/template/asset-manage-template/package.json +2 -2
- package/template/echarts-custom-cmp-template/package.json +1 -1
- package/template/empty-custom-cmp-template/package.json +1 -1
- package/template/map-custom-cmp-template/package.json +1 -1
- package/template/neo-bi-cmps/.npmrc copy +1 -0
- package/template/neo-bi-cmps/package.json +1 -1
- package/template/neo-custom-cmp-template/package.json +1 -1
- package/template/neo-custom-cmp-template/src/components/entityTable__c/index.tsx +2 -1
- package/template/neo-h5-cmps/package.json +1 -1
- package/template/neo-order-cmps/package.json +1 -1
- package/template/{neo-web-cmps → neo-web-entity-grid}/neo.config.js +4 -0
- package/template/{neo-web-cmps → neo-web-entity-grid}/package.json +2 -2
- package/template/neo-web-entity-grid/src/components/createForm__c/README.md +176 -0
- package/template/neo-web-entity-grid/src/components/createForm__c/index.tsx +786 -0
- package/template/neo-web-entity-grid/src/components/createForm__c/model.ts +130 -0
- package/template/neo-web-entity-grid/src/components/createForm__c/style.scss +370 -0
- package/template/neo-web-entity-grid/src/components/entityGrid2__c/index.tsx +139 -0
- package/template/{neo-web-cmps/src/components/entityGrid4__c → neo-web-entity-grid/src/components/entityGrid2__c}/model.ts +20 -3
- package/template/{neo-web-cmps/src/components/entityGrid4__c → neo-web-entity-grid/src/components/entityGrid2__c}/style.scss +1 -1
- package/template/{neo-web-cmps → neo-web-entity-grid}/src/components/entityGrid3__c/index.tsx +17 -6
- package/template/{neo-web-cmps → neo-web-entity-grid}/src/components/entityGrid3__c/model.ts +3 -2
- package/template/{neo-web-cmps → neo-web-entity-grid}/src/components/entityGrid4__c/index.tsx +57 -8
- package/template/{neo-web-cmps/src/components/entityGrid2__c → neo-web-entity-grid/src/components/entityGrid4__c}/style.scss +9 -13
- package/template/{neo-web-cmps/src/components/entityGrid2__c → neo-web-entity-grid/src/components/entityGrid__c}/index.tsx +6 -4
- package/template/{neo-web-cmps → neo-web-entity-grid}/src/components/entityGrid__c/model.ts +1 -1
- package/template/neo-web-entity-grid/src/components/searchForm__c/README.md +144 -0
- package/template/neo-web-entity-grid/src/components/searchForm__c/index.tsx +667 -0
- package/template/neo-web-entity-grid/src/components/searchForm__c/model.ts +135 -0
- package/template/neo-web-entity-grid/src/components/searchForm__c/style.scss +370 -0
- package/template/react-custom-cmp-template/package.json +1 -1
- package/template/react-ts-custom-cmp-template/package.json +1 -1
- package/template/vue2-custom-cmp-template/package.json +1 -1
- package/template/neo-web-cmps/src/components/entityGrid__c/index.tsx +0 -77
- /package/template/{neo-web-cmps → neo-web-entity-grid}/.prettierrc.js +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/@types/neo-ui-common.d.ts +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/README.md +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/commitlint.config.js +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/public/css/base.css +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/public/scripts/app/bluebird.js +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/public/template.html +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/css/common.scss +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/css/mixin.scss +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/AIBtn.gif +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/NeoCRM.jpg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/aiLogo.png +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/card-list.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/contact-form.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/custom-form.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/custom-widget.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/data-list.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/detail.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/favicon.png +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/map.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/search.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/assets/img/table.svg +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/components/entityGrid3__c/style.scss +0 -0
- /package/template/{neo-web-cmps/src/components/entityGrid2__c → neo-web-entity-grid/src/components/entityGrid4__c}/model.ts +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/components/entityGrid__c/style.scss +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/utils/axiosFetcher.ts +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/utils/queryObjectData.ts +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/src/utils/xobjects.ts +0 -0
- /package/template/{neo-web-cmps → neo-web-entity-grid}/tsconfig.json +0 -0
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file SearchForm 自定义查询表单组件
|
|
3
|
+
* @description 基于 Neo 平台的 XObject 字段元数据渲染筛选表单,点击查询输出 conditions(type 1 等于 / type 3 包含)
|
|
4
|
+
*/
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import {
|
|
7
|
+
Form,
|
|
8
|
+
Input,
|
|
9
|
+
Select,
|
|
10
|
+
Button,
|
|
11
|
+
message,
|
|
12
|
+
Card,
|
|
13
|
+
DatePicker,
|
|
14
|
+
InputNumber,
|
|
15
|
+
Space,
|
|
16
|
+
Spin,
|
|
17
|
+
Empty,
|
|
18
|
+
Row,
|
|
19
|
+
Col,
|
|
20
|
+
} from 'antd';
|
|
21
|
+
import { SearchOutlined, ReloadOutlined } from '@ant-design/icons';
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
import { xObject } from 'neo-open-api'; // Neo Open API
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
import isEqual from 'lodash/isEqual';
|
|
26
|
+
// 引入 neo-ui-common / NeoEvent
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
import { NeoEvent } from 'neo-ui-common';
|
|
29
|
+
import './style.scss';
|
|
30
|
+
|
|
31
|
+
const { Option } = Select;
|
|
32
|
+
|
|
33
|
+
/** 单条查询条件(与 NeoEntityGrid additionalConditions 等约定一致:1 等于,3 包含) */
|
|
34
|
+
export interface CustomQueryCondition {
|
|
35
|
+
apiKey: string;
|
|
36
|
+
type: 1 | 3;
|
|
37
|
+
value: unknown;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** 点击查询时对外传递的自定义查询数据 */
|
|
41
|
+
export interface CustomQueryPayload {
|
|
42
|
+
xObjectApiKey: string;
|
|
43
|
+
conditions: CustomQueryCondition[];
|
|
44
|
+
data?: Object;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 组件属性接口
|
|
49
|
+
*/
|
|
50
|
+
interface SearchFormProps {
|
|
51
|
+
/** XObject 实体对象的 API Key,用于标识要操作的数据对象 */
|
|
52
|
+
xObjectDataApi: {
|
|
53
|
+
xObjectApiKey: string;
|
|
54
|
+
fields?: string[];
|
|
55
|
+
fieldDescList?: any[];
|
|
56
|
+
};
|
|
57
|
+
/** Neo 平台传递的数据,包含系统信息等 */
|
|
58
|
+
data?: any;
|
|
59
|
+
/** 表单标题 */
|
|
60
|
+
formTitle?: string;
|
|
61
|
+
/** 是否显示重置按钮 */
|
|
62
|
+
showResetButton?: boolean;
|
|
63
|
+
/** 表单列数(1列或2列) */
|
|
64
|
+
columnCount?: 1 | 2;
|
|
65
|
+
/** 查询提交后的回调(与 onSubmit 事件二选一或同时使用) */
|
|
66
|
+
onSuccess?: (data: CustomQueryPayload) => void;
|
|
67
|
+
/** 是否为自定义实体对象 */
|
|
68
|
+
custom?: boolean;
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 字段信息接口
|
|
74
|
+
*/
|
|
75
|
+
interface FieldInfo {
|
|
76
|
+
/** 字段名称 */
|
|
77
|
+
name: string;
|
|
78
|
+
/** 字段显示标签 */
|
|
79
|
+
label: string;
|
|
80
|
+
/** 字段 API Key */
|
|
81
|
+
apiKey: string;
|
|
82
|
+
/** 字段类型 */
|
|
83
|
+
type: string;
|
|
84
|
+
/** 字段项类型 */
|
|
85
|
+
itemType: string;
|
|
86
|
+
/** 复选框选项列表 */
|
|
87
|
+
checkitem: any[];
|
|
88
|
+
/** 下拉选择选项列表 */
|
|
89
|
+
selectitem?: any[];
|
|
90
|
+
/** 是否必填 */
|
|
91
|
+
required: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 组件状态接口
|
|
96
|
+
*/
|
|
97
|
+
interface SearchFormState {
|
|
98
|
+
/** 表单标题 */
|
|
99
|
+
title?: string;
|
|
100
|
+
/** 字段列表 */
|
|
101
|
+
fieldList: FieldInfo[];
|
|
102
|
+
/** 加载状态 */
|
|
103
|
+
loading: boolean;
|
|
104
|
+
/** 查询请求中状态 */
|
|
105
|
+
submitting: boolean;
|
|
106
|
+
/** 错误信息 */
|
|
107
|
+
error: string | null;
|
|
108
|
+
/** 表单实例 */
|
|
109
|
+
form: any;
|
|
110
|
+
/** 业务类型列表 */
|
|
111
|
+
entityTypeList: any[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 自定义查询表单:收集表单项 apiKey + value,并按字段类型映射查询运算符 type(输入类 3,下拉/日期/单选类 1)
|
|
116
|
+
*/
|
|
117
|
+
export default class SearchForm extends React.PureComponent<
|
|
118
|
+
SearchFormProps,
|
|
119
|
+
SearchFormState
|
|
120
|
+
> {
|
|
121
|
+
constructor(props: SearchFormProps) {
|
|
122
|
+
super(props);
|
|
123
|
+
|
|
124
|
+
// 初始化组件状态
|
|
125
|
+
this.state = {
|
|
126
|
+
fieldList: [],
|
|
127
|
+
loading: false,
|
|
128
|
+
submitting: false,
|
|
129
|
+
error: null,
|
|
130
|
+
form: null,
|
|
131
|
+
entityTypeList: [],
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// 绑定方法上下文
|
|
135
|
+
this.loadFieldList = this.loadFieldList.bind(this);
|
|
136
|
+
this.handleSubmit = this.handleSubmit.bind(this);
|
|
137
|
+
this.handleReset = this.handleReset.bind(this);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
componentDidMount() {
|
|
141
|
+
const { xObjectDataApi } = this.props;
|
|
142
|
+
const { xObjectApiKey } = xObjectDataApi || {};
|
|
143
|
+
|
|
144
|
+
if (xObjectApiKey) {
|
|
145
|
+
// 初始化字段列表和业务类型列表
|
|
146
|
+
this.getEntityTypeList(xObjectApiKey);
|
|
147
|
+
this.loadFieldList();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 组件更新后执行
|
|
153
|
+
* 当 xObjectApiKey 发生变化时重新加载字段列表
|
|
154
|
+
*/
|
|
155
|
+
async componentDidUpdate(prevProps: SearchFormProps) {
|
|
156
|
+
const { xObjectApiKey, fields } = this.props.xObjectDataApi || {};
|
|
157
|
+
const { xObjectApiKey: prevXObjectApiKey, fields: prevFields } =
|
|
158
|
+
prevProps.xObjectDataApi || {};
|
|
159
|
+
|
|
160
|
+
if (xObjectApiKey !== prevXObjectApiKey || !isEqual(fields, prevFields)) {
|
|
161
|
+
if (xObjectApiKey) {
|
|
162
|
+
await this.loadFieldList();
|
|
163
|
+
await this.getEntityTypeList(xObjectApiKey);
|
|
164
|
+
} else {
|
|
165
|
+
this.setState({
|
|
166
|
+
fieldList: [],
|
|
167
|
+
error: null,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 获取业务类型列表
|
|
175
|
+
* 用于下拉选择框的选项数据
|
|
176
|
+
*/
|
|
177
|
+
async getEntityTypeList(xObjectApiKey?: string) {
|
|
178
|
+
const { xObjectDataApi } = this.props;
|
|
179
|
+
const curXObjectApiKey = xObjectApiKey || xObjectDataApi?.xObjectApiKey;
|
|
180
|
+
try {
|
|
181
|
+
const result = await xObject.getEntityTypeList(curXObjectApiKey);
|
|
182
|
+
if (result && result.status) {
|
|
183
|
+
const records = result.data || [];
|
|
184
|
+
this.setState({
|
|
185
|
+
entityTypeList: records,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error('获取业务类型列表失败:', error);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 加载字段列表
|
|
195
|
+
* 从 Neo 平台获取 XObject 的字段描述信息
|
|
196
|
+
*/
|
|
197
|
+
async loadFieldList() {
|
|
198
|
+
const { xObjectDataApi } = this.props || {};
|
|
199
|
+
|
|
200
|
+
this.setState({ loading: true, error: null });
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
// 方式一:直接从 props.xObjectDataApi 中获取字段描述
|
|
204
|
+
if (xObjectDataApi && xObjectDataApi.fieldDescList) {
|
|
205
|
+
this.setState({
|
|
206
|
+
fieldList: xObjectDataApi.fieldDescList,
|
|
207
|
+
loading: false,
|
|
208
|
+
});
|
|
209
|
+
} else {
|
|
210
|
+
// 方式二:自行通过 OpenAPI SDK 获取字段描述
|
|
211
|
+
if (!xObjectDataApi.xObjectApiKey) {
|
|
212
|
+
this.setState({ loading: false });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const resultData = await xObject.getDesc(xObjectDataApi.xObjectApiKey);
|
|
216
|
+
if (resultData && resultData.status) {
|
|
217
|
+
const result = resultData.data || {};
|
|
218
|
+
const fieldList = result.fields || [];
|
|
219
|
+
this.setState({
|
|
220
|
+
fieldList,
|
|
221
|
+
title: result.label,
|
|
222
|
+
loading: false,
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
this.setState({
|
|
226
|
+
error: '获取字段列表失败',
|
|
227
|
+
loading: false,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.error('获取字段列表失败:', error);
|
|
233
|
+
message.error('获取字段列表失败');
|
|
234
|
+
this.setState({
|
|
235
|
+
error: '获取字段列表失败',
|
|
236
|
+
loading: false,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** 下拉、日期、单选/多选等:查询运算符为等于(1);其余按输入类处理为包含(3) */
|
|
242
|
+
private static getConditionType(fieldType: string): 1 | 3 {
|
|
243
|
+
const equalsTypes = new Set([
|
|
244
|
+
'entityType',
|
|
245
|
+
'entitytype',
|
|
246
|
+
'picklist',
|
|
247
|
+
'multipicklist',
|
|
248
|
+
'date',
|
|
249
|
+
'datetime',
|
|
250
|
+
'time',
|
|
251
|
+
]);
|
|
252
|
+
return equalsTypes.has(fieldType) ? 1 : 3;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private normalizeQueryValue(field: FieldInfo, raw: unknown): unknown {
|
|
256
|
+
if (raw === undefined || raw === null) return raw;
|
|
257
|
+
if (Array.isArray(raw)) {
|
|
258
|
+
return raw.length === 0 ? raw : raw.join(',');
|
|
259
|
+
}
|
|
260
|
+
const t = field.type;
|
|
261
|
+
if (
|
|
262
|
+
(t === 'date' || t === 'datetime' || t === 'time') &&
|
|
263
|
+
raw !== '' &&
|
|
264
|
+
typeof raw === 'object' &&
|
|
265
|
+
typeof (raw as { valueOf?: () => number }).valueOf === 'function'
|
|
266
|
+
) {
|
|
267
|
+
return (raw as { valueOf: () => number }).valueOf();
|
|
268
|
+
}
|
|
269
|
+
if (
|
|
270
|
+
(t === 'date' || t === 'datetime' || t === 'time') &&
|
|
271
|
+
raw !== '' &&
|
|
272
|
+
!(typeof raw === 'number')
|
|
273
|
+
) {
|
|
274
|
+
const n = new Date(raw as string | Date).getTime();
|
|
275
|
+
return Number.isNaN(n) ? raw : n;
|
|
276
|
+
}
|
|
277
|
+
return raw;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private isEmptyQueryValue(v: unknown): boolean {
|
|
281
|
+
if (v === undefined || v === null) return true;
|
|
282
|
+
if (v === '') return true;
|
|
283
|
+
if (Array.isArray(v) && v.length === 0) return true;
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* 页面设计器事件:点击查询后触发,参数为自定义查询数据
|
|
289
|
+
*/
|
|
290
|
+
@NeoEvent.dispatch
|
|
291
|
+
onQuery(customSearchData?: CustomQueryPayload) {
|
|
292
|
+
// 触发一个广播事件
|
|
293
|
+
// console.log('触发了一个广播事件 customSearchEvent:', customSearchData);
|
|
294
|
+
// NeoEvent.broadcast('customSearchEvent', customSearchData);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 点击查询:校验表单,组装 apiKey + value + type,触发 onSubmit
|
|
299
|
+
*/
|
|
300
|
+
handleSubmit() {
|
|
301
|
+
const form = this.state.form;
|
|
302
|
+
if (!form) return;
|
|
303
|
+
|
|
304
|
+
const { xObjectApiKey } = this.props.xObjectDataApi || {};
|
|
305
|
+
if (!xObjectApiKey) {
|
|
306
|
+
message.error('请先选择要操作的对象');
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this.setState({ submitting: true });
|
|
311
|
+
|
|
312
|
+
form
|
|
313
|
+
.validateFields()
|
|
314
|
+
.then((values: Record<string, unknown>) => {
|
|
315
|
+
const { fieldList } = this.state;
|
|
316
|
+
|
|
317
|
+
const conditions: CustomQueryCondition[] = [];
|
|
318
|
+
|
|
319
|
+
Object.keys(values).forEach((apiKey) => {
|
|
320
|
+
const field = fieldList.find((f) => f.apiKey === apiKey);
|
|
321
|
+
if (!field) return;
|
|
322
|
+
|
|
323
|
+
const raw = values[apiKey];
|
|
324
|
+
if (this.isEmptyQueryValue(raw)) return;
|
|
325
|
+
|
|
326
|
+
const value = this.normalizeQueryValue(field, raw);
|
|
327
|
+
if (this.isEmptyQueryValue(value)) return;
|
|
328
|
+
|
|
329
|
+
conditions.push({
|
|
330
|
+
apiKey,
|
|
331
|
+
type: SearchForm.getConditionType(field.type),
|
|
332
|
+
value,
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
const payload: CustomQueryPayload = {
|
|
337
|
+
xObjectApiKey, // 冗余数据
|
|
338
|
+
conditions, // 冗余数据
|
|
339
|
+
data: { // 事件动作的入参数据
|
|
340
|
+
xObjectApiKey,
|
|
341
|
+
conditions
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
this.onQuery(payload);
|
|
346
|
+
if (this.props.onSuccess) {
|
|
347
|
+
this.props.onSuccess(payload);
|
|
348
|
+
}
|
|
349
|
+
})
|
|
350
|
+
.catch(() => {
|
|
351
|
+
/* 表单校验未通过 */
|
|
352
|
+
})
|
|
353
|
+
.finally(() => {
|
|
354
|
+
this.setState({ submitting: false });
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* 处理表单重置
|
|
360
|
+
*/
|
|
361
|
+
handleReset() {
|
|
362
|
+
this.state.form?.resetFields();
|
|
363
|
+
message.info('表单已重置');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 渲染表单内容
|
|
368
|
+
* 根据字段类型动态生成对应的输入组件
|
|
369
|
+
* @returns 表单 JSX 元素
|
|
370
|
+
*/
|
|
371
|
+
renderForm() {
|
|
372
|
+
const { fieldList, entityTypeList } = this.state;
|
|
373
|
+
const { xObjectApiKey, fields } = this.props.xObjectDataApi || {};
|
|
374
|
+
const { columnCount = 1 } = this.props;
|
|
375
|
+
|
|
376
|
+
let curFieldList = fieldList;
|
|
377
|
+
|
|
378
|
+
// 如果指定了 fields,则只显示指定的字段
|
|
379
|
+
if (fields && fields.length > 0) {
|
|
380
|
+
curFieldList = fieldList.filter((field) => fields.includes(field.apiKey));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// 如果没有选择对象,显示提示信息
|
|
384
|
+
if (!xObjectApiKey) {
|
|
385
|
+
return (
|
|
386
|
+
<Empty
|
|
387
|
+
description="请先选择要操作的对象"
|
|
388
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
389
|
+
/>
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// 如果字段列表为空,显示提示信息
|
|
394
|
+
if (curFieldList.length === 0) {
|
|
395
|
+
return (
|
|
396
|
+
<Empty
|
|
397
|
+
description="暂无可用字段"
|
|
398
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
399
|
+
/>
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const formItemLayout =
|
|
404
|
+
columnCount === 2
|
|
405
|
+
? {
|
|
406
|
+
labelCol: { span: 8 },
|
|
407
|
+
wrapperCol: { span: 16 },
|
|
408
|
+
}
|
|
409
|
+
: {
|
|
410
|
+
labelCol: { span: 4 },
|
|
411
|
+
wrapperCol: { span: 20 },
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
return (
|
|
415
|
+
<Form
|
|
416
|
+
ref={(form) => this.setState({ form })}
|
|
417
|
+
layout="horizontal"
|
|
418
|
+
{...formItemLayout}
|
|
419
|
+
>
|
|
420
|
+
<Row gutter={16}>
|
|
421
|
+
{curFieldList.map((field) => {
|
|
422
|
+
// 跳过 ID 字段,不需要在表单中显示
|
|
423
|
+
if (field.apiKey === 'id') return null;
|
|
424
|
+
|
|
425
|
+
let inputComponent;
|
|
426
|
+
const selectitem = field.selectitem || [];
|
|
427
|
+
const checkitem = field.checkitem || [];
|
|
428
|
+
|
|
429
|
+
// 根据字段类型生成对应的输入组件
|
|
430
|
+
switch (field.type) {
|
|
431
|
+
case 'entityType':
|
|
432
|
+
case 'entitytype':
|
|
433
|
+
// 业务类型选择器
|
|
434
|
+
inputComponent = (
|
|
435
|
+
<Select placeholder="请选择业务类型" allowClear>
|
|
436
|
+
{entityTypeList.map((item) => (
|
|
437
|
+
<Option
|
|
438
|
+
key={item.apiKey}
|
|
439
|
+
value={item.id}
|
|
440
|
+
disabled={!item.active}
|
|
441
|
+
>
|
|
442
|
+
{item.label}
|
|
443
|
+
</Option>
|
|
444
|
+
))}
|
|
445
|
+
</Select>
|
|
446
|
+
);
|
|
447
|
+
break;
|
|
448
|
+
case 'picklist':
|
|
449
|
+
// 单选下拉框
|
|
450
|
+
inputComponent = (
|
|
451
|
+
<Select placeholder={`请选择${field.label}`} allowClear>
|
|
452
|
+
{selectitem.map((item) => (
|
|
453
|
+
<Option key={item.apiKey} value={item.id}>
|
|
454
|
+
{item.label}
|
|
455
|
+
</Option>
|
|
456
|
+
))}
|
|
457
|
+
</Select>
|
|
458
|
+
);
|
|
459
|
+
break;
|
|
460
|
+
case 'textarea':
|
|
461
|
+
// 多行文本输入框
|
|
462
|
+
inputComponent = (
|
|
463
|
+
<Input.TextArea
|
|
464
|
+
placeholder={`请输入${field.label}`}
|
|
465
|
+
rows={3}
|
|
466
|
+
showCount
|
|
467
|
+
maxLength={500}
|
|
468
|
+
/>
|
|
469
|
+
);
|
|
470
|
+
break;
|
|
471
|
+
case 'multipicklist':
|
|
472
|
+
// 多选下拉框
|
|
473
|
+
inputComponent = (
|
|
474
|
+
<Select
|
|
475
|
+
placeholder={`请选择${field.label}`}
|
|
476
|
+
mode="multiple"
|
|
477
|
+
allowClear
|
|
478
|
+
>
|
|
479
|
+
{checkitem.map((item) => (
|
|
480
|
+
<Option key={item.apiKey} value={item.id}>
|
|
481
|
+
{item.label}
|
|
482
|
+
</Option>
|
|
483
|
+
))}
|
|
484
|
+
</Select>
|
|
485
|
+
);
|
|
486
|
+
break;
|
|
487
|
+
case 'datetime':
|
|
488
|
+
// 日期时间选择器
|
|
489
|
+
inputComponent = (
|
|
490
|
+
<DatePicker
|
|
491
|
+
placeholder={`请选择${field.label}`}
|
|
492
|
+
format={'YYYY/MM/DD HH:mm:ss'}
|
|
493
|
+
showTime={true}
|
|
494
|
+
style={{ width: '100%' }}
|
|
495
|
+
/>
|
|
496
|
+
);
|
|
497
|
+
break;
|
|
498
|
+
case 'date':
|
|
499
|
+
// 日期选择器
|
|
500
|
+
inputComponent = (
|
|
501
|
+
<DatePicker
|
|
502
|
+
placeholder={`请选择${field.label}`}
|
|
503
|
+
format={'YYYY/MM/DD'}
|
|
504
|
+
style={{ width: '100%' }}
|
|
505
|
+
/>
|
|
506
|
+
);
|
|
507
|
+
break;
|
|
508
|
+
case 'time':
|
|
509
|
+
// 时间选择器
|
|
510
|
+
inputComponent = (
|
|
511
|
+
<DatePicker
|
|
512
|
+
placeholder={`请选择${field.label}`}
|
|
513
|
+
format={'HH:mm:ss'}
|
|
514
|
+
showTime={true}
|
|
515
|
+
style={{ width: '100%' }}
|
|
516
|
+
/>
|
|
517
|
+
);
|
|
518
|
+
break;
|
|
519
|
+
case 'int':
|
|
520
|
+
case 'float':
|
|
521
|
+
// 数字输入框
|
|
522
|
+
inputComponent = (
|
|
523
|
+
<InputNumber
|
|
524
|
+
placeholder={`请输入${field.label}`}
|
|
525
|
+
style={{ width: '100%' }}
|
|
526
|
+
/>
|
|
527
|
+
);
|
|
528
|
+
break;
|
|
529
|
+
case 'email':
|
|
530
|
+
// 邮箱输入框
|
|
531
|
+
inputComponent = (
|
|
532
|
+
<Input placeholder={`请输入${field.label}`} type="email" />
|
|
533
|
+
);
|
|
534
|
+
break;
|
|
535
|
+
case 'url':
|
|
536
|
+
// URL 输入框
|
|
537
|
+
inputComponent = (
|
|
538
|
+
<Input placeholder={`请输入${field.label}`} type="url" />
|
|
539
|
+
);
|
|
540
|
+
break;
|
|
541
|
+
case 'phone':
|
|
542
|
+
// 电话号码输入框
|
|
543
|
+
inputComponent = (
|
|
544
|
+
<Input placeholder={`请输入${field.label}`} type="tel" />
|
|
545
|
+
);
|
|
546
|
+
break;
|
|
547
|
+
default:
|
|
548
|
+
// 默认文本输入框
|
|
549
|
+
inputComponent = (
|
|
550
|
+
<Input placeholder={`请输入${field.label}`} maxLength={200} />
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const colSpan = columnCount === 2 ? 12 : 24;
|
|
555
|
+
|
|
556
|
+
return (
|
|
557
|
+
<Col span={colSpan} key={field.apiKey}>
|
|
558
|
+
<Form.Item
|
|
559
|
+
name={field.apiKey}
|
|
560
|
+
label={field.label}
|
|
561
|
+
/*
|
|
562
|
+
required={field.required ?? false}
|
|
563
|
+
rules={[
|
|
564
|
+
{
|
|
565
|
+
required: field.required,
|
|
566
|
+
message: `请${
|
|
567
|
+
field.type === 'picklist' ||
|
|
568
|
+
field.type === 'multipicklist' ||
|
|
569
|
+
field.type === 'entityType' ||
|
|
570
|
+
field.type === 'entitytype' ||
|
|
571
|
+
field.type === 'date' ||
|
|
572
|
+
field.type === 'datetime' ||
|
|
573
|
+
field.type === 'time'
|
|
574
|
+
? '选择'
|
|
575
|
+
: '输入'
|
|
576
|
+
}${field.label}`,
|
|
577
|
+
},
|
|
578
|
+
]}
|
|
579
|
+
*/
|
|
580
|
+
>
|
|
581
|
+
{inputComponent}
|
|
582
|
+
</Form.Item>
|
|
583
|
+
</Col>
|
|
584
|
+
);
|
|
585
|
+
})}
|
|
586
|
+
</Row>
|
|
587
|
+
</Form>
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* 渲染组件
|
|
593
|
+
* @returns 组件 JSX 元素
|
|
594
|
+
*/
|
|
595
|
+
render() {
|
|
596
|
+
const { title, loading, submitting, error } = this.state;
|
|
597
|
+
const { formTitle, className, showResetButton = true, data } = this.props;
|
|
598
|
+
|
|
599
|
+
// 测试输出
|
|
600
|
+
console.log('this.props:', this.props);
|
|
601
|
+
|
|
602
|
+
const curAmisData = data || {};
|
|
603
|
+
const systemInfo = curAmisData.__NeoSystemInfo || {};
|
|
604
|
+
const { xObjectApiKey } = this.props.xObjectDataApi || {};
|
|
605
|
+
|
|
606
|
+
const displayTitle = formTitle || title || '自定义筛选条件';
|
|
607
|
+
|
|
608
|
+
return (
|
|
609
|
+
<div className={`searchForm__c ${className}`}>
|
|
610
|
+
<Card>
|
|
611
|
+
<div className="form-header">
|
|
612
|
+
<h3 className="form-title">
|
|
613
|
+
{displayTitle}
|
|
614
|
+
{systemInfo.tenantName ? `【${systemInfo.tenantName}】` : ''}
|
|
615
|
+
</h3>
|
|
616
|
+
</div>
|
|
617
|
+
|
|
618
|
+
<div className="form-content">
|
|
619
|
+
<Spin spinning={loading} tip="加载字段信息...">
|
|
620
|
+
{error ? (
|
|
621
|
+
<Empty
|
|
622
|
+
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
|
623
|
+
description={
|
|
624
|
+
<div>
|
|
625
|
+
<div style={{ color: '#ff4d4f', marginBottom: 8 }}>
|
|
626
|
+
{error}
|
|
627
|
+
</div>
|
|
628
|
+
<Button type="primary" onClick={this.loadFieldList}>
|
|
629
|
+
重新加载
|
|
630
|
+
</Button>
|
|
631
|
+
</div>
|
|
632
|
+
}
|
|
633
|
+
/>
|
|
634
|
+
) : (
|
|
635
|
+
<>
|
|
636
|
+
{this.renderForm()}
|
|
637
|
+
<div className="form-actions">
|
|
638
|
+
<Space size="middle">
|
|
639
|
+
{showResetButton && (
|
|
640
|
+
<Button
|
|
641
|
+
icon={<ReloadOutlined />}
|
|
642
|
+
onClick={this.handleReset}
|
|
643
|
+
disabled={submitting}
|
|
644
|
+
>
|
|
645
|
+
重置
|
|
646
|
+
</Button>
|
|
647
|
+
)}
|
|
648
|
+
<Button
|
|
649
|
+
type="primary"
|
|
650
|
+
icon={<SearchOutlined />}
|
|
651
|
+
onClick={this.handleSubmit}
|
|
652
|
+
loading={submitting}
|
|
653
|
+
disabled={!xObjectApiKey}
|
|
654
|
+
>
|
|
655
|
+
{submitting ? '查询中...' : '查询'}
|
|
656
|
+
</Button>
|
|
657
|
+
</Space>
|
|
658
|
+
</div>
|
|
659
|
+
</>
|
|
660
|
+
)}
|
|
661
|
+
</Spin>
|
|
662
|
+
</div>
|
|
663
|
+
</Card>
|
|
664
|
+
</div>
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
}
|