gm-printer 10.41.9 → 10.42.0
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/build/demo.js +9 -9
- package/package.json +1 -1
- package/src/common/editor_customize_config.js +3 -0
- package/src/common/editor_store.js +219 -23
- package/src/index.js +4 -2
- package/src/printer/compute_pages.js +122 -0
- package/src/printer/index.js +3 -1
- package/src/printer/multi_column.js +461 -0
- package/src/printer/printer.js +34 -15
- package/src/printer/store.js +297 -33
- package/src/printer/table.js +3 -7
- package/src/util.js +13 -10
package/src/printer/store.js
CHANGED
|
@@ -3,6 +3,8 @@ import { action, observable, computed } from 'mobx'
|
|
|
3
3
|
import {
|
|
4
4
|
getSumTrHeight,
|
|
5
5
|
isMultiTable,
|
|
6
|
+
getMultiNumber,
|
|
7
|
+
getDataKey,
|
|
6
8
|
caclSingleDetailsPageHeight,
|
|
7
9
|
getArrayMid,
|
|
8
10
|
getOverallOrderTrHeight
|
|
@@ -11,6 +13,20 @@ import { isIndependentRolDataKey } from '../common/data_key_util'
|
|
|
11
13
|
import _ from 'lodash'
|
|
12
14
|
import Big from 'big.js'
|
|
13
15
|
import { Tip } from '../components'
|
|
16
|
+
import {
|
|
17
|
+
fillEmptyRowIndex,
|
|
18
|
+
fillPartialLastRow,
|
|
19
|
+
getMaxSerial,
|
|
20
|
+
detectColNumber,
|
|
21
|
+
ensureRowSerialKeys,
|
|
22
|
+
flattenHorizontalPackedRows,
|
|
23
|
+
repackVerticalTableByPageRanges,
|
|
24
|
+
packVerticalNewspaper,
|
|
25
|
+
packHorizontalRowMajor,
|
|
26
|
+
createEmptyRows,
|
|
27
|
+
createEmptyRowSkeleton,
|
|
28
|
+
resolveVerticalEmptyCount
|
|
29
|
+
} from './multi_column'
|
|
14
30
|
|
|
15
31
|
export const TR_BASE_HEIGHT = 23
|
|
16
32
|
|
|
@@ -48,6 +64,8 @@ class PrinterStore {
|
|
|
48
64
|
/** 当前页剩余空白高度 */
|
|
49
65
|
@observable remainPageHeight = 0
|
|
50
66
|
@observable isSave = false
|
|
67
|
+
/** data._table 非 observable,变更后递增以驱动预览重渲 */
|
|
68
|
+
@observable dataRevision = 0
|
|
51
69
|
|
|
52
70
|
data = {}
|
|
53
71
|
|
|
@@ -217,6 +235,19 @@ class PrinterStore {
|
|
|
217
235
|
this.config = config || {}
|
|
218
236
|
}
|
|
219
237
|
|
|
238
|
+
/**
|
|
239
|
+
* 签名区高度:优先 DOM 测高,否则用配置 style.height。
|
|
240
|
+
* 打印在 iframe 内时测高常为 0,若只用 this.height.sign 会导致末页不扣签名、空行多填。
|
|
241
|
+
*/
|
|
242
|
+
getSignHeight() {
|
|
243
|
+
const measured = this.height?.sign
|
|
244
|
+
if (measured && measured > 0) return measured
|
|
245
|
+
const raw = this.config?.sign?.style?.height
|
|
246
|
+
if (raw == null || raw === '') return 0
|
|
247
|
+
const parsed = parseFloat(raw)
|
|
248
|
+
return Number.isFinite(parsed) ? parsed : 0
|
|
249
|
+
}
|
|
250
|
+
|
|
220
251
|
/** 处理采购单的明细
|
|
221
252
|
一行有多个明细, 并且采购明细是换行展示, 明细数据超多的情况则需要分割到不同页面中
|
|
222
253
|
比如: 一行有20行明细,当前页只能放下17行明细 ,剩下的3行明细需要放到下一页进行展示 */
|
|
@@ -357,9 +388,12 @@ class PrinterStore {
|
|
|
357
388
|
/** 当前page页面的最小高度 */
|
|
358
389
|
const currentPageMinimumHeight =
|
|
359
390
|
allPagesHaveThisHeight + allTableHaveThisHeight
|
|
391
|
+
// 最后一项是表格时,末页仍要渲染签名:装行可用高度预留签名,避免空行顶进签名区
|
|
392
|
+
const isLastContent = index === this.config.contents.length - 1
|
|
393
|
+
const signReserve = isLastContent ? this.getSignHeight() : 0
|
|
360
394
|
/** 当前page可容纳的table高度 */
|
|
361
395
|
let pageAccomodateTableHeight = roundHeight(
|
|
362
|
-
pageHeight - currentPageHeight
|
|
396
|
+
pageHeight - currentPageHeight - signReserve
|
|
363
397
|
)
|
|
364
398
|
// 拷贝一份行高数组,避免 splice 触发 observable 副作用
|
|
365
399
|
const heights = [
|
|
@@ -492,9 +526,9 @@ class PrinterStore {
|
|
|
492
526
|
}
|
|
493
527
|
|
|
494
528
|
begin = end
|
|
495
|
-
//
|
|
529
|
+
// 开启新一页,重置页面高度(末项表格仍预留签名)
|
|
496
530
|
pageAccomodateTableHeight = roundHeight(
|
|
497
|
-
pageHeight - allPagesHaveThisHeight
|
|
531
|
+
pageHeight - allPagesHaveThisHeight - signReserve
|
|
498
532
|
)
|
|
499
533
|
currentTableHeight = allTableHaveThisHeight
|
|
500
534
|
currentPageHeight = currentPageMinimumHeight
|
|
@@ -534,7 +568,7 @@ class PrinterStore {
|
|
|
534
568
|
|
|
535
569
|
// 如果是最后一页,必须要加上sign的高度,否则会重叠
|
|
536
570
|
if (index === contentsLength - 1) {
|
|
537
|
-
currentPageHeight +=
|
|
571
|
+
currentPageHeight += this.getSignHeight()
|
|
538
572
|
}
|
|
539
573
|
|
|
540
574
|
if (currentPageHeight <= pageHeight) {
|
|
@@ -557,9 +591,88 @@ class PrinterStore {
|
|
|
557
591
|
}
|
|
558
592
|
pages.push(page)
|
|
559
593
|
this.pages = pages
|
|
560
|
-
|
|
594
|
+
|
|
595
|
+
// 末页签名:panel 分支会在「最后一项是 panel」时扣 sign;
|
|
596
|
+
// 最后一项是 table 时上面不会扣,导致 remain 偏大、空行多填溢页
|
|
597
|
+
// 打印 iframe 内 height.sign 可能为 0,必须用 getSignHeight(含配置兜底)
|
|
598
|
+
const lastContent = contents[contentsLength - 1]
|
|
599
|
+
if (lastContent?.type === 'table') {
|
|
600
|
+
currentPageHeight += this.getSignHeight()
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
this.remainPageHeight = Math.max(
|
|
604
|
+
0,
|
|
605
|
+
Math.round(pageHeight - currentPageHeight)
|
|
606
|
+
)
|
|
561
607
|
this.isSave = false
|
|
562
608
|
this.config.isSave = false
|
|
609
|
+
this.repackVerticalMultiByPages()
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
getTablePageRanges(contentIndex, rows) {
|
|
613
|
+
const ranges = []
|
|
614
|
+
this.pages.forEach(page => {
|
|
615
|
+
page.forEach(panel => {
|
|
616
|
+
if (panel.type === 'table' && panel.index === contentIndex) {
|
|
617
|
+
ranges.push({ begin: panel.begin, end: panel.end })
|
|
618
|
+
}
|
|
619
|
+
})
|
|
620
|
+
})
|
|
621
|
+
if (!ranges.length || !rows?.length) return ranges
|
|
622
|
+
const last = ranges[ranges.length - 1]
|
|
623
|
+
let end = last.end
|
|
624
|
+
while (end < rows.length && rows[end]?._isEmptyData) {
|
|
625
|
+
end++
|
|
626
|
+
}
|
|
627
|
+
last.end = end
|
|
628
|
+
return ranges
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
@action
|
|
632
|
+
repackVerticalMultiByPages() {
|
|
633
|
+
if (!this.pages?.length) return
|
|
634
|
+
this.config.contents.forEach((content, contentIndex) => {
|
|
635
|
+
if (content?.type !== 'table' || !isMultiTable(content.dataKey)) {
|
|
636
|
+
return
|
|
637
|
+
}
|
|
638
|
+
const dataKey = content.dataKey
|
|
639
|
+
const isVertical =
|
|
640
|
+
content.arrange === 'vertical' || /_vertical$/.test(dataKey)
|
|
641
|
+
if (!isVertical) return
|
|
642
|
+
|
|
643
|
+
const sourceKey = dataKey.replace(/_vertical$/, '')
|
|
644
|
+
const verticalKey = /_vertical$/.test(dataKey)
|
|
645
|
+
? dataKey
|
|
646
|
+
: `${sourceKey}_vertical`
|
|
647
|
+
const colNumber = getMultiNumber(sourceKey)
|
|
648
|
+
const verticalRows = this.data._table[verticalKey]
|
|
649
|
+
if (!verticalRows?.length) return
|
|
650
|
+
|
|
651
|
+
const singleKey = sourceKey.replace(/_multi3?/, '')
|
|
652
|
+
const sourceRows =
|
|
653
|
+
this.data._table[singleKey] || this.data._table[sourceKey] || []
|
|
654
|
+
const sourceColNumber = isMultiTable(singleKey)
|
|
655
|
+
? getMultiNumber(singleKey)
|
|
656
|
+
: isMultiTable(sourceKey)
|
|
657
|
+
? colNumber
|
|
658
|
+
: 1
|
|
659
|
+
const sourceItems = flattenHorizontalPackedRows(
|
|
660
|
+
sourceRows,
|
|
661
|
+
sourceColNumber
|
|
662
|
+
)
|
|
663
|
+
// 无商品时仍可能需要给空行按列编序号
|
|
664
|
+
if (!sourceItems.length && !this.fillIndex) return
|
|
665
|
+
|
|
666
|
+
const pageRanges = this.getTablePageRanges(contentIndex, verticalRows)
|
|
667
|
+
this.data._table[verticalKey] = repackVerticalTableByPageRanges(
|
|
668
|
+
verticalRows,
|
|
669
|
+
colNumber,
|
|
670
|
+
pageRanges,
|
|
671
|
+
this.fillIndex,
|
|
672
|
+
sourceItems
|
|
673
|
+
)
|
|
674
|
+
this.dataRevision += 1
|
|
675
|
+
})
|
|
563
676
|
}
|
|
564
677
|
|
|
565
678
|
@action
|
|
@@ -670,7 +783,7 @@ class PrinterStore {
|
|
|
670
783
|
}
|
|
671
784
|
|
|
672
785
|
templateTable(text, dataKey, index, pageIndex) {
|
|
673
|
-
//
|
|
786
|
+
// 做好保护,出错就返回空串(勿回传原始 {{}},否则单元格会露出模板)
|
|
674
787
|
try {
|
|
675
788
|
let list = this.data._table[dataKey] || this.data._table.orders
|
|
676
789
|
|
|
@@ -679,18 +792,34 @@ class PrinterStore {
|
|
|
679
792
|
list = _.uniqBy(list, '序号')
|
|
680
793
|
}
|
|
681
794
|
|
|
795
|
+
const colNumber = detectColNumber(dataKey, list)
|
|
796
|
+
const sample = (list || []).find(item => item && !item._isEmptyData)
|
|
797
|
+
let row = list?.[index]
|
|
798
|
+
// 渲染 end 偶发超过数据长度时,用空行骨架兜底,避免 列=undefined 抛错露出 {{列.xxx_MULTI_SUFFIX}}
|
|
799
|
+
if (!row) {
|
|
800
|
+
if (!this.isAutoFilling) return ''
|
|
801
|
+
list = (list || []).slice()
|
|
802
|
+
while (list.length <= index) {
|
|
803
|
+
list.push(createEmptyRowSkeleton(sample, colNumber))
|
|
804
|
+
}
|
|
805
|
+
row = list[index]
|
|
806
|
+
}
|
|
807
|
+
row =
|
|
808
|
+
ensureRowSerialKeys(list, index, colNumber, this.fillIndex, dataKey) ||
|
|
809
|
+
row
|
|
810
|
+
|
|
682
811
|
return _.template(text, {
|
|
683
812
|
interpolate: /{{([\s\S]+?)}}/g
|
|
684
813
|
})({
|
|
685
814
|
...this.data.common,
|
|
686
815
|
|
|
687
|
-
[i18next.t('列')]:
|
|
816
|
+
[i18next.t('列')]: row,
|
|
688
817
|
[i18next.t('当前页码')]: pageIndex + 1,
|
|
689
818
|
[i18next.t('页码总数')]: Math.max(1, this.pages.length),
|
|
690
819
|
price: price // 提供一个价格处理函数
|
|
691
820
|
})
|
|
692
821
|
} catch (err) {
|
|
693
|
-
return
|
|
822
|
+
return ''
|
|
694
823
|
}
|
|
695
824
|
}
|
|
696
825
|
|
|
@@ -763,41 +892,176 @@ class PrinterStore {
|
|
|
763
892
|
const tr_count = Math.floor(
|
|
764
893
|
this.remainPageHeight / this.computedTableCustomerRowHeight
|
|
765
894
|
)
|
|
895
|
+
if (tr_count <= 0) return []
|
|
766
896
|
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
897
|
+
const sample = (tableData || []).find(item => item && !item._isEmptyData)
|
|
898
|
+
const colNumber = detectColNumber(
|
|
899
|
+
this.tableConfig?.dataKey || autoFillConfig?.dataKey,
|
|
900
|
+
tableData
|
|
901
|
+
)
|
|
902
|
+
return createEmptyRows(tr_count, sample, colNumber)
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/** 空行高度只由 getNormalTableBodyHeights 虚拟追加,禁止写入 body.heights(会双计溢页) */
|
|
906
|
+
@action
|
|
907
|
+
trimTableBodyHeightsToRealRows(dataKey) {
|
|
908
|
+
if (!dataKey || !this.tablesInfo) return
|
|
909
|
+
this.config.contents.forEach((content, index) => {
|
|
910
|
+
if (content?.type !== 'table') return
|
|
911
|
+
const resolved = getDataKey(content.dataKey, content.arrange)
|
|
912
|
+
if (resolved !== dataKey && content.dataKey !== dataKey) return
|
|
913
|
+
|
|
914
|
+
const name = `contents.table.${index}`
|
|
915
|
+
const info = this.tablesInfo[name]
|
|
916
|
+
if (!info?.body?.heights) return
|
|
917
|
+
|
|
918
|
+
const rows = this.data._table[resolved] || this.data._table[dataKey] || []
|
|
919
|
+
const realCount = rows.filter(row => row && !row._isEmptyData).length
|
|
920
|
+
if (info.body.heights.length > realCount) {
|
|
921
|
+
info.body.heights = info.body.heights.slice(0, realCount)
|
|
922
|
+
}
|
|
772
923
|
})
|
|
773
|
-
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/** 多栏表缺失时(如双栏切三栏),从单栏/低栏源表现场打包 */
|
|
927
|
+
ensureMultiTableData(dataKey) {
|
|
928
|
+
const existing = this.data._table[dataKey]
|
|
929
|
+
if (existing?.length) return existing
|
|
930
|
+
if (!isMultiTable(dataKey)) return existing || null
|
|
931
|
+
|
|
932
|
+
const isVertical = /_vertical$/.test(dataKey)
|
|
933
|
+
const sourceKey = dataKey.replace(/_vertical$/, '')
|
|
934
|
+
const colNumber = getMultiNumber(sourceKey)
|
|
935
|
+
const singleKey = sourceKey.replace(/_multi3?/, '')
|
|
936
|
+
|
|
937
|
+
let sourceRows = this.data._table[singleKey]
|
|
938
|
+
let sourceColNumber = 1
|
|
939
|
+
if (!sourceRows?.length && /multi3/.test(sourceKey)) {
|
|
940
|
+
const dualKey = sourceKey.replace('multi3', 'multi')
|
|
941
|
+
sourceRows = this.data._table[dualKey]
|
|
942
|
+
sourceColNumber = 2
|
|
943
|
+
}
|
|
944
|
+
if (!sourceRows?.length) {
|
|
945
|
+
sourceRows = this.data._table[sourceKey]
|
|
946
|
+
sourceColNumber = isMultiTable(sourceKey) ? colNumber : 1
|
|
947
|
+
}
|
|
948
|
+
if (!sourceRows?.length) {
|
|
949
|
+
this.data._table[dataKey] = []
|
|
950
|
+
return []
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
const sourceItems = flattenHorizontalPackedRows(sourceRows, sourceColNumber)
|
|
954
|
+
const baseRowCount = sourceItems.length
|
|
955
|
+
? Math.max(1, Math.ceil(sourceItems.length / colNumber))
|
|
956
|
+
: 0
|
|
957
|
+
const packed = !baseRowCount
|
|
958
|
+
? []
|
|
959
|
+
: isVertical
|
|
960
|
+
? packVerticalNewspaper(sourceItems, colNumber, baseRowCount, false)
|
|
961
|
+
: packHorizontalRowMajor(sourceItems, colNumber)
|
|
962
|
+
this.data._table[dataKey] = packed
|
|
963
|
+
return packed
|
|
964
|
+
}
|
|
774
965
|
|
|
775
|
-
|
|
966
|
+
fillTableEmptyIndex(dataKey) {
|
|
967
|
+
let tableData = this.data._table[dataKey]
|
|
968
|
+
if (!tableData && isMultiTable(dataKey)) {
|
|
969
|
+
tableData = this.ensureMultiTableData(dataKey)
|
|
970
|
+
}
|
|
971
|
+
if (!tableData) return
|
|
972
|
+
const emptyTable = tableData.filter(item => item._isEmptyData)
|
|
973
|
+
const table = tableData.filter(item => !item._isEmptyData)
|
|
974
|
+
const toFillEmptyCount =
|
|
975
|
+
emptyTable.length === 0 ? this.getFilledTableData(table).length : 0
|
|
976
|
+
const emptyCount =
|
|
977
|
+
emptyTable.length > 0 ? emptyTable.length : toFillEmptyCount
|
|
978
|
+
|
|
979
|
+
// 纵向多栏:源商品按对半行落位 + 追加空行;左列优先由 repack 按「数据行+空行」整段完成
|
|
980
|
+
if (/_vertical$/.test(dataKey)) {
|
|
981
|
+
const sourceKey = dataKey.replace(/_vertical$/, '')
|
|
982
|
+
const singleKey = sourceKey.replace(/_multi3?/, '')
|
|
983
|
+
const colNumber = getMultiNumber(sourceKey)
|
|
984
|
+
// 横向源表缺失时先生成(双栏→三栏常见)
|
|
985
|
+
if (!this.data._table[sourceKey]?.length) {
|
|
986
|
+
this.ensureMultiTableData(sourceKey)
|
|
987
|
+
}
|
|
988
|
+
const sourceRows =
|
|
989
|
+
this.data._table[singleKey] || this.data._table[sourceKey] || []
|
|
990
|
+
const sourceColNumber = isMultiTable(singleKey)
|
|
991
|
+
? getMultiNumber(singleKey)
|
|
992
|
+
: isMultiTable(sourceKey)
|
|
993
|
+
? colNumber
|
|
994
|
+
: 1
|
|
995
|
+
const sourceItems = flattenHorizontalPackedRows(
|
|
996
|
+
sourceRows,
|
|
997
|
+
sourceColNumber
|
|
998
|
+
)
|
|
999
|
+
const baseRowCount = sourceItems.length
|
|
1000
|
+
? Math.max(1, Math.ceil(sourceItems.length / colNumber))
|
|
1001
|
+
: 0
|
|
1002
|
+
// 钉死总行:left-first repack 后 _isEmptyData 变少,不能用 emptyTable.length 回推
|
|
1003
|
+
const emptyCount = resolveVerticalEmptyCount(
|
|
1004
|
+
tableData.length,
|
|
1005
|
+
baseRowCount,
|
|
1006
|
+
emptyTable.length > 0
|
|
1007
|
+
? emptyTable.length
|
|
1008
|
+
: this.getFilledTableData(table).length,
|
|
1009
|
+
emptyTable.length > 0
|
|
1010
|
+
)
|
|
1011
|
+
const dataRows = baseRowCount
|
|
1012
|
+
? packVerticalNewspaper(sourceItems, colNumber, baseRowCount, false)
|
|
1013
|
+
: []
|
|
1014
|
+
const sample = dataRows[0] || sourceRows[0]
|
|
1015
|
+
const emptyRows = createEmptyRows(emptyCount, sample, colNumber)
|
|
1016
|
+
this.data._table[dataKey] = dataRows.concat(emptyRows)
|
|
1017
|
+
return
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
const colNumber = detectColNumber(dataKey, tableData)
|
|
1021
|
+
const templates =
|
|
1022
|
+
emptyCount === 0
|
|
1023
|
+
? []
|
|
1024
|
+
: emptyTable.length > 0
|
|
1025
|
+
? emptyTable
|
|
1026
|
+
: this.getFilledTableData(table)
|
|
1027
|
+
const withPartial = fillPartialLastRow(table, colNumber, this.fillIndex)
|
|
1028
|
+
const lastKey = getMaxSerial(withPartial, colNumber) + 1
|
|
1029
|
+
const sample = table[0]
|
|
1030
|
+
const fillList = templates.map((item, index) =>
|
|
1031
|
+
fillEmptyRowIndex(
|
|
1032
|
+
{
|
|
1033
|
+
...createEmptyRowSkeleton(sample, colNumber),
|
|
1034
|
+
...item,
|
|
1035
|
+
_isEmptyData: true
|
|
1036
|
+
},
|
|
1037
|
+
index,
|
|
1038
|
+
lastKey,
|
|
1039
|
+
colNumber,
|
|
1040
|
+
this.fillIndex
|
|
1041
|
+
)
|
|
1042
|
+
)
|
|
1043
|
+
withPartial.push(...fillList)
|
|
1044
|
+
this.data._table[dataKey] = withPartial
|
|
776
1045
|
}
|
|
777
1046
|
|
|
778
1047
|
@action.bound
|
|
779
1048
|
changeTableData() {
|
|
780
1049
|
const { autoFillConfig } = this.config
|
|
781
1050
|
if (!this.isAutoFilling) return
|
|
782
|
-
const dataKey = autoFillConfig?.dataKey
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
)
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
if (this.fillIndex) {
|
|
792
|
-
return { ...item, 序号: index + lastKey }
|
|
793
|
-
} else {
|
|
794
|
-
return { ...item, 序号: '' }
|
|
795
|
-
}
|
|
1051
|
+
const dataKey = this.tableConfig?.dataKey || autoFillConfig?.dataKey
|
|
1052
|
+
if (!dataKey) return
|
|
1053
|
+
this.fillTableEmptyIndex(dataKey)
|
|
1054
|
+
// 测高只含商品行;空行高度交给 getNormalTableBodyHeights,避免写入 heights 双计
|
|
1055
|
+
this.trimTableBodyHeightsToRealRows(dataKey)
|
|
1056
|
+
if (isMultiTable(dataKey)) {
|
|
1057
|
+
const verticalKey = getDataKey(dataKey, 'vertical')
|
|
1058
|
+
if (!this.data._table[verticalKey]) {
|
|
1059
|
+
this.data._table[verticalKey] = []
|
|
796
1060
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
this.
|
|
1061
|
+
this.fillTableEmptyIndex(verticalKey)
|
|
1062
|
+
this.trimTableBodyHeightsToRealRows(verticalKey)
|
|
1063
|
+
}
|
|
1064
|
+
this.repackVerticalMultiByPages()
|
|
801
1065
|
}
|
|
802
1066
|
}
|
|
803
1067
|
|
package/src/printer/table.js
CHANGED
|
@@ -360,15 +360,11 @@ class Table extends React.Component {
|
|
|
360
360
|
}
|
|
361
361
|
|
|
362
362
|
// 如果项为空对象展现一个占满一行的td
|
|
363
|
-
const isItemNone = !_.keys(tableData[i]).length
|
|
363
|
+
const isItemNone = !_.keys(tableData[i] || {}).length
|
|
364
364
|
return (
|
|
365
365
|
<tr style={{ height: `${customerRowHeight}px` }} key={i}>
|
|
366
|
-
{isItemNone ? (
|
|
367
|
-
|
|
368
|
-
<td colSpan='99' />
|
|
369
|
-
) : (
|
|
370
|
-
<></>
|
|
371
|
-
)
|
|
366
|
+
{isItemNone && !printerStore?.isAutoFilling ? (
|
|
367
|
+
<td colSpan='99' />
|
|
372
368
|
) : (
|
|
373
369
|
_.map(columns, (col, j) => {
|
|
374
370
|
const rowSpan = printerStore.templateTableRowSpan(
|
package/src/util.js
CHANGED
|
@@ -2,19 +2,23 @@ import _ from 'lodash'
|
|
|
2
2
|
import Big from 'big.js'
|
|
3
3
|
|
|
4
4
|
function getHeight(el) {
|
|
5
|
-
|
|
5
|
+
// 打印渲染在 iframe 内时,必须用元素所属 document 的 window,
|
|
6
|
+
// 否则 parent window.getComputedStyle 可能得到错误值、测高为 0
|
|
7
|
+
const view = (el.ownerDocument && el.ownerDocument.defaultView) || window
|
|
8
|
+
const styles = view.getComputedStyle(el)
|
|
6
9
|
const height = el.offsetHeight
|
|
7
|
-
const borderTopWidth = parseFloat(styles.borderTopWidth)
|
|
8
|
-
const borderBottomWidth = parseFloat(styles.borderBottomWidth)
|
|
9
|
-
const paddingTop = parseFloat(styles.paddingTop)
|
|
10
|
-
const paddingBottom = parseFloat(styles.paddingBottom)
|
|
10
|
+
const borderTopWidth = parseFloat(styles.borderTopWidth) || 0
|
|
11
|
+
const borderBottomWidth = parseFloat(styles.borderBottomWidth) || 0
|
|
12
|
+
const paddingTop = parseFloat(styles.paddingTop) || 0
|
|
13
|
+
const paddingBottom = parseFloat(styles.paddingBottom) || 0
|
|
11
14
|
return (
|
|
12
15
|
height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom
|
|
13
16
|
)
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
function getWidth(el) {
|
|
17
|
-
const
|
|
20
|
+
const view = (el.ownerDocument && el.ownerDocument.defaultView) || window
|
|
21
|
+
const styles = view.getComputedStyle(el)
|
|
18
22
|
// 取width保留小数点用 getBoundClientRect
|
|
19
23
|
const style = el.getBoundingClientRect()
|
|
20
24
|
const width = Math.round(style.width * 100) / 100 // 保留两位小数并四舍五入
|
|
@@ -82,13 +86,12 @@ function exchange(arr, target, source) {
|
|
|
82
86
|
return arr
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
let timer
|
|
86
|
-
|
|
87
89
|
function afterImgAndSvgLoaded(callback, $printer) {
|
|
88
90
|
const $imgList = $printer.querySelectorAll('img')
|
|
89
91
|
const $svgList = $printer.querySelectorAll('svg')
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
// timer 为函数内局部变量:computePages(导出测高)与 doPrint(打印)可能并发调用本函数,
|
|
94
|
+
// 若共享模块级 timer,后调用方会 clearTimeout 掉前一方的轮询,导致其 callback 永不执行
|
|
92
95
|
|
|
93
96
|
const everyThingIsOk =
|
|
94
97
|
_.every($imgList, img => img.complete) &&
|
|
@@ -96,7 +99,7 @@ function afterImgAndSvgLoaded(callback, $printer) {
|
|
|
96
99
|
if (everyThingIsOk) {
|
|
97
100
|
callback()
|
|
98
101
|
} else {
|
|
99
|
-
|
|
102
|
+
setTimeout(afterImgAndSvgLoaded.bind(this, callback, $printer), 300)
|
|
100
103
|
}
|
|
101
104
|
}
|
|
102
105
|
|