cloud-web-corejs 1.1.0-dev.21 → 1.1.0-dev.22

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cloud-web-corejs",
3
3
  "private": false,
4
- "version": "1.1.0-dev.21",
4
+ "version": "1.1.0-dev.22",
5
5
  "scripts": {
6
6
  "dev": "vue-cli-service serve",
7
7
  "dev:micro": "vue-cli-service serve --port 17527",
@@ -0,0 +1,112 @@
1
+ import { getLogicParamValue } from "@base/api/user";
2
+
3
+ export const CONDITION_EXPORT_PARAM_CODE = "conditionExportParams";
4
+ export const CONDITION_EXPORT_SEARCH_COUNT_CODE
5
+ = "conditionExportSearchCount";
6
+
7
+ export const DEFAULT_CONDITION_EXPORT_CONFIG = Object.freeze({
8
+ maxQueryTotal: 300000,
9
+ pageSize: 1000,
10
+ limitFileSize: 100000,
11
+ searchCount: true,
12
+ });
13
+
14
+ function parsePositiveInteger(value, fallback) {
15
+ let text = String(value == null ? "" : value).trim();
16
+ if (!/^\d+$/.test(text)) return fallback;
17
+ let result = Number(text);
18
+ if (!Number.isSafeInteger(result) || result <= 0) return fallback;
19
+ return result;
20
+ }
21
+
22
+ /**
23
+ * 解析「最大查询总数;每页查询数量;单文件最大数据量」。每一项独立回落默认值,
24
+ * 避免一项填错导致另外两项已生效的配置也被丢弃。
25
+ */
26
+ export function parseConditionExportParams(rawValue) {
27
+ let values = typeof rawValue === "string" ? rawValue.split(";") : [];
28
+ return {
29
+ maxQueryTotal: parsePositiveInteger(
30
+ values[0],
31
+ DEFAULT_CONDITION_EXPORT_CONFIG.maxQueryTotal
32
+ ),
33
+ pageSize: parsePositiveInteger(
34
+ values[1],
35
+ DEFAULT_CONDITION_EXPORT_CONFIG.pageSize
36
+ ),
37
+ limitFileSize: parsePositiveInteger(
38
+ values[2],
39
+ DEFAULT_CONDITION_EXPORT_CONFIG.limitFileSize
40
+ ),
41
+ };
42
+ }
43
+
44
+ export function parseConditionExportSearchCount(rawValue, fallback = true) {
45
+ if (typeof rawValue === "boolean") return rawValue;
46
+ if (typeof rawValue !== "string") return fallback;
47
+ let value = rawValue.trim().toLowerCase();
48
+ if (value === "true") return true;
49
+ if (value === "false") return false;
50
+ return fallback;
51
+ }
52
+
53
+ function readLogicParam(paramCode) {
54
+ return getLogicParamValue({
55
+ data: { paramCode },
56
+ modal: false,
57
+ failMsg: false,
58
+ errorMsg: false,
59
+ })
60
+ .then((res) => (res && res.type === "success" ? res.objx : ""))
61
+ .catch(() => "");
62
+ }
63
+
64
+ /** 读取两条全局逻辑参数;接口异常时静默使用内置默认值。 */
65
+ export function loadConditionExportConfig() {
66
+ return Promise.all([
67
+ readLogicParam(CONDITION_EXPORT_PARAM_CODE),
68
+ readLogicParam(CONDITION_EXPORT_SEARCH_COUNT_CODE),
69
+ ]).then(([paramsRaw, searchCountRaw]) => ({
70
+ ...parseConditionExportParams(paramsRaw),
71
+ searchCount: parseConditionExportSearchCount(searchCountRaw, true),
72
+ }));
73
+ }
74
+
75
+ /**
76
+ * 从导出按钮 options 取出条件导出的三项覆盖值。空值转成 null,交给
77
+ * resolveConditionExportConfig 回落到全局逻辑参数。
78
+ */
79
+ export function pickConditionExportOverrides(fieldOptions = {}) {
80
+ return {
81
+ pageSize: fieldOptions.exportPageSize || null,
82
+ maxQueryTotal: fieldOptions.maxQueryTotal || null,
83
+ limitFileSize: fieldOptions.limitFileSize || null,
84
+ };
85
+ }
86
+
87
+ /**
88
+ * 单次导出参数优先于全局逻辑参数。按钮参数与脚本参数在进入导出器前已经合并,且脚本
89
+ * 位于展开表达式右侧,所以这里读取到的 option 天然满足「脚本 > 按钮 > 全局」。
90
+ */
91
+ export function resolveConditionExportConfig(globalConfig, option = {}) {
92
+ let base = globalConfig || DEFAULT_CONDITION_EXPORT_CONFIG;
93
+ let searchCountOverride
94
+ = option.conditionExportSearchCount !== undefined
95
+ ? option.conditionExportSearchCount
96
+ : option.searchCount;
97
+ return {
98
+ maxQueryTotal: parsePositiveInteger(
99
+ option.maxQueryTotal,
100
+ base.maxQueryTotal
101
+ ),
102
+ pageSize: parsePositiveInteger(option.pageSize, base.pageSize),
103
+ limitFileSize: parsePositiveInteger(
104
+ option.limitFileSize,
105
+ base.limitFileSize
106
+ ),
107
+ searchCount: parseConditionExportSearchCount(
108
+ searchCountOverride,
109
+ base.searchCount
110
+ ),
111
+ };
112
+ }
@@ -39,6 +39,14 @@ export function isRowExport(type) {
39
39
  return type === EXPORT_TYPE.SELECTED || type === EXPORT_TYPE.CURRENT;
40
40
  }
41
41
 
42
+ /**
43
+ * 是否条件导出。主表条件导出的历史 type 是 null/undefined;明细条件导出有独立类型。
44
+ * 明细选择导出虽然也走后端分页,但不受条件导出全局上限与查总数开关影响。
45
+ */
46
+ export function isConditionExport(type) {
47
+ return type == null || type === EXPORT_TYPE.ITEM_CONDITION;
48
+ }
49
+
42
50
  /**
43
51
  * 是否必须先勾选行:空勾选要拦截,且以勾选行 id 作为查询条件。
44
52
  * @param {String|null} type 导出模式。
@@ -41,6 +41,12 @@
41
41
  <div class="export-box">
42
42
  <div class="tips">
43
43
  {{ $t2("导出中,请勿关闭当前窗口", "components.excelExport.tip") }}
44
+ <template v-if="conditionExportMode">
45
+ ,{{
46
+ $t2("导出最大数据量", "components.excelExport.maxDataSize")
47
+ }}:{{ conditionExportConfig.maxQueryTotal
48
+ }}{{ $t2("条", "components.excelExport.rowUnit") }}
49
+ </template>
44
50
  </div>
45
51
  <el-progress
46
52
  :text-inside="true"
@@ -62,7 +68,7 @@
62
68
  <div class="fl import-count">
63
69
  <span class="f-red doneNum">{{ doneSize }}</span>
64
70
  /
65
- <span class="dataSize">{{ tTotalSize }}</span>
71
+ <span class="dataSize">{{ exportTotalText }}</span>
66
72
  </div>
67
73
  <el-button type="primary" plain class="button-sty" @click="dialogClose2">
68
74
  <i class="el-icon-close el-icon"></i>
@@ -5,9 +5,19 @@ import { getToken } from "../../utils/auth";
5
5
  import indexUtil from "../../utils/index.js";
6
6
  import exportFieldDialog from "./exportFieldDialog.vue";
7
7
  import { getCellValue } from "@base/components/table/util/index";
8
- import { isItemExport, isRowExport, requiresCheckedRows } from "./exportType";
9
- import { getExportItemColumns } from "./exportItemConfigUtil";
10
- import { viewKey } from "@base/utils/repeatOpen";
8
+ import {
9
+ isConditionExport,
10
+ isItemExport,
11
+ isRowExport,
12
+ requiresCheckedRows,
13
+ } from "./exportType";
14
+ import { getExportItemColumns } from "./exportItemConfigUtil";
15
+ import { viewKey } from "@base/utils/repeatOpen";
16
+ import {
17
+ DEFAULT_CONDITION_EXPORT_CONFIG,
18
+ loadConditionExportConfig,
19
+ resolveConditionExportConfig,
20
+ } from "./conditionExportConfig";
11
21
 
12
22
  let configUtil = {
13
23
  baseUrl: process.env.VUE_APP_BASE_API,
@@ -130,8 +140,14 @@ function getGrid(that, tableRef) {
130
140
  showExportFieldDialog: false,
131
141
  leafColumns: [],
132
142
  columns: [],
133
- queryParam: {},
134
- isMinimize: false,
143
+ queryParam: {},
144
+ isMinimize: false,
145
+ // 条件导出在本次任务内使用的配置快照。逻辑参数只在开始时读取一次,避免中途变更
146
+ // 导致前后页使用不同的分页/分卷口径。
147
+ conditionExportMode: false,
148
+ conditionExportConfig: { ...DEFAULT_CONDITION_EXPORT_CONFIG },
149
+ // 不查总数时,处理过程中分母显示「...」;文件合并成功后才回填实际完成数。
150
+ totalSizeKnown: true,
135
151
  // 定时器必须放实例上:模块级共享会导致并发导出互相清除对方的定时器
136
152
  exportTimer: null,
137
153
  countTimer: null,
@@ -146,9 +162,14 @@ function getGrid(that, tableRef) {
146
162
  // $route.path」现查,用户在导出期间切了页签(弹框可最小化,切走完全合法)
147
163
  // 解的就是另一把锁 —— 原页签会永久 affix,而 tagsView 的 delOthersViews /
148
164
  // delAllViews 都保留 affix,「关闭其他」「全部关闭」也删不掉它,只能刷新页面。
149
- lockedView: null,
150
- };
151
- },
165
+ lockedView: null,
166
+ };
167
+ },
168
+ computed: {
169
+ exportTotalText() {
170
+ return this.totalSizeKnown ? this.tTotalSize : "...";
171
+ },
172
+ },
152
173
  created() {},
153
174
  mounted() {
154
175
  // this.exc();
@@ -256,13 +277,29 @@ function getGrid(that, tableRef) {
256
277
  this.param.destroyComponent(loadingObj);
257
278
  }, 0);
258
279
  },
259
- dialogPrimary2() {
280
+ dialogPrimary2() {
260
281
  // this.showUserDialog=false
261
282
  this.$emit("confirm");
262
283
  this.$emit("close");
263
- this.clearExportTimer();
264
- },
265
- startProcess() {
284
+ this.clearExportTimer();
285
+ },
286
+ /**
287
+ * 读取并固化本次条件导出的全局配置。单次按钮/脚本参数已经在 option 中完成合并,
288
+ * resolveConditionExportConfig 会让它们覆盖同名的全局配置。
289
+ */
290
+ prepareConditionExportConfig() {
291
+ this.conditionExportMode = isConditionExport(this.option.type);
292
+ this.totalSizeKnown = true;
293
+ if (!this.conditionExportMode) return Promise.resolve();
294
+ return loadConditionExportConfig().then((globalConfig) => {
295
+ this.conditionExportConfig = resolveConditionExportConfig(
296
+ globalConfig,
297
+ this.option
298
+ );
299
+ this.totalSizeKnown = this.conditionExportConfig.searchCount;
300
+ });
301
+ },
302
+ startProcess() {
266
303
  this.lockMenu();
267
304
  this.createCountTimer();
268
305
  this.tableTarget = getGrid(this.option.vue, this.option.targetRef);
@@ -296,47 +333,62 @@ function getGrid(that, tableRef) {
296
333
  this.$t1("无法确定导出服务前缀,请在导出配置中指定 prefix")
297
334
  );
298
335
  return;
299
- }
300
- this.CURRENT_PREFIX = options.prefix;
301
- // 取数走 originOption.exportAjax 时请求由 xform 侧构造,前端拿不到那个 config,
302
- // 只能把令牌顺着导出参数带过去(data-table-mixin 的 exportAjax 会塞进
303
- // customParam.config,最终由 formHttp 的 ...opts 透传给 axios)
304
- options.cancelToken = this.getCancelToken();
305
-
306
- this.title = title;
307
- that.tTotalPage = 0;
308
- that.tTotalSize = 0;
309
- that
310
- .createExcelFile()
311
- .then((resultMsg) => {
312
- if (that.isExportStopped()) return;
313
- if (resultMsg.type === "success") {
314
- let aObj = resultMsg.objx;
315
- that.uuid = aObj.uuid;
316
- that.nowDate = aObj.nowDate;
317
- that.ippaaapp = aObj.ippaaapp;
318
- setTimeout(function () {
319
- /*num = 1;
320
- loopToDo(0, num);*/
321
- if (that.isExportStopped()) return;
322
- that.handleLoopToDo();
323
- }, 300);
324
- } else {
325
- that.abortExport();
326
- that.showImportDialog = false;
327
- that.showImportDialog2 = false;
328
- }
329
- })
330
- .catch((error) => {
331
- if (that.isExportStopped()) return;
332
- console.error(error);
333
- that.abortExport(that.$t1("创建导出文件失败,导出已中止"));
334
- that.showImportDialog = false;
335
- that.showImportDialog2 = false;
336
- });
337
- },
338
- getExportPageSize() {
339
- let pageSize = Math.min(this.option.pageSize || 1000, 1000);
336
+ }
337
+ this.CURRENT_PREFIX = options.prefix;
338
+ this.title = title;
339
+ that.tTotalPage = 0;
340
+ that.tTotalSize = 0;
341
+ that.prepareConditionExportConfig().then(() => {
342
+ if (that.isExportStopped()) return;
343
+ // 取数走 originOption.exportAjax 时请求由 xform 侧构造,前端拿不到那个 config,
344
+ // 只能把令牌顺着导出参数带过去(data-table-mixin 的 exportAjax 会塞进
345
+ // customParam.config,最终由 formHttp 的 ...opts 透传给 axios)
346
+ options.cancelToken = that.getCancelToken();
347
+ that
348
+ .createExcelFile()
349
+ .then((resultMsg) => {
350
+ if (that.isExportStopped()) return;
351
+ if (resultMsg.type === "success") {
352
+ let aObj = resultMsg.objx;
353
+ that.uuid = aObj.uuid;
354
+ that.nowDate = aObj.nowDate;
355
+ that.ippaaapp = aObj.ippaaapp;
356
+ setTimeout(function () {
357
+ if (that.isExportStopped()) return;
358
+ that.handleLoopToDo();
359
+ }, 300);
360
+ } else {
361
+ that.abortExport();
362
+ that.showImportDialog = false;
363
+ that.showImportDialog2 = false;
364
+ }
365
+ })
366
+ .catch((error) => {
367
+ if (that.isExportStopped()) return;
368
+ console.error(error);
369
+ that.abortExport(that.$t1("创建导出文件失败,导出已中止"));
370
+ that.showImportDialog = false;
371
+ that.showImportDialog2 = false;
372
+ });
373
+ });
374
+ },
375
+ getExportPageSize() {
376
+ let configuredPageSize = this.conditionExportMode
377
+ ? this.conditionExportConfig.pageSize
378
+ : this.option.pageSize || 1000;
379
+ // 条件导出的按钮/脚本值已经按优先级写进配置快照,不再用全局默认值 1000
380
+ // 反向封顶;非条件导出保持原有最多 1000 的行为。
381
+ let pageSize = this.conditionExportMode
382
+ ? configuredPageSize
383
+ : Math.min(configuredPageSize, 1000);
384
+ if (this.conditionExportMode) {
385
+ // 单页本身不能突破总量或单文件上限,否则无法在页级合并时兑现硬上限。
386
+ pageSize = Math.min(
387
+ pageSize,
388
+ this.conditionExportConfig.maxQueryTotal,
389
+ this.conditionExportConfig.limitFileSize
390
+ );
391
+ }
340
392
  let showImageAtTable = this.option.showImageAtTable || false;
341
393
  let hasExportImage = !!this.leafColumns.find((item) => {
342
394
  let exportType = item?.params?.exportType;
@@ -359,17 +411,19 @@ function getGrid(that, tableRef) {
359
411
  }
360
412
  return pageSize;
361
413
  },
362
- hadleMergeExcel(pPageSize) {
414
+ hadleMergeExcel(pPageSize) {
363
415
  if (this.isExportStopped()) return;
364
416
  let that = this;
365
417
  let title = this.title;
366
418
  let options = this.option;
367
419
  // let pPageSize = this.getExportPageSize();
368
- let limitFileSize = options.limitFileSize || 100000;
420
+ let limitFileSize = this.conditionExportMode
421
+ ? this.conditionExportConfig.limitFileSize
422
+ : options.limitFileSize || 100000;
369
423
  let limitThreadNum = options.limitThreadNum || 5;
370
424
  let totalPages = this.tTotalPage || 1;
371
425
 
372
- let kTotalPages = parseInt(limitFileSize / pPageSize);
426
+ let kTotalPages = Math.max(parseInt(limitFileSize / pPageSize), 1);
373
427
 
374
428
  let fileNum = parseInt(totalPages / kTotalPages);
375
429
  if (totalPages % kTotalPages !== 0) {
@@ -438,20 +492,195 @@ function getGrid(that, tableRef) {
438
492
  });
439
493
  // 注意:此处不能同步 clearExportTimer,否则计时统计会在合并完成前被提前停掉
440
494
  }
441
- };
442
- loopDo();
443
- },
444
- handleLoopToDo() {
445
- let that = this;
446
- let uuid;
447
- let num = 0;
448
- let title = this.title;
449
-
450
- let options = this.option;
451
-
452
- let pPageSize = this.getExportPageSize();
453
- let limitFileSize = options.limitFileSize || 100000;
454
- let limitThreadNum = options.limitThreadNum || 5;
495
+ };
496
+ loopDo();
497
+ },
498
+ /** 统一组装一页条件导出的取数请求,保证两种查总数模式使用完全相同的查询条件。 */
499
+ async requestExportPage(pageNumber, pageSize, searchCount) {
500
+ let options = this.option;
501
+ let originOption = this.tableTarget.params.originOption;
502
+ let url = originOption.exportPath || originOption.path;
503
+ let params = this.$baseLodash.cloneDeep(this.queryParam);
504
+ let aParam = {
505
+ current: pageNumber,
506
+ size: pageSize,
507
+ nowDate: this.nowDate ?? options.nowDate,
508
+ searchCount,
509
+ };
510
+ let cpParam;
511
+ if (originOption.vform === true) {
512
+ params.conditions = params.conditions || {};
513
+ cpParam = params.conditions;
514
+ } else {
515
+ cpParam = params;
516
+ }
517
+ Object.assign(cpParam, aParam);
518
+
519
+ if (originOption.exportAjax) {
520
+ return originOption.exportAjax(aParam, {
521
+ ...options,
522
+ exportQuerySnapshot: this.$baseLodash.cloneDeep(this.queryParam),
523
+ });
524
+ }
525
+ // URL 上若写死 searchCount,会与本次模式冲突;实际值统一由请求体控制。
526
+ let resolvedUrl = typeof url === "function" ? url() : url;
527
+ if (typeof resolvedUrl !== "string" || !resolvedUrl) {
528
+ throw new Error("无效的导出查询地址");
529
+ }
530
+ let requestUrl = resolvedUrl
531
+ .replace("searchCount=false", "1=1")
532
+ .replace("searchCount=true", "1=1");
533
+ let finalParams = params;
534
+ if (originOption.paramHandle) {
535
+ finalParams = originOption.paramHandle(params) || {};
536
+ }
537
+ return this.$commonHttp({
538
+ aes: originOption.aes || false,
539
+ url: requestUrl,
540
+ method: "post",
541
+ data: finalParams,
542
+ modal: false,
543
+ queryCreateInfo: originOption.queryCreateInfo,
544
+ addCreateInfo: originOption.addCreateInfo,
545
+ cancelToken: this.getCancelToken(),
546
+ });
547
+ },
548
+ /** 导出尚在取数/合并时最多显示 99%,100% 只由 completeExport 设置。 */
549
+ updateExportProgress(doneSize, progressTotal) {
550
+ this.doneSize = parseInt(doneSize);
551
+ let percentage = progressTotal > 0 ? (doneSize * 100) / progressTotal : 99;
552
+ if (percentage > 0 && percentage < 1) percentage = 1;
553
+ if (percentage >= 100) percentage = 99;
554
+ this.percentageNum = parseInt(percentage);
555
+ },
556
+ /**
557
+ * 不查询总数:每页都发 searchCount=false,以 records.length < pageSize 判定末页。
558
+ * 取数与写入按页串行,确保发现末页或达到最大查询总数后不会继续派发多余请求。
559
+ */
560
+ handleLoopWithoutCount(pageSize) {
561
+ let that = this;
562
+ let maxQueryTotal = this.conditionExportConfig.maxQueryTotal;
563
+ let maxPages = Math.max(Math.ceil(maxQueryTotal / pageSize), 1);
564
+ let doneSize = 0;
565
+ this.tTotalPage = 0;
566
+ this.tTotalSize = 0;
567
+ this.totalSizeKnown = false;
568
+
569
+ let finish = function (lastPage) {
570
+ if (that.isExportStopped()) return;
571
+ that.tTotalPage = Math.max(lastPage, 1);
572
+ that.hadleMergeExcel(pageSize);
573
+ };
574
+
575
+ let fetchPage = function (pageNumber, retryCount = 0) {
576
+ if (that.isExportStopped()) return Promise.resolve(null);
577
+ return that
578
+ .requestExportPage(pageNumber, pageSize, false)
579
+ .then((resultMsg) => {
580
+ if (resultMsg && resultMsg.type === "success") return resultMsg;
581
+ if (retryCount < 1) {
582
+ return new Promise((resolve) => {
583
+ setTimeout(
584
+ () => resolve(fetchPage(pageNumber, retryCount + 1)),
585
+ 500
586
+ );
587
+ });
588
+ }
589
+ that.abortExport();
590
+ return null;
591
+ })
592
+ .catch((error) => {
593
+ if (that.isExportStopped()) return null;
594
+ if (retryCount < 1) {
595
+ return new Promise((resolve) => {
596
+ setTimeout(
597
+ () => resolve(fetchPage(pageNumber, retryCount + 1)),
598
+ 500
599
+ );
600
+ });
601
+ }
602
+ console.error(error);
603
+ that.abortExport(
604
+ that.$t1("第{n}页数据拉取失败,导出已中止", {
605
+ n: pageNumber,
606
+ })
607
+ );
608
+ return null;
609
+ });
610
+ };
611
+
612
+ let appendPage = function (pageNumber) {
613
+ fetchPage(pageNumber).then((resultMsg) => {
614
+ if (!resultMsg || that.isExportStopped()) return;
615
+ let page = resultMsg.objx || {};
616
+ let actualSize = Number(page.size || page.pageSize || pageSize);
617
+ if (!Number.isSafeInteger(actualSize) || actualSize <= 0
618
+ || actualSize > pageSize || (pageNumber > 1 && actualSize !== pageSize)) {
619
+ that.abortExport(that.$t1("服务端分页大小发生变化,导出已中止"));
620
+ return;
621
+ }
622
+ pageSize = actualSize;
623
+ maxPages = Math.max(Math.ceil(maxQueryTotal / pageSize), 1);
624
+ let rawRows = Array.isArray(page.records) ? page.records : [];
625
+ let hasNext = rawRows.length >= pageSize;
626
+
627
+ // 整页数据需要再探测一页;探测到的空页不写入,也不参与合并。
628
+ if (pageNumber > 1 && rawRows.length === 0) {
629
+ finish(pageNumber - 1);
630
+ return;
631
+ }
632
+
633
+ let remaining = Math.max(maxQueryTotal - doneSize, 0);
634
+ let rows = rawRows.slice(0, remaining);
635
+ let reachedLimit = rows.length >= remaining;
636
+ page.current = pageNumber;
637
+ page.pageNumber = pageNumber;
638
+ page.size = pageSize;
639
+ page.pageSize = pageSize;
640
+ page.records = rows;
641
+
642
+ that
643
+ .addExcelData({ rows, pageNumber })
644
+ .then((appendResult) => {
645
+ if (that.isExportStopped()) return;
646
+ if (!appendResult || appendResult.type !== "success") {
647
+ if (appendResult && appendResult.type === "abort") return;
648
+ that.abortExport();
649
+ return;
650
+ }
651
+ doneSize += rows.length;
652
+ that.updateExportProgress(doneSize, maxQueryTotal);
653
+ if (reachedLimit || !hasNext || pageNumber >= maxPages) {
654
+ finish(pageNumber);
655
+ return;
656
+ }
657
+ appendPage(pageNumber + 1);
658
+ })
659
+ .catch((error) => {
660
+ if (that.isExportStopped()) return;
661
+ console.error(error);
662
+ that.abortExport(that.$t1("导出数据写入失败,导出已中止"));
663
+ });
664
+ });
665
+ };
666
+
667
+ appendPage(1);
668
+ },
669
+ handleLoopToDo() {
670
+ let that = this;
671
+ let num = 0;
672
+ let options = this.option;
673
+
674
+ let pPageSize = this.getExportPageSize();
675
+ let limitThreadNum = options.limitThreadNum || 5;
676
+
677
+ if (
678
+ this.conditionExportMode
679
+ && this.conditionExportConfig.searchCount === false
680
+ ) {
681
+ this.handleLoopWithoutCount(pPageSize);
682
+ return;
683
+ }
455
684
 
456
685
  /**处理返回值*/
457
686
  this.doneSize = 0;
@@ -478,39 +707,15 @@ function getGrid(that, tableRef) {
478
707
  rows: resultMsg.objx.records,
479
708
  pageNumber: pageNumber,
480
709
  })
481
- .then(function (resultMsg2) {
482
- releaseWindow();
483
- let data = resultMsg.objx;
484
- let total = data.total;
485
-
486
- let pageNumber = data.pageNumber || 1;
487
- let totalPages = that.tTotalPage || 1;
488
- if (resultMsg2.type === "success") {
489
- excedNum++;
490
- let pageNumber = data.pageNumber || 1;
491
- let k = (excedNum * 100) / totalPages;
492
- if (k > 0 && k < 1) {
493
- k = 1;
494
- }
495
- if (k > 100) k = 100;
496
- let cTotal = that.tTotalSize;
497
- let pageSize = data.pageSize;
498
- // let datas = data.records;
499
- let size = data.records.length;
500
- cSize = cSize + size;
501
-
502
- let ttNum = cSize + "/" + cTotal;
503
- let percentageStr = parseInt(k) + "%";
504
-
505
- let percentageNum = k;
506
- if (percentageNum >= 100) {
507
- percentageNum = 99;
508
- }
509
- // that.$set(that, "doneSize", parseInt(cSize));
510
- // that.$set(that, "percentageNum", parseInt(percentageNum));
511
-
512
- that.doneSize = parseInt(cSize);
513
- that.percentageNum = parseInt(percentageNum);
710
+ .then(function (resultMsg2) {
711
+ releaseWindow();
712
+ let data = resultMsg.objx;
713
+ let totalPages = that.tTotalPage || 1;
714
+ if (resultMsg2.type === "success") {
715
+ excedNum++;
716
+ let size = data.records.length;
717
+ cSize = cSize + size;
718
+ that.updateExportProgress(cSize, that.tTotalSize);
514
719
 
515
720
  if (totalPages === 0 || excedNum >= totalPages) {
516
721
  that.hadleMergeExcel(data.pageSize);
@@ -605,113 +810,49 @@ function getGrid(that, tableRef) {
605
810
  });
606
811
  };
607
812
 
608
- let waitReqNum = 0;
609
- let promise;
610
- let loopToDo = function (flag, pageNumber, retryCount = 0) {
611
- // 取消后不再发起新页,也不再重试(重试是从 .catch 里递归回来的)
612
- if (that.isExportStopped()) return;
613
- let maxWaitNum = limitThreadNum;
614
- // 分页取数的时间快照:createExcelTemplate 返回后存在 this.nowDate(见
615
- // startProcess),此前这里读的是 options.nowDate —— 那是调用方入参,全库
616
- // 没有任何调用方维护它,于是每页请求的 nowDate 恒为 undefined、被
617
- // JSON.stringify 丢掉,后端拿不到快照点。导出期间数据发生增删时,分页会
618
- // 整体前后错位,合出来的文件既漏行又重行,且全程不报错。
619
- // 仍保留 options.nowDate 兜底:服务端未返回快照时,调用方若显式指定了一个,
620
- // 用它总好过不带。
621
- // 两条取数通道都要带:通用表格随请求体平铺下发;xform exportAjax,快照
622
- // aParam 进去后由 data-table-mixin.loadDefaultQueryList 提到信封层(与
623
- // formCode 同级),不能留在内层 data —— 那是业务查询条件的地盘。
624
- let nowDate = that.nowDate ?? options.nowDate;
625
- if (flag === 1) {
626
- /*if (num > that.tTotalPage) {
627
- let size = page.records.length;
628
- if (size === 0 || page.totalPages === 0 || (page.pageNumber >= page.totalPages)) {
629
- that.clearExportTimer();
630
- return;
631
- }
632
- }*/
633
- } else {
634
- waitReqNum = 0;
635
- }
636
-
637
- let target = that.tableTarget;
638
- let originOption = target.params.originOption;
639
- let url = originOption.exportPath || originOption.path;
640
-
641
- // let params = originOption.param() || {};
642
- // 每页必须独立参数对象。此前所有页共享 that.queryParam 这一个对象,下面的
643
- // Object.assign current 写进去后,靠"派发间隔 100ms、微任务已 flush"侥幸
644
- // 不冲突;请求拦截器一旦变成异步(token 续期等),并发的两页会带上同一个
645
- // current —— 合并出的文件重复页 + 缺页,且全程不报错。
646
- let params = that.$baseLodash.cloneDeep(that.queryParam);
647
- let aParam = {
648
- current: pageNumber,
649
- size: pPageSize,
650
- nowDate: nowDate,
651
- searchCount: flag !== 1,
652
- };
653
- let cpParam;
654
- if (originOption.vform === true) {
655
- params.conditions = params.conditions || {};
656
- cpParam = params.conditions;
657
- } else {
658
- cpParam = params;
659
- }
660
- Object.assign(cpParam, aParam);
661
-
662
- if (!originOption.exportAjax) {
663
- let turl = url.replace("searchCount=false", "1=1");
664
- let finaParams = params;
665
- if (originOption.paramHandle) {
666
- finaParams = originOption.paramHandle
667
- ? originOption.paramHandle(params) || {}
668
- : {};
669
- }
670
- promise = that.$commonHttp({
671
- aes: originOption.aes || false,
672
- url: turl,
673
- method: "post",
674
- data: finaParams,
675
- modal: false,
676
- queryCreateInfo: originOption.queryCreateInfo,
677
- addCreateInfo: originOption.addCreateInfo,
678
- cancelToken: that.getCancelToken(),
679
- });
680
- } else {
681
- promise = originOption.exportAjax(aParam, options);
682
- }
683
-
684
- promise
685
- .then(function (resultMsg) {
686
- if (resultMsg.type === "success") {
687
- let objx = resultMsg.objx;
688
- objx.pageNumber = objx.current || 1;
689
- objx.totalPages = objx.pages || 1;
690
- objx.pageSize = objx.size;
691
- let size = objx.records.length;
692
- if (flag === 0) {
693
- that.tTotalPage = objx.pages;
694
- // that.tTotalSize = objx.total;
695
- setTimeout(function () {
696
- that.$set(that, "tTotalSize", objx.total);
697
- }, 0);
698
- let tTotalPage = objx.pages;
699
- let tTotalSize = objx.total;
700
- let ttNum = 0 + "/" + objx.total;
701
-
702
- let opNum = limitFileSize;
703
- let kTotalPages = parseInt(opNum / objx.size);
704
-
705
- let fileNum = parseInt(tTotalPage / kTotalPages);
706
- if (tTotalPage % kTotalPages !== 0) {
707
- fileNum = fileNum + 1;
708
- }
709
- if (
710
- size > 0 ||
711
- objx.totalPages > 0 ||
712
- objx.pageNumber < objx.totalPages
713
- ) {
714
- that.exportTimer = setInterval(function () {
813
+ let waitReqNum = 0;
814
+ let loopToDo = function (flag, pageNumber, retryCount = 0) {
815
+ // 取消后不再发起新页,也不再重试(重试是从 .catch 里递归回来的)
816
+ if (that.isExportStopped()) return;
817
+ let maxWaitNum = limitThreadNum;
818
+ if (flag !== 1) waitReqNum = 0;
819
+
820
+ that
821
+ .requestExportPage(pageNumber, pPageSize, flag !== 1)
822
+ .then(function (resultMsg) {
823
+ if (resultMsg.type === "success") {
824
+ let objx = resultMsg.objx || {};
825
+ objx.records = Array.isArray(objx.records) ? objx.records : [];
826
+ objx.pageNumber = objx.current || pageNumber;
827
+ objx.pageSize = objx.size || pPageSize;
828
+ let actualSize = Number(objx.pageSize);
829
+ if (!Number.isSafeInteger(actualSize) || actualSize <= 0
830
+ || actualSize > pPageSize || (flag !== 0 && actualSize !== pPageSize)) {
831
+ that.abortExport(that.$t1("服务端分页大小发生变化,导出已中止"));
832
+ return;
833
+ }
834
+ pPageSize = actualSize;
835
+ objx.pageSize = actualSize;
836
+ let size = objx.records.length;
837
+ if (flag === 0) {
838
+ let rawTotal = Number(objx.total);
839
+ if (!Number.isFinite(rawTotal) || rawTotal < 0) {
840
+ rawTotal = size;
841
+ }
842
+ let exportTotal = that.conditionExportMode
843
+ ? Math.min(
844
+ rawTotal,
845
+ that.conditionExportConfig.maxQueryTotal
846
+ )
847
+ : rawTotal;
848
+ that.tTotalPage = that.conditionExportMode
849
+ ? Math.max(Math.ceil(exportTotal / pPageSize), 1)
850
+ : objx.pages;
851
+ objx.totalPages = that.tTotalPage || 1;
852
+ that.tTotalSize = exportTotal;
853
+ let tTotalPage = that.tTotalPage || 1;
854
+ if (tTotalPage > 1) {
855
+ that.exportTimer = setInterval(function () {
715
856
  if (waitReqNum < maxWaitNum && num < tTotalPage) {
716
857
  waitReqNum++;
717
858
  num++;
@@ -726,9 +867,15 @@ function getGrid(that, tableRef) {
726
867
  }, 100);
727
868
  } else {
728
869
  clearInterval(that.exportTimer);
729
- that.exportTimer = null;
730
- }
731
- }
870
+ that.exportTimer = null;
871
+ }
872
+ }
873
+ if (that.conditionExportMode) {
874
+ // 总数超过有效上限时,最后一页只写允许范围内的数据。
875
+ let rowOffset = (pageNumber - 1) * pPageSize;
876
+ let allowedRows = Math.max(that.tTotalSize - rowOffset, 0);
877
+ objx.records = objx.records.slice(0, allowedRows);
878
+ }
732
879
  // 注意:此处不再释放并发窗口。拉取完成只是这一页做完了一半,
733
880
  // 窗口由 handleData 在上送(addExcelData)落地后释放,见那里的注释。
734
881
 
@@ -898,14 +1045,14 @@ function getGrid(that, tableRef) {
898
1045
  }
899
1046
  let cUUid = this.uuid;
900
1047
  let ippaaapp = this.ippaaapp;
901
- let url1 =
902
- this.CURRENT_PREFIX +
903
- "/excel/appendExcelData?uuid=" +
904
- cUUid +
905
- "&ippaaapp=" +
906
- ippaaapp +
907
- "&pageNumber=" +
908
- pageNumber;
1048
+ let url1
1049
+ = this.CURRENT_PREFIX
1050
+ + "/excel/appendExcelData?uuid="
1051
+ + cUUid
1052
+ + "&ippaaapp="
1053
+ + ippaaapp
1054
+ + "&pageNumber="
1055
+ + pageNumber;
909
1056
  return this.$http({
910
1057
  url: url1,
911
1058
  method: "post",
@@ -919,12 +1066,12 @@ function getGrid(that, tableRef) {
919
1066
  });
920
1067
  },
921
1068
  mergeExcel(startPage, endPage, loading) {
922
- let url1 =
923
- this.CURRENT_PREFIX +
924
- "/excel/mergeExcel?uuid=" +
925
- this.uuid +
926
- "&ippaaapp=" +
927
- this.ippaaapp;
1069
+ let url1
1070
+ = this.CURRENT_PREFIX
1071
+ + "/excel/mergeExcel?uuid="
1072
+ + this.uuid
1073
+ + "&ippaaapp="
1074
+ + this.ippaaapp;
928
1075
  return this.$http({
929
1076
  url: url1 + "&startPage=" + startPage + "&endPage=" + endPage,
930
1077
  method: "post",
@@ -954,8 +1101,12 @@ function getGrid(that, tableRef) {
954
1101
  * 合法的状态,那时页签必须能正常关闭 —— 解锁此前只挂在 beforeDestroy 上,
955
1102
  * 用户不点「取消/确定」就永远解不开,正是「导出完成后页签关不掉」的来源。
956
1103
  */
957
- completeExport() {
958
- setTimeout(() => {
1104
+ completeExport() {
1105
+ if (!this.totalSizeKnown) {
1106
+ this.tTotalSize = this.doneSize;
1107
+ this.totalSizeKnown = true;
1108
+ }
1109
+ setTimeout(() => {
959
1110
  if (this.isExportStopped()) return;
960
1111
  this.percentageNum = parseInt(100);
961
1112
  }, 100);
@@ -1011,10 +1162,10 @@ function getGrid(that, tableRef) {
1011
1162
  return column.slots.filterVal(params);
1012
1163
  }
1013
1164
  let slotDefault = column.slots && column.slots.default;
1014
- let hasRenderFn =
1015
- !!column.renderCell ||
1016
- typeof slotDefault === "function" ||
1017
- typeof slotDefault === "string";
1165
+ let hasRenderFn
1166
+ = !!column.renderCell
1167
+ || typeof slotDefault === "function"
1168
+ || typeof slotDefault === "string";
1018
1169
  if (!hasRenderFn) {
1019
1170
  let cellValue = params.row[column.field];
1020
1171
  if (typeof column.formatter === "function") {
@@ -1072,8 +1223,8 @@ function getGrid(that, tableRef) {
1072
1223
  // _columnIndex
1073
1224
  };
1074
1225
  let exportType = column.params?.exportType;
1075
- let exportVal =
1076
- column.params && column.params.exportVal
1226
+ let exportVal
1227
+ = column.params && column.params.exportVal
1077
1228
  ? column.params.exportVal
1078
1229
  : null;
1079
1230
  if (exportVal) {
@@ -1089,16 +1240,16 @@ function getGrid(that, tableRef) {
1089
1240
  } else if (exportType === "Number") {
1090
1241
  resultStr = that.getExportCellValue(params);
1091
1242
  if (
1092
- resultStr !== null &&
1093
- resultStr !== undefined &&
1094
- resultStr !== "" &&
1095
- !(resultStr + "").startsWith("[EXPNUM]")
1243
+ resultStr !== null
1244
+ && resultStr !== undefined
1245
+ && resultStr !== ""
1246
+ && !(resultStr + "").startsWith("[EXPNUM]")
1096
1247
  ) {
1097
1248
  resultStr = "[EXPNUM]" + resultStr;
1098
1249
  }
1099
1250
  } else if (
1100
- exportType === "Image" ||
1101
- (showImageAtTable && exportType === "Image2")
1251
+ exportType === "Image"
1252
+ || (showImageAtTable && exportType === "Image2")
1102
1253
  ) {
1103
1254
  // 取值刻意延到"确实用得上"的那条分支才做:附件的正常形态是数组,
1104
1255
  // 那条分支会用 row[column.field] 自己拼 [EXPIMG],把取值结果整个覆盖;
@@ -1111,9 +1262,9 @@ function getGrid(that, tableRef) {
1111
1262
  that.isPicture(item.extension)
1112
1263
  );
1113
1264
  if (items.length > 0) {
1114
- resultStr =
1115
- "[EXPIMG]" +
1116
- items
1265
+ resultStr
1266
+ = "[EXPIMG]"
1267
+ + items
1117
1268
  .map((item) => {
1118
1269
  let url = item.large || item.medium;
1119
1270
  return item.domain + url;
@@ -1131,10 +1282,10 @@ function getGrid(that, tableRef) {
1131
1282
  )
1132
1283
  ) {
1133
1284
  if (
1134
- resultStr !== null &&
1135
- resultStr !== undefined &&
1136
- resultStr !== "" &&
1137
- !(resultStr + "").startsWith("[EXPIMG]")
1285
+ resultStr !== null
1286
+ && resultStr !== undefined
1287
+ && resultStr !== ""
1288
+ && !(resultStr + "").startsWith("[EXPIMG]")
1138
1289
  ) {
1139
1290
  resultStr = "[EXPIMG]" + resultStr;
1140
1291
  }
@@ -1185,13 +1336,13 @@ function getGrid(that, tableRef) {
1185
1336
  let cUUid = encodeURIComponent(row.uuid);
1186
1337
  let ippaaapp = this.ippaaapp;
1187
1338
  let fileName = row.title;
1188
- let fileUrl =
1189
- configUtil.baseUrl +
1190
- this.CURRENT_PREFIX +
1191
- "/excel/download?uuid=" +
1192
- cUUid +
1193
- "&ippaaapp=" +
1194
- ippaaapp;
1339
+ let fileUrl
1340
+ = configUtil.baseUrl
1341
+ + this.CURRENT_PREFIX
1342
+ + "/excel/download?uuid="
1343
+ + cUUid
1344
+ + "&ippaaapp="
1345
+ + ippaaapp;
1195
1346
 
1196
1347
  function downLoadFile2() {
1197
1348
  let params = {
@@ -1201,8 +1352,8 @@ function getGrid(that, tableRef) {
1201
1352
 
1202
1353
  let form = document.createElement("form");
1203
1354
 
1204
- let randomNum =
1205
- new Date().valueOf() + Math.floor(Math.random() * 1000000);
1355
+ let randomNum
1356
+ = new Date().valueOf() + Math.floor(Math.random() * 1000000);
1206
1357
  let formId = "formId-" + randomNum;
1207
1358
  let formName = "formName-" + randomNum;
1208
1359
 
@@ -1287,8 +1438,8 @@ function getGrid(that, tableRef) {
1287
1438
  this.tableTarget = getGrid(this.option.vue, this.option.targetRef);
1288
1439
  let that = this;
1289
1440
  let options = this.option;
1290
- let title =
1291
- options.title || this.$t2("导出", "components.excelExport.title");
1441
+ let title
1442
+ = options.title || this.$t2("导出", "components.excelExport.title");
1292
1443
  if (!options.prefix && options.prefix !== "") {
1293
1444
  let originOption = this.tableTarget.params.originOption;
1294
1445
  let path = originOption.exportPath || originOption.path;
@@ -44,6 +44,7 @@ import i18n from "../../../utils/i18n";
44
44
  import fieldMixin from "./fieldMixin";
45
45
  import StaticContentWrapper from "./static-content-wrapper.vue";
46
46
  import { EXPORT_TYPE } from "../../../../excelExport/exportType";
47
+ import { pickConditionExportOverrides } from "@base/components/excelExport/conditionExportConfig";
47
48
 
48
49
  export default {
49
50
  name: "select-export-item-button-widget",
@@ -101,8 +102,8 @@ export default {
101
102
  let opt = {
102
103
  title: this.field.options.exportFileName || null,
103
104
  targetRef: this.field.options.tableRef || null,
104
- pageSize: this.field.options.exportPageSize || null,
105
105
  showImageAtTable: this.field.options.showImageAtTable || null,
106
+ ...pickConditionExportOverrides(this.field.options),
106
107
  // 明细导出的列 / 脚本编码 / 取数参数三项各自独立:按钮上维护了哪项就以哪项为准,
107
108
  // 留空的那项沿用数据表格属性上那套。参数脚本原样下发,由数据表格求值(this 是
108
109
  // 表格组件,与配在表格属性上时同义)
@@ -32,6 +32,7 @@ import emitter from "../../../../../components/xform/utils/emitter";
32
32
  import i18n from "../../../../../components/xform/utils/i18n";
33
33
  import fieldMixin from "../../../../../components/xform/form-designer/form-widget/field-widget/fieldMixin";
34
34
  import StaticContentWrapper from "../../../../../components/xform/form-designer/form-widget/field-widget/static-content-wrapper.vue";
35
+ import { pickConditionExportOverrides } from "@base/components/excelExport/conditionExportConfig";
35
36
 
36
37
  export default {
37
38
  name: "table-export-button-widget",
@@ -81,8 +82,8 @@ export default {
81
82
  let opt = {
82
83
  title: this.field.options.exportFileName || null,
83
84
  targetRef: this.field.options.tableRef || null,
84
- pageSize: this.field.options.exportPageSize || null,
85
85
  showImageAtTable: this.field.options.showImageAtTable || null,
86
+ ...pickConditionExportOverrides(this.field.options),
86
87
  };
87
88
  let tableExportParam = this.handleCustomEvent(this.field.options.tableExportParam);
88
89
  let options = { ...opt, ...tableExportParam, type: type };
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <base-input-number
3
+ :value="innerValue"
4
+ v-bind="$attrs"
5
+ v-on="listeners"
6
+ @input="onInput"
7
+ />
8
+ </template>
9
+
10
+ <script>
11
+ /**
12
+ * 未配置(null / undefined / 非正数)时显示空白,而不是 el-input-number 默认的 0。
13
+ * 清空后回写 null,运行时会回落到全局逻辑参数。
14
+ */
15
+ function toDisplayNumber(value) {
16
+ if (value == null || value === "") return undefined;
17
+ let num = Number(value);
18
+ if (!Number.isFinite(num) || num <= 0) return undefined;
19
+ return num;
20
+ }
21
+
22
+ function toStoredNumber(value) {
23
+ if (value == null || value === "") return null;
24
+ let num = Number(value);
25
+ if (!Number.isFinite(num) || num <= 0) return null;
26
+ return num;
27
+ }
28
+
29
+ export default {
30
+ name: "empty-number-input",
31
+ inheritAttrs: false,
32
+ props: {
33
+ value: {},
34
+ },
35
+ computed: {
36
+ innerValue() {
37
+ return toDisplayNumber(this.value);
38
+ },
39
+ listeners() {
40
+ let listeners = Object.assign({}, this.$listeners);
41
+ delete listeners.input;
42
+ return listeners;
43
+ },
44
+ },
45
+ methods: {
46
+ onInput(val) {
47
+ this.$emit("input", toStoredNumber(val));
48
+ },
49
+ },
50
+ };
51
+ </script>
@@ -19,10 +19,29 @@
19
19
  ></el-switch>
20
20
  </el-form-item>
21
21
  <el-form-item label="导出每页查询数量" class="form-item-label-top">
22
- <base-input-number
22
+ <empty-number-input
23
23
  v-model="optionModel.exportPageSize"
24
24
  :max="optionModel.showImageAtTable ? 150 : 1000"
25
- ></base-input-number>
25
+ :placeholder="'默认 ' + defaultPageSize"
26
+ ></empty-number-input>
27
+ </el-form-item>
28
+ <el-form-item label="最大查询总数" class="form-item-label-top">
29
+ <empty-number-input
30
+ v-model="optionModel.maxQueryTotal"
31
+ :placeholder="'默认 ' + defaultMaxQueryTotal"
32
+ ></empty-number-input>
33
+ <div class="export-item-columns-tip">
34
+ 条件导出最多拉取的行数。留空则使用全局逻辑参数(默认 {{ defaultMaxQueryTotal }})
35
+ </div>
36
+ </el-form-item>
37
+ <el-form-item label="每个文件最大数据量" class="form-item-label-top">
38
+ <empty-number-input
39
+ v-model="optionModel.limitFileSize"
40
+ :placeholder="'默认 ' + defaultLimitFileSize"
41
+ ></empty-number-input>
42
+ <div class="export-item-columns-tip">
43
+ 单个 Excel 最多行数,超出则分多个文件。留空则使用全局逻辑参数(默认 {{ defaultLimitFileSize }})
44
+ </div>
26
45
  </el-form-item>
27
46
  <el-form-item label="导出参数" label-width="150px">
28
47
  <a
@@ -80,12 +99,15 @@
80
99
  import i18n from "../../../../utils/i18n";
81
100
  import eventMixin from "../event-handler/eventMixin";
82
101
  import exportItemColumnsDialog from "../container-data-table/exportItemColumns-dialog.vue";
102
+ import { DEFAULT_CONDITION_EXPORT_CONFIG } from "@base/components/excelExport/conditionExportConfig";
103
+ import emptyNumberInput from "./empty-number-input.vue";
83
104
 
84
105
  export default {
85
106
  name: "select-export-item-button-editor",
86
107
  mixins: [i18n, eventMixin],
87
108
  components: {
88
109
  exportItemColumnsDialog,
110
+ emptyNumberInput,
89
111
  },
90
112
  props: {
91
113
  designer: Object,
@@ -98,6 +120,9 @@ export default {
98
120
  // 与数据表格属性面板同一套:脚本里可直接用 dataId / formCode
99
121
  tableConfigParams: ["dataId", "formCode"],
100
122
  showExportItemColumnsDialog: false,
123
+ defaultPageSize: DEFAULT_CONDITION_EXPORT_CONFIG.pageSize,
124
+ defaultMaxQueryTotal: DEFAULT_CONDITION_EXPORT_CONFIG.maxQueryTotal,
125
+ defaultLimitFileSize: DEFAULT_CONDITION_EXPORT_CONFIG.limitFileSize,
101
126
  };
102
127
  },
103
128
  methods: {
@@ -13,8 +13,23 @@
13
13
  <el-switch v-model="optionModel.showImageAtTable" @change="changeShowImageAtTable"></el-switch>
14
14
  </el-form-item>
15
15
  <el-form-item label="导出每页查询数量" class="form-item-label-top">
16
- <base-input-number v-model="optionModel.exportPageSize"
17
- :max="optionModel.showImageAtTable?150:1000"></base-input-number>
16
+ <empty-number-input v-model="optionModel.exportPageSize"
17
+ :max="optionModel.showImageAtTable?150:1000"
18
+ :placeholder="'默认 ' + defaultPageSize"></empty-number-input>
19
+ </el-form-item>
20
+ <el-form-item label="最大查询总数" class="form-item-label-top">
21
+ <empty-number-input v-model="optionModel.maxQueryTotal"
22
+ :placeholder="'默认 ' + defaultMaxQueryTotal"></empty-number-input>
23
+ <div class="export-limit-tip">
24
+ 条件导出最多拉取的行数。留空则使用全局逻辑参数(默认 {{ defaultMaxQueryTotal }})
25
+ </div>
26
+ </el-form-item>
27
+ <el-form-item label="每个文件最大数据量" class="form-item-label-top">
28
+ <empty-number-input v-model="optionModel.limitFileSize"
29
+ :placeholder="'默认 ' + defaultLimitFileSize"></empty-number-input>
30
+ <div class="export-limit-tip">
31
+ 单个 Excel 最多行数,超出则分多个文件。留空则使用全局逻辑参数(默认 {{ defaultLimitFileSize }})
32
+ </div>
18
33
  </el-form-item>
19
34
  <el-form-item label="导出参数" label-width="150px">
20
35
  <a href="javascript:void(0);" class="a-link link-oneLind"
@@ -30,10 +45,15 @@
30
45
  import i18n from "../../../../../../components/xform/utils/i18n";
31
46
  import eventMixin
32
47
  from "../../../../../../components/xform/form-designer/setting-panel/property-editor/event-handler/eventMixin";
48
+ import { DEFAULT_CONDITION_EXPORT_CONFIG } from "@base/components/excelExport/conditionExportConfig";
49
+ import emptyNumberInput from "./empty-number-input.vue";
33
50
 
34
51
  export default {
35
52
  name: "table-export-button-editor",
36
53
  mixins: [i18n, eventMixin],
54
+ components: {
55
+ emptyNumberInput,
56
+ },
37
57
  props: {
38
58
  designer: Object,
39
59
  selectedWidget: Object,
@@ -42,6 +62,9 @@ export default {
42
62
  data() {
43
63
  return {
44
64
  eventParams: [],
65
+ defaultPageSize: DEFAULT_CONDITION_EXPORT_CONFIG.pageSize,
66
+ defaultMaxQueryTotal: DEFAULT_CONDITION_EXPORT_CONFIG.maxQueryTotal,
67
+ defaultLimitFileSize: DEFAULT_CONDITION_EXPORT_CONFIG.limitFileSize,
45
68
  };
46
69
  },
47
70
  methods: {
@@ -57,4 +80,11 @@ export default {
57
80
  };
58
81
  </script>
59
82
 
60
- <style scoped></style>
83
+ <style scoped>
84
+ .export-limit-tip {
85
+ line-height: 18px;
86
+ color: #909399;
87
+ font-size: 12px;
88
+ margin-top: 4px;
89
+ }
90
+ </style>
@@ -3287,6 +3287,9 @@ export const advancedFields = [
3287
3287
  tableRef: "",
3288
3288
  tableExportParam: "",
3289
3289
  showImageAtTable: false,
3290
+ exportPageSize: null,
3291
+ maxQueryTotal: null,
3292
+ limitFileSize: null,
3290
3293
  tableExportFlag: 1,
3291
3294
 
3292
3295
  onCreated: "",
@@ -3351,6 +3354,9 @@ export const advancedFields = [
3351
3354
  tableRef: "",
3352
3355
  tableExportParam: "",
3353
3356
  showImageAtTable: false,
3357
+ exportPageSize: null,
3358
+ maxQueryTotal: null,
3359
+ limitFileSize: null,
3354
3360
  selectExportItemFlag: 1,
3355
3361
  exportItemConditionEnabled: !1,
3356
3362
  // 按钮级明细导出配置:三项各自独立,留空的那项沿用数据表格属性上维护的
@@ -2798,7 +2798,9 @@ modules = {
2798
2798
  if (
2799
2799
  customParam?.exportParam?.type !== EXPORT_TYPE.ITEM_SELECTED
2800
2800
  ) {
2801
- formData = tableOption.param ? tableOption.param() || {} : {};
2801
+ formData = customParam?.exportParam?.exportQuerySnapshot !== undefined
2802
+ ? this.$baseLodash.cloneDeep(customParam.exportParam.exportQuerySnapshot)
2803
+ : tableOption.param ? tableOption.param() || {} : {};
2802
2804
  }
2803
2805
  const queryParams = Object.assign({}, formData);
2804
2806