neo-cmp-cli 1.13.17 → 1.13.19

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 (91) hide show
  1. package/README.md +23 -3
  2. package/dist/index2.js +1 -1
  3. package/dist/neo/env.js +1 -1
  4. package/dist/neo/pushCmp.js +1 -1
  5. package/dist/package.json.js +1 -1
  6. package/package.json +3 -2
  7. package/template/asset-manage-template/docs/README.md +1 -232
  8. package/template/echarts-custom-cmp-template/package.json +1 -1
  9. package/template/neo-bi-cmps/package.json +1 -1
  10. package/template/neo-bi-cmps/src/components/filterBar__c/common.scss +1 -1
  11. package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +18 -10
  12. package/template/neo-bi-cmps/src/components/filterBar__c/model.ts +8 -2
  13. package/template/neo-bi-cmps/src/components/targetNumber__c/model.ts +1 -1
  14. package/template/neo-bi-cmps/src/utils/common.ts +18 -20
  15. package/template/neo-bi-cmps/src/utils/filter2chartFilter.ts +4 -6
  16. package/template/neo-bi-cmps/src/utils/pipelineFunnel.ts +4 -2
  17. package/template/neo-bi-cmps/src/utils/simpleTable.tsx +21 -16
  18. package/template/neo-custom-cmp-template/docs/README.md +0 -231
  19. package/template/neo-custom-cmp-template/package.json +1 -1
  20. package/template/neo-h5-cmps/src/components/entityList__c/index.tsx +1 -2
  21. package/template/neo-h5-cmps/src/components/entityTabs__c/index.tsx +1 -1
  22. package/template/neo-h5-cmps/src/components/globalSearchInput__c/index.tsx +1 -1
  23. package/template/neo-h5-cmps/src/components/openChatPageBtn__c/index.tsx +1 -2
  24. package/template/neo-pipeline-cmps/neo.config.js +11 -0
  25. package/template/neo-pipeline-cmps/src/assets/css/common.scss +16 -16
  26. package/template/neo-pipeline-cmps/src/assets/css/mixin.scss +5 -5
  27. package/template/neo-pipeline-cmps/src/components/filterBar__c/README.md +9 -9
  28. package/template/neo-pipeline-cmps/src/components/filterBar__c/common.scss +5 -5
  29. package/template/neo-pipeline-cmps/src/components/filterBar__c/index.tsx +47 -46
  30. package/template/neo-pipeline-cmps/src/components/filterBar__c/model.ts +22 -12
  31. package/template/neo-pipeline-cmps/src/components/filterBar__c/style.scss +1 -1
  32. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/README.md +17 -17
  33. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/index.tsx +24 -22
  34. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/model.ts +31 -18
  35. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/reset.scss +4 -0
  36. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/index.tsx +33 -26
  37. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/model.ts +9 -9
  38. package/template/neo-pipeline-cmps/src/components/simpleTable__c/README.md +53 -54
  39. package/template/neo-pipeline-cmps/src/components/simpleTable__c/common.scss +5 -5
  40. package/template/neo-pipeline-cmps/src/components/simpleTable__c/index.tsx +70 -68
  41. package/template/neo-pipeline-cmps/src/components/simpleTable__c/model.ts +41 -41
  42. package/template/neo-pipeline-cmps/src/components/simpleTable__c/style.scss +2 -3
  43. package/template/neo-pipeline-cmps/src/components/stageSwitch__c/README.md +15 -15
  44. package/template/neo-pipeline-cmps/src/components/stageSwitch__c/index.tsx +35 -33
  45. package/template/neo-pipeline-cmps/src/components/stageSwitch__c/model.ts +29 -16
  46. package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/README.md +18 -18
  47. package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/index.tsx +20 -20
  48. package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/model.ts +34 -19
  49. package/template/neo-pipeline-cmps/src/utils/common.ts +14 -14
  50. package/template/neo-pipeline-cmps/src/utils/filter2chartFilter.ts +21 -23
  51. package/template/neo-pipeline-cmps/src/utils/filterBar.ts +14 -14
  52. package/template/neo-pipeline-cmps/src/utils/pipelineFunnel.ts +5 -5
  53. package/template/neo-pipeline-cmps/src/utils/queryByCustomSQL.ts +26 -22
  54. package/template/neo-pipeline-cmps/src/utils/requestDebounce.ts +3 -3
  55. package/template/neo-pipeline-cmps/src/utils/simpleTable.tsx +31 -26
  56. package/template/neo-pipeline-cmps/src/utils/stageSwitch.ts +1 -1
  57. package/template/neo-pipeline-cmps/src/utils/stageTimeChart.ts +5 -5
  58. package/template/neo-pipeline-cmps/src/utils/targetNumber.ts +2 -2
  59. package/template/neo-web-entity-grid/src/components/createForm__c/index.tsx +271 -259
  60. package/template/neo-web-entity-grid/src/components/createForm__c/model.ts +17 -3
  61. package/template/neo-web-entity-grid/src/components/createForm__c/resetAntd.scss +0 -1
  62. package/template/neo-web-entity-grid/src/components/createForm__c/style.scss +1 -1
  63. package/template/neo-web-entity-grid/src/components/entityGrid2__c/index.tsx +5 -1
  64. package/template/neo-web-entity-grid/src/components/entityGrid2__c/model.ts +4 -3
  65. package/template/neo-web-entity-grid/src/components/entityGrid3__c/index.tsx +1 -1
  66. package/template/neo-web-entity-grid/src/components/searchForm__c/index.tsx +4 -3
  67. package/template/neo-web-entity-grid/src/components/searchForm__c/model.ts +9 -4
  68. package/template/neo-web-entity-grid/src/components/searchForm__c/style.scss +2 -1
  69. package/template/neo-web-form/package.json +1 -1
  70. package/template/neo-web-form/src/components/batchAddTable__c/index.tsx +179 -59
  71. package/template/neo-web-form/src/components/batchAddTable__c/model.ts +12 -14
  72. package/template/neo-web-form/src/components/listSummary__c/index.tsx +6 -5
  73. package/template/react-custom-cmp-template/package.json +1 -1
  74. package/template/asset-manage-template/src/utils/axiosFetcher.ts +0 -37
  75. package/template/asset-manage-template/src/utils/queryObjectData.ts +0 -112
  76. package/template/asset-manage-template/src/utils/xobjects.ts +0 -162
  77. package/template/neo-custom-cmp-template/src/utils/axiosFetcher.ts +0 -37
  78. package/template/neo-custom-cmp-template/src/utils/queryObjectData.ts +0 -112
  79. package/template/neo-custom-cmp-template/src/utils/xobjects.ts +0 -162
  80. package/template/neo-h5-cmps/src/utils/axiosFetcher.ts +0 -37
  81. package/template/neo-h5-cmps/src/utils/queryObjectData.ts +0 -112
  82. package/template/neo-h5-cmps/src/utils/xobjects.ts +0 -167
  83. package/template/neo-order-cmps/src/utils/axiosFetcher.ts +0 -37
  84. package/template/neo-order-cmps/src/utils/queryObjectData.ts +0 -112
  85. package/template/neo-order-cmps/src/utils/xobjects.ts +0 -162
  86. package/template/neo-web-entity-grid/src/utils/axiosFetcher.ts +0 -37
  87. package/template/neo-web-entity-grid/src/utils/queryObjectData.ts +0 -112
  88. package/template/neo-web-entity-grid/src/utils/xobjects.ts +0 -167
  89. package/template/neo-web-form/src/utils/axiosFetcher.ts +0 -37
  90. package/template/neo-web-form/src/utils/queryObjectData.ts +0 -112
  91. package/template/neo-web-form/src/utils/xobjects.ts +0 -167
@@ -67,14 +67,15 @@ export class NeoEntityGridModel {
67
67
  apiKey: 'handleCustomSearchEvent',
68
68
  label: '更新筛选条件',
69
69
  helpTextKey: '更新自定义筛选条件',
70
- funcInParams: [ // 定义组件函数入参
70
+ funcInParams: [
71
+ // 定义组件函数入参
71
72
  {
72
73
  apiKey: 'eventData',
73
74
  label: '自定义筛选条件',
74
75
  type: 'Array',
75
- required: true
76
+ required: true,
76
77
  },
77
- ]
78
+ ],
78
79
  },
79
80
  ];
80
81
 
@@ -61,7 +61,7 @@ export default class NeoEntityGridCmp extends React.PureComponent<NeoEntityGridP
61
61
  objectApiKey={objectApiKey || 'account'}
62
62
  pattern={'pickView'} // Picker 列表(选择器)
63
63
  referData={referData}
64
- selectionMode={selectionMode ?? "single"} // 多选模式
64
+ selectionMode={selectionMode ?? 'single'} // 多选模式
65
65
  shouldCloseDialog={restProps.shouldCloseDialog ?? true}
66
66
  onRowSelected={(data: any, event: any) => {
67
67
  const selectedIds = data.map(({ data }: any) => data.id);
@@ -335,10 +335,11 @@ export default class SearchForm extends React.PureComponent<
335
335
  const payload: CustomQueryPayload = {
336
336
  xObjectApiKey, // 冗余数据
337
337
  conditions, // 冗余数据
338
- data: { // 事件动作的入参数据
338
+ data: {
339
+ // 事件动作的入参数据
339
340
  xObjectApiKey,
340
- conditions
341
- }
341
+ conditions,
342
+ },
342
343
  };
343
344
 
344
345
  this.onQuery(payload);
@@ -66,10 +66,15 @@ export class SearchFormModel {
66
66
  label: '点击查询后',
67
67
  helpText:
68
68
  '点击「查询」后触发;事件参数为 { xObjectApiKey, conditions },conditions 每项含 apiKey、type(1 等于 / 3 包含)、value',
69
- eventParams1: // 测试使用:定义事件触发时接收到的事件数据格式
70
- '[{"apiKey":"eventParam","label":"当前表单数据","type":"Object"}]',
71
- eventParams: // 定义事件触发时接收到的事件数据格式
72
- '[{"apiKey":"eventParam","children":[{"apiKey":"data","label":"当前表单数据","type":"Object"}],"label":"事件入参","type":"Object"}]',
69
+ // 定义事件触发时接收到的事件数据格式
70
+ eventParams: [
71
+ {
72
+ apiKey: 'eventParam',
73
+ children: [{ apiKey: 'data', label: '当前表单数据', type: 'Object' }],
74
+ label: '事件入参',
75
+ type: 'Object',
76
+ },
77
+ ],
73
78
  },
74
79
  ];
75
80
 
@@ -189,7 +189,8 @@
189
189
  font-weight: 400;
190
190
  min-width: auto;
191
191
  margin-left: 10px;
192
- transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
192
+ transition: border-color 0.2s ease, background 0.2s ease,
193
+ box-shadow 0.2s ease;
193
194
 
194
195
  &:first-child {
195
196
  margin-left: 0;
@@ -53,7 +53,7 @@
53
53
  "@types/react-dom": "^16.9.15",
54
54
  "husky": "^4.2.5",
55
55
  "lint-staged": "^10.2.9",
56
- "neo-cmp-cli": "^1.13.17",
56
+ "neo-cmp-cli": "^1.13.18",
57
57
  "prettier": "^2.0.5"
58
58
  },
59
59
  "overrides": {
@@ -83,6 +83,14 @@ interface BatchAddTableState {
83
83
  entityTypeList: any[];
84
84
  submitting: boolean;
85
85
  modalVisible: boolean;
86
+ /** Excel 导入 loading 状态 */
87
+ importLoading: boolean;
88
+ /** 导入进度信息 */
89
+ importProgress: { current: number; total: number } | null;
90
+ /** 当前页码 */
91
+ currentPage: number;
92
+ /** 每页条数 */
93
+ pageSize: number;
86
94
  }
87
95
 
88
96
  let rowKeySeed = 0;
@@ -145,6 +153,10 @@ export default class BatchAddTable extends React.PureComponent<
145
153
  entityTypeList: [],
146
154
  submitting: false,
147
155
  modalVisible: false,
156
+ importLoading: false,
157
+ importProgress: null,
158
+ currentPage: 1,
159
+ pageSize: 100,
148
160
  };
149
161
  this.loadFieldList = this.loadFieldList.bind(this);
150
162
  this.getEntityTypeList = this.getEntityTypeList.bind(this);
@@ -279,9 +291,14 @@ export default class BatchAddTable extends React.PureComponent<
279
291
  message.warning('暂无可用字段');
280
292
  return;
281
293
  }
282
- this.setState((prev) => ({
283
- rows: [...prev.rows, emptyRowForFields(visible)],
284
- }));
294
+ const { rows, pageSize } = this.state;
295
+ const newRows = [...rows, emptyRowForFields(visible)];
296
+ // 计算新增后的最后一页页码
297
+ const lastPage = Math.ceil(newRows.length / pageSize);
298
+ this.setState({
299
+ rows: newRows,
300
+ currentPage: lastPage,
301
+ });
285
302
  }
286
303
 
287
304
  handleCellChange(rowKey: string, apiKey: string, value: any) {
@@ -315,17 +332,11 @@ export default class BatchAddTable extends React.PureComponent<
315
332
  (it) => it.id === raw || String(it.id) === s,
316
333
  );
317
334
  if (byId) return byId.id;
318
- const byLabel = entityTypeList.find(
319
- (it) => String(it.label).trim() === s,
320
- );
335
+ const byLabel = entityTypeList.find((it) => String(it.label).trim() === s);
321
336
  return byLabel ? byLabel.id : raw;
322
337
  }
323
338
 
324
- parseImportedCell(
325
- field: FieldInfo,
326
- raw: any,
327
- entityTypeList: any[],
328
- ): any {
339
+ parseImportedCell(field: FieldInfo, raw: any, entityTypeList: any[]): any {
329
340
  if (raw === undefined || raw === null || raw === '') return undefined;
330
341
  if (raw instanceof Date) {
331
342
  if (
@@ -413,72 +424,132 @@ export default class BatchAddTable extends React.PureComponent<
413
424
  const ws = XLSX.utils.aoa_to_sheet([headers]); // 将标题行转换为工作表
414
425
  const wb = XLSX.utils.book_new(); // 创建新的工作簿
415
426
  XLSX.utils.book_append_sheet(wb, ws, '导入模板'); // 将工作表添加到工作簿
416
- const name = `${this.props.xObjectDataApi?.xObjectApiKey || 'data'}_导入模板.xlsx`; // 生成文件名
427
+ const name = `${
428
+ this.props.xObjectDataApi?.xObjectApiKey || 'data'
429
+ }_导入模板.xlsx`; // 生成文件名
417
430
  XLSX.writeFile(wb, name); // 将工作簿写入文件
418
431
  message.success('模板已下载');
419
432
  }
420
433
 
434
+ /**
435
+ * 分批处理导入数据,避免大数据量阻塞 UI
436
+ */
437
+ private async processImportData(
438
+ rowsAoA: any[][],
439
+ fields: FieldInfo[],
440
+ colMap: Record<string, number>,
441
+ entityTypeList: any[],
442
+ onProgress: (current: number, total: number) => void,
443
+ ): Promise<RowRecord[]> {
444
+ const newRows: RowRecord[] = [];
445
+ const total = rowsAoA.length - 1; // 排除表头
446
+ const batchSize = 100; // 每批处理 100 行
447
+
448
+ for (let r = 1; r < rowsAoA.length; r++) {
449
+ const line = rowsAoA[r];
450
+ if (!line || !line.some((c) => c !== '' && c != null)) continue;
451
+
452
+ const row: RowRecord = { _rowKey: nextRowKey() };
453
+ fields.forEach((f) => {
454
+ const idx = colMap[f.apiKey];
455
+ const raw = idx !== undefined ? line[idx] : undefined;
456
+ row[f.apiKey] = this.parseImportedCell(f, raw, entityTypeList);
457
+ });
458
+ newRows.push(row);
459
+
460
+ // 每处理 batchSize 行,让出主线程并更新进度
461
+ if (r % batchSize === 0) {
462
+ onProgress(r - 1, total);
463
+ await new Promise((resolve) => setTimeout(resolve, 0));
464
+ }
465
+ }
466
+
467
+ onProgress(total, total);
468
+ return newRows;
469
+ }
470
+
421
471
  handleImportBeforeUpload(file: File) {
422
472
  const fields = this.getVisibleFields();
423
473
  if (!fields.length) {
424
474
  message.warning('暂无可用字段');
425
475
  return false;
426
476
  }
477
+
478
+ // 设置导入 loading 状态
479
+ this.setState({
480
+ importLoading: true,
481
+ importProgress: { current: 0, total: 0 },
482
+ });
483
+
427
484
  const reader = new FileReader();
428
- reader.onload = (e) => {
485
+ reader.onload = async (e) => {
429
486
  try {
430
- const data = new Uint8Array(e.target?.result as ArrayBuffer); // 将文件内容转换为 Uint8Array
431
- const wb = XLSX.read(data, { type: 'array', cellDates: true }); // 读取 Excel 文件
432
- const sheetName = wb.SheetNames[0]; // 获取工作表名称
487
+ const data = new Uint8Array(e.target?.result as ArrayBuffer);
488
+ const wb = XLSX.read(data, { type: 'array', cellDates: true });
489
+ const sheetName = wb.SheetNames[0];
433
490
  if (!sheetName) {
434
491
  message.error('Excel 中未找到工作表');
492
+ this.setState({ importLoading: false, importProgress: null });
435
493
  return;
436
494
  }
437
- const sheet = wb.Sheets[sheetName]; // 获取工作表
438
- const rowsAoA: any[][] = XLSX.utils.sheet_to_json(sheet, { // 将工作表转换为 JSON 数组
439
- header: 1, // 使用第一行作为标题行
440
- raw: true, // 保持原始数据格式
441
- defval: '', // 默认值
442
- }) as any[][]; // 将 JSON 数组转换为 any[][] 类型
495
+ const sheet = wb.Sheets[sheetName];
496
+ const rowsAoA: any[][] = XLSX.utils.sheet_to_json(sheet, {
497
+ header: 1,
498
+ raw: true,
499
+ defval: '',
500
+ }) as any[][];
443
501
  if (!rowsAoA.length) {
444
502
  message.error('Excel 内容为空');
503
+ this.setState({ importLoading: false, importProgress: null });
445
504
  return;
446
505
  }
447
506
  const headerRow = rowsAoA[0] || [];
448
- const colMap = this.buildHeaderIndexMap(headerRow, fields); // 构建列索引映射
449
- const missing = fields.filter((f) => colMap[f.apiKey] === undefined); // 过滤出未匹配的字段
507
+ const colMap = this.buildHeaderIndexMap(headerRow, fields);
508
+ const missing = fields.filter((f) => colMap[f.apiKey] === undefined);
450
509
  if (missing.length) {
451
510
  message.error(
452
511
  `表头无法匹配字段:${missing.map((m) => m.label).join('、')}`,
453
512
  );
513
+ this.setState({ importLoading: false, importProgress: null });
454
514
  return;
455
515
  }
456
516
  const { entityTypeList } = this.state;
457
- const newRows: RowRecord[] = [];
458
- for (let r = 1; r < rowsAoA.length; r++) {
459
- const line = rowsAoA[r];
460
- if (!line || !line.some((c) => c !== '' && c != null)) continue;
461
- const row: RowRecord = { _rowKey: nextRowKey() };
462
- fields.forEach((f) => {
463
- const idx = colMap[f.apiKey];
464
- const raw = idx !== undefined ? line[idx] : undefined;
465
- row[f.apiKey] = this.parseImportedCell(f, raw, entityTypeList); // 解析导入的单元格值
466
- });
467
- newRows.push(row);
468
- }
517
+
518
+ // 使用分批处理解析数据
519
+ const newRows = await this.processImportData(
520
+ rowsAoA,
521
+ fields,
522
+ colMap,
523
+ entityTypeList,
524
+ (current, total) => {
525
+ this.setState({ importProgress: { current, total } });
526
+ },
527
+ );
528
+
469
529
  if (!newRows.length) {
470
530
  message.warning('未解析到有效数据行');
531
+ this.setState({ importLoading: false, importProgress: null });
471
532
  return;
472
533
  }
534
+
473
535
  this.setState((prev) => ({
474
536
  rows: [...prev.rows, ...newRows],
537
+ importLoading: false,
538
+ importProgress: null,
539
+ // 导入完成后跳转到第一页,展示新导入的数据
540
+ currentPage: 1,
475
541
  }));
476
542
  message.success(`已导入 ${newRows.length} 行`);
477
543
  } catch (err) {
478
544
  console.error(err);
479
545
  message.error('解析 Excel 失败');
546
+ this.setState({ importLoading: false, importProgress: null });
480
547
  }
481
548
  };
549
+ reader.onerror = () => {
550
+ message.error('读取文件失败');
551
+ this.setState({ importLoading: false, importProgress: null });
552
+ };
482
553
  reader.readAsArrayBuffer(file);
483
554
  return false;
484
555
  }
@@ -556,7 +627,13 @@ export default class BatchAddTable extends React.PureComponent<
556
627
  const cloned = this.cloneRowRecord(record, fields);
557
628
  const newRows = [...this.state.rows];
558
629
  newRows.splice(idx + 1, 0, cloned);
559
- this.setState({ rows: newRows });
630
+ // 计算复制行所在的页码
631
+ const { pageSize, currentPage } = this.state;
632
+ const copiedRowIndex = idx + 1;
633
+ const copiedRowPage = Math.floor(copiedRowIndex / pageSize) + 1;
634
+ // 如果复制的行不在当前页,跳转到复制的行所在页
635
+ const newPage = copiedRowPage !== currentPage ? copiedRowPage : currentPage;
636
+ this.setState({ rows: newRows, currentPage: newPage });
560
637
  message.success('已在本行下方复制一行');
561
638
  }
562
639
 
@@ -566,10 +643,22 @@ export default class BatchAddTable extends React.PureComponent<
566
643
  if (newRows.length === 0 && fields.length) {
567
644
  newRows.push(emptyRowForFields(fields));
568
645
  }
569
- this.setState({ rows: newRows });
646
+ // 删除后重新计算当前页码,避免当前页超出范围
647
+ const { pageSize, currentPage } = this.state;
648
+ const totalPages = Math.ceil(newRows.length / pageSize) || 1;
649
+ const newCurrentPage = Math.min(currentPage, totalPages);
650
+ this.setState({ rows: newRows, currentPage: newCurrentPage });
570
651
  message.success('已删除该行');
571
652
  }
572
653
 
654
+ /** 分页变化处理 */
655
+ handlePageChange = (page: number, pageSize?: number) => {
656
+ this.setState({
657
+ currentPage: page,
658
+ ...(pageSize ? { pageSize } : {}),
659
+ } as BatchAddTableState);
660
+ };
661
+
573
662
  openModal() {
574
663
  this.setState({ modalVisible: true });
575
664
  }
@@ -682,11 +771,7 @@ export default class BatchAddTable extends React.PureComponent<
682
771
  style={{ minWidth: 140 }}
683
772
  >
684
773
  {entityTypeList.map((item) => (
685
- <Option
686
- key={item.apiKey}
687
- value={item.id}
688
- disabled={!item.active}
689
- >
774
+ <Option key={item.apiKey} value={item.id} disabled={!item.active}>
690
775
  {item.label}
691
776
  </Option>
692
777
  ))}
@@ -819,7 +904,17 @@ export default class BatchAddTable extends React.PureComponent<
819
904
  }
820
905
 
821
906
  render() {
822
- const { loading, error, rows, submitting, title } = this.state;
907
+ const {
908
+ loading,
909
+ error,
910
+ rows,
911
+ submitting,
912
+ title,
913
+ importLoading,
914
+ importProgress,
915
+ currentPage,
916
+ pageSize,
917
+ } = this.state;
823
918
  const { tableTitle, className, data } = this.props;
824
919
  const curAmisData = data || {};
825
920
  const systemInfo = curAmisData.__NeoSystemInfo || {};
@@ -876,12 +971,15 @@ export default class BatchAddTable extends React.PureComponent<
876
971
  ),
877
972
  });
878
973
 
879
- const displayTitle =
880
- tableTitle || title || '批量新增数据';
974
+ // 计算分页数据
975
+ const startIndex = (currentPage - 1) * pageSize;
976
+ const endIndex = startIndex + pageSize;
977
+ const paginatedRows = rows.slice(startIndex, endIndex);
978
+
979
+ const displayTitle = tableTitle || title || '批量新增数据';
881
980
  const batchImportButtonTitle =
882
981
  this.props.batchImportButtonTitle ?? '批量导入';
883
- const batchImportButtonAlign =
884
- this.props.batchImportButtonAlign ?? 'right';
982
+ const batchImportButtonAlign = this.props.batchImportButtonAlign ?? 'right';
885
983
 
886
984
  const showModalFooter = !error && !!xObjectApiKey && fields.length > 0;
887
985
 
@@ -967,14 +1065,16 @@ export default class BatchAddTable extends React.PureComponent<
967
1065
  accept=".xlsx,.xls"
968
1066
  showUploadList={false}
969
1067
  beforeUpload={this.handleImportBeforeUpload}
1068
+ disabled={importLoading}
970
1069
  >
971
1070
  <Button
972
1071
  size="small"
973
1072
  className="batch-add-modal-toolbar-btn"
974
1073
  icon={<UploadOutlined />}
975
- disabled={!xObjectApiKey || !fields.length}
1074
+ loading={importLoading}
1075
+ disabled={!xObjectApiKey || !fields.length || importLoading}
976
1076
  >
977
- Excel 导入
1077
+ {importLoading ? '导入中...' : 'Excel 导入'}
978
1078
  </Button>
979
1079
  </Upload>
980
1080
  </Space>
@@ -1008,15 +1108,35 @@ export default class BatchAddTable extends React.PureComponent<
1008
1108
  />
1009
1109
  ) : (
1010
1110
  <div className="table-wrap">
1011
- <Table
1012
- rowKey="_rowKey"
1013
- columns={columns as any}
1014
- dataSource={rows}
1015
- pagination={false}
1016
- scroll={{ x: 'max-content' }}
1017
- bordered
1018
- size="small"
1019
- />
1111
+ <Spin
1112
+ spinning={importLoading}
1113
+ tip={
1114
+ importProgress
1115
+ ? `正在加载导入数据... (${importProgress.current}/${importProgress.total})`
1116
+ : '正在加载导入数据...'
1117
+ }
1118
+ size="large"
1119
+ >
1120
+ <Table
1121
+ rowKey="_rowKey"
1122
+ columns={columns as any}
1123
+ dataSource={paginatedRows}
1124
+ pagination={{
1125
+ current: currentPage,
1126
+ pageSize: pageSize,
1127
+ total: rows.length,
1128
+ showSizeChanger: true,
1129
+ showQuickJumper: true,
1130
+ pageSizeOptions: ['50', '100', '200', '500'],
1131
+ showTotal: (total) => `共 ${total} 条`,
1132
+ onChange: this.handlePageChange,
1133
+ onShowSizeChange: this.handlePageChange,
1134
+ }}
1135
+ scroll={{ x: 'max-content', y: 'calc(100vh - 400px)' }}
1136
+ bordered
1137
+ size="small"
1138
+ />
1139
+ </Spin>
1020
1140
  </div>
1021
1141
  )}
1022
1142
  </Spin>
@@ -21,7 +21,7 @@ export class BatchAddTableModel {
21
21
  batchImportButtonTitle: '批量导入',
22
22
  batchImportButtonAlign: 'right',
23
23
  xObjectDataApi: {
24
- xObjectApiKey: 'opportunityProduct',
24
+ xObjectApiKey: 'opportunityProduct', // 商机明细
25
25
  fields: [],
26
26
  },
27
27
  };
@@ -31,19 +31,17 @@ export class BatchAddTableModel {
31
31
  apiKey: 'onSubmit',
32
32
  label: '点击提交',
33
33
  helpText: '点击提交按钮时触发,事件参数包含当前表格中所有行数据',
34
- eventParams1:
35
- [{
36
- "apiKey": "eventParam",
37
- "children":
38
- [
39
- { "apiKey": "xObjectApiKey", "label": "实体 API Key", "type": "String" },
40
- { "apiKey": "rows", "label": "表格数据列表", "type": "Array" }
41
- ],
42
- "label": "事件入参",
43
- "type": "Object"
44
- }],
45
- eventParams:
46
- '[{"apiKey":"eventParam","children":[{"apiKey":"xObjectApiKey","label":"实体 API Key","type":"String"},{"apiKey":"rows","label":"表格数据列表","type":"Array"}],"label":"事件入参","type":"Object"}]',
34
+ eventParams: [
35
+ {
36
+ apiKey: 'eventParam',
37
+ children: [
38
+ { apiKey: 'xObjectApiKey', label: '实体 API Key', type: 'String' },
39
+ { apiKey: 'rows', label: '表格数据列表', type: 'Array' },
40
+ ],
41
+ label: '事件入参',
42
+ type: 'Object',
43
+ },
44
+ ],
47
45
  },
48
46
  ];
49
47
 
@@ -29,7 +29,9 @@ interface ListSummaryState {
29
29
  listData: any[];
30
30
  }
31
31
 
32
- function getFirstFieldApiKey(desc?: FieldDescItem[] | null): string | undefined {
32
+ function getFirstFieldApiKey(
33
+ desc?: FieldDescItem[] | null,
34
+ ): string | undefined {
33
35
  if (!desc || !Array.isArray(desc) || desc.length === 0) return undefined;
34
36
  const first = desc[0];
35
37
  return first?.value;
@@ -84,12 +86,11 @@ class ListSummary extends BaseCmp<ListSummaryProps, ListSummaryState> {
84
86
 
85
87
  const hasRows = Array.isArray(listData) && listData.length > 0;
86
88
  const totalQty = hasRows && qtyKey ? sumField(listData, qtyKey) : 0;
87
- const totalAmount = hasRows && amountKey ? sumField(listData, amountKey) : 0;
89
+ const totalAmount =
90
+ hasRows && amountKey ? sumField(listData, amountKey) : 0;
88
91
 
89
92
  const qtyDisplay =
90
- !hasRows || !qtyKey
91
- ? '0'
92
- : totalQty.toLocaleString('zh-CN');
93
+ !hasRows || !qtyKey ? '0' : totalQty.toLocaleString('zh-CN');
93
94
 
94
95
  const amountDisplay =
95
96
  !hasRows || !amountKey
@@ -45,7 +45,7 @@
45
45
  "devDependencies": {
46
46
  "@commitlint/cli": "^18.0.0",
47
47
  "@commitlint/config-conventional": "^18.0.0",
48
- "neo-cmp-cli": "^1.13.17",
48
+ "neo-cmp-cli": "^1.13.18",
49
49
  "husky": "^4.2.5",
50
50
  "lint-staged": "^10.2.9",
51
51
  "prettier": "^2.0.5"
@@ -1,37 +0,0 @@
1
- import axios from 'axios'; // https://www.axios-http.cn/docs/intro
2
-
3
- // 创建基于 axios 的 fetcher 函数
4
- const axiosFetcher = async (options: any) => {
5
- try {
6
- const config = {
7
- ...options,
8
- method: options?.method || 'GET',
9
- data: options?.data || {},
10
- headers: {
11
- 'Content-Type': 'application/json',
12
- ...options?.headers,
13
- },
14
- timeout: options?.timeout || 30000,
15
- };
16
-
17
- if (config?.method === 'GET') {
18
- config.params = options?.data || {};
19
- }
20
-
21
- const response = await axios(config);
22
- return response?.data || {};
23
- } catch (error) {
24
- if (error.response) {
25
- // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
26
- console.error('接口请求报错 / 接口服务异常:', error.message);
27
- } else if (error.request) {
28
- // 请求已经成功发起,但没有收到响应
29
- console.error('接口请求报错 / 接口未正常响应:', error.message);
30
- } else {
31
- console.error('接口请求报错:', error, ',请求参数:', options);
32
- }
33
- throw error;
34
- }
35
- };
36
-
37
- export default axiosFetcher;