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