gm-printer 10.42.3 → 10.42.4-beta.1
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_sort_setting.js +143 -0
- package/src/common/editor_store.js +7 -3
- package/src/editor/editor.js +3 -0
- package/src/editor_account/editor.js +2 -0
- package/src/printer/multi_column.js +99 -43
- package/src/printer/store.js +25 -36
package/package.json
CHANGED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import _ from 'lodash'
|
|
4
|
+
import { observer, inject } from 'mobx-react'
|
|
5
|
+
import i18next from '../../locales'
|
|
6
|
+
import { Flex, Select, Option } from '../components'
|
|
7
|
+
import { Title, Gap, Radio } from './component'
|
|
8
|
+
|
|
9
|
+
// 排序方式常量,与宿主 sort_setting_util / 后端 parse_sort_setting 对齐
|
|
10
|
+
// product_row_sort.field:'' 不排序 / tax_rate 税率 / box_num 箱号 / sort_num 行号
|
|
11
|
+
const SORT_FIELD_LIST = [
|
|
12
|
+
{ value: '', text: i18next.t('不排序') },
|
|
13
|
+
{ value: 'tax_rate', text: i18next.t('税率') },
|
|
14
|
+
{ value: 'box_num', text: i18next.t('箱号') },
|
|
15
|
+
{ value: 'sort_num', text: i18next.t('行号') }
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
const SORT_DIRECTION_LIST = [
|
|
19
|
+
{ value: 'asc', text: i18next.t('升序') },
|
|
20
|
+
{ value: 'desc', text: i18next.t('降序') }
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
// order_sort.type:仅商户配送单模板提供(账户模板不渲染该组)
|
|
24
|
+
const ORDER_SORT_LIST = [
|
|
25
|
+
{ value: 'none', text: i18next.t('不排序') },
|
|
26
|
+
{ value: 'asc', text: i18next.t('按订单时间升序') },
|
|
27
|
+
{ value: 'desc', text: i18next.t('按订单时间降序') }
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 「排序方式」配置类:归集「商品行排序」「单据内订单顺序」两组子配置
|
|
32
|
+
* 读写 editStore.config.sort_setting(mobx4 读取不存在的键不建立依赖,
|
|
33
|
+
* 宿主传入 config 前需保证 sort_setting 键存在,无配置时为 null)
|
|
34
|
+
*/
|
|
35
|
+
@inject('editStore')
|
|
36
|
+
@observer
|
|
37
|
+
class SortSettingField extends React.Component {
|
|
38
|
+
getProductRowSort() {
|
|
39
|
+
return this.props.editStore.config.sort_setting?.product_row_sort || {}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getOrderSortType() {
|
|
43
|
+
return this.props.editStore.config.sort_setting?.order_sort?.type || 'none'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setSortSetting(sortSetting) {
|
|
47
|
+
this.props.editStore.config.sort_setting = sortSetting
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
handleFieldChange = field => {
|
|
51
|
+
const productRowSort = { ...this.getProductRowSort(), field }
|
|
52
|
+
this.setSortSetting({
|
|
53
|
+
...this.props.editStore.config.sort_setting,
|
|
54
|
+
product_row_sort: {
|
|
55
|
+
...productRowSort,
|
|
56
|
+
direction: productRowSort.direction || 'asc'
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
handleDirectionChange = direction => {
|
|
62
|
+
this.setSortSetting({
|
|
63
|
+
...this.props.editStore.config.sort_setting,
|
|
64
|
+
product_row_sort: { ...this.getProductRowSort(), direction }
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
handleOrderSortChange = type => {
|
|
69
|
+
this.setSortSetting({
|
|
70
|
+
...this.props.editStore.config.sort_setting,
|
|
71
|
+
order_sort: { type }
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
render() {
|
|
76
|
+
const { showOrderSort } = this.props
|
|
77
|
+
const productRowSort = this.getProductRowSort()
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div>
|
|
81
|
+
<Title title={i18next.t('排序方式')} />
|
|
82
|
+
<Gap height='5px' />
|
|
83
|
+
<Flex alignCenter className='gm-padding-top-5'>
|
|
84
|
+
<div>{i18next.t('商品行排序')}:</div>
|
|
85
|
+
<Select
|
|
86
|
+
className='gm-printer-edit-select'
|
|
87
|
+
value={productRowSort.field || ''}
|
|
88
|
+
onChange={this.handleFieldChange}
|
|
89
|
+
>
|
|
90
|
+
{_.map(SORT_FIELD_LIST, v => (
|
|
91
|
+
<Option key={v.value} value={v.value}>
|
|
92
|
+
{v.text}
|
|
93
|
+
</Option>
|
|
94
|
+
))}
|
|
95
|
+
</Select>
|
|
96
|
+
</Flex>
|
|
97
|
+
<Flex alignCenter className='gm-padding-top-5'>
|
|
98
|
+
<div>{i18next.t('排序方向')}:</div>
|
|
99
|
+
<Select
|
|
100
|
+
className='gm-printer-edit-select'
|
|
101
|
+
value={productRowSort.direction || 'asc'}
|
|
102
|
+
onChange={this.handleDirectionChange}
|
|
103
|
+
>
|
|
104
|
+
{_.map(SORT_DIRECTION_LIST, v => (
|
|
105
|
+
<Option key={v.value} value={v.value}>
|
|
106
|
+
{v.text}
|
|
107
|
+
</Option>
|
|
108
|
+
))}
|
|
109
|
+
</Select>
|
|
110
|
+
</Flex>
|
|
111
|
+
{showOrderSort && (
|
|
112
|
+
<>
|
|
113
|
+
<div className='gm-padding-top-5'>
|
|
114
|
+
{i18next.t('单据内订单顺序')}:
|
|
115
|
+
</div>
|
|
116
|
+
{_.map(ORDER_SORT_LIST, v => (
|
|
117
|
+
<Radio
|
|
118
|
+
key={v.value}
|
|
119
|
+
id={`sort_setting_order_${v.value}`}
|
|
120
|
+
value={v.text}
|
|
121
|
+
inputName='sort_setting_order_sort'
|
|
122
|
+
checked={this.getOrderSortType() === v.value}
|
|
123
|
+
radioChecked={this.handleOrderSortChange.bind(this, v.value)}
|
|
124
|
+
/>
|
|
125
|
+
))}
|
|
126
|
+
</>
|
|
127
|
+
)}
|
|
128
|
+
<Gap />
|
|
129
|
+
</div>
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
SortSettingField.propTypes = {
|
|
135
|
+
showOrderSort: PropTypes.bool,
|
|
136
|
+
editStore: PropTypes.object
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
SortSettingField.defaultProps = {
|
|
140
|
+
showOrderSort: false
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export default SortSettingField
|
|
@@ -238,7 +238,7 @@ class EditorStore {
|
|
|
238
238
|
}
|
|
239
239
|
}).join('/')
|
|
240
240
|
} else {
|
|
241
|
-
return v.style ? v.style.height : ''
|
|
241
|
+
return v && v.style ? v.style.height : ''
|
|
242
242
|
}
|
|
243
243
|
}).join('_')
|
|
244
244
|
}
|
|
@@ -1575,7 +1575,8 @@ class EditorStore {
|
|
|
1575
1575
|
const table = this.config.contents[arr[2]]
|
|
1576
1576
|
const prefix = getDataKeyPrefix(table.dataKey)
|
|
1577
1577
|
// 切换「按商品/按商户排序」时保留已开启的商品分类、双栏后缀,避免点完分类再切排序把 category 冲掉
|
|
1578
|
-
const baseSuffix =
|
|
1578
|
+
const baseSuffix =
|
|
1579
|
+
dataKey === 'goods' ? 'independent_rol_sku' : 'independent_rol_address'
|
|
1579
1580
|
const nextDataKey = buildDataKey(
|
|
1580
1581
|
prefix,
|
|
1581
1582
|
`${baseSuffix}${getDataKeyModifierSuffix(table.dataKey)}`
|
|
@@ -1606,7 +1607,10 @@ class EditorStore {
|
|
|
1606
1607
|
|
|
1607
1608
|
const { dataKey } = table
|
|
1608
1609
|
// independent_rol_* / detail_one_row_*(含 category、multi 后缀)在下拉里都映射回「按采购明细单行」
|
|
1609
|
-
if (
|
|
1610
|
+
if (
|
|
1611
|
+
isIndependentRolDataKey(dataKey) ||
|
|
1612
|
+
isDetailOneRowSelectKey(dataKey)
|
|
1613
|
+
) {
|
|
1610
1614
|
return buildDataKey(getDataKeyPrefix(dataKey), 'detail_one_row')
|
|
1611
1615
|
}
|
|
1612
1616
|
return dataKey
|
package/src/editor/editor.js
CHANGED
|
@@ -9,6 +9,7 @@ import EditorTitle from '../common/editor_title'
|
|
|
9
9
|
import EditorSelect from '../common/editor_select'
|
|
10
10
|
import SpecialField from '../common/editor_special_field'
|
|
11
11
|
import SpecialOtherField from '../common/editor_special_other_field'
|
|
12
|
+
import SortSettingField from '../common/editor_sort_setting'
|
|
12
13
|
import EditorField from '../common/editor_edit_field'
|
|
13
14
|
import EditorAddField from '../common/editor_add_field'
|
|
14
15
|
import EditorPageSummary from '../common/editor_page_summary'
|
|
@@ -88,6 +89,8 @@ class Editor extends React.Component {
|
|
|
88
89
|
<Gap height='5px' />
|
|
89
90
|
<SpecialField addFields={addFields} mockData={mockData} />
|
|
90
91
|
<SpecialOtherField addFields={addFields} mockData={mockData} />
|
|
92
|
+
<Gap height='5px' />
|
|
93
|
+
<SortSettingField showOrderSort />
|
|
91
94
|
<EditorCutomizedConfig />
|
|
92
95
|
<Gap height='5px' />
|
|
93
96
|
<EditorField
|
|
@@ -7,6 +7,7 @@ import editStore from './store'
|
|
|
7
7
|
import { observer, inject } from 'mobx-react'
|
|
8
8
|
import EditorTitle from '../common/editor_title'
|
|
9
9
|
import EditorSelect from '../common/editor_select'
|
|
10
|
+
import SortSettingField from '../common/editor_sort_setting'
|
|
10
11
|
import EditorField from '../common/editor_edit_field'
|
|
11
12
|
import EditorAddField from '../common/editor_add_field'
|
|
12
13
|
import EditorCutomizedConfig from '../common/editor_customize_config'
|
|
@@ -55,6 +56,7 @@ class Editor extends React.Component {
|
|
|
55
56
|
<Gap height='10px' />
|
|
56
57
|
<EditorSelect />
|
|
57
58
|
<Gap height='5px' />
|
|
59
|
+
<SortSettingField />
|
|
58
60
|
<EditorCutomizedConfig />
|
|
59
61
|
<Gap height='5px' />
|
|
60
62
|
<EditorField showNewDate={showNewDate} />
|
|
@@ -5,6 +5,7 @@ export const INDEX_KEY = '序号'
|
|
|
5
5
|
|
|
6
6
|
const SPECIAL_ROW_KEYS = [
|
|
7
7
|
'_special',
|
|
8
|
+
'_specialText',
|
|
8
9
|
'_diyCategorySubtotal',
|
|
9
10
|
'_diyTagSubtotal',
|
|
10
11
|
'_customTr'
|
|
@@ -105,7 +106,8 @@ export const flattenHorizontalPackedRows = (rows, colNumber) => {
|
|
|
105
106
|
export const flattenVerticalSegment = (rows, colNumber) => {
|
|
106
107
|
const columns = Array.from({ length: colNumber }, () => [])
|
|
107
108
|
rows.forEach(row => {
|
|
108
|
-
|
|
109
|
+
// _isEmptyData 行的序号可能被填充过,必须显式跳过,否则会被当真实商品吸收
|
|
110
|
+
if (isSpecialTableRow(row) || row._isEmptyData) return
|
|
109
111
|
splitPackedRow(row, colNumber).forEach((item, col) => {
|
|
110
112
|
if (isRealItem(item)) {
|
|
111
113
|
columns[col].push(stripMultiSuffixFields(item))
|
|
@@ -115,6 +117,37 @@ export const flattenVerticalSegment = (rows, colNumber) => {
|
|
|
115
117
|
return columns.reduce((list, col) => list.concat(col), [])
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
/** 按特殊行(分类小计/标题等)把整表切成若干「组」:相邻非特殊行的 run */
|
|
121
|
+
export const splitRowsIntoGroups = rows => {
|
|
122
|
+
const groups = []
|
|
123
|
+
let start = -1
|
|
124
|
+
for (let i = 0; i <= (rows || []).length; i++) {
|
|
125
|
+
const isBoundary = i === rows.length || isSpecialTableRow(rows[i])
|
|
126
|
+
if (!isBoundary && start < 0) {
|
|
127
|
+
start = i
|
|
128
|
+
}
|
|
129
|
+
if (isBoundary) {
|
|
130
|
+
if (start >= 0) {
|
|
131
|
+
groups.push({ begin: start, end: i })
|
|
132
|
+
}
|
|
133
|
+
start = -1
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return groups
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 源表(单栏/横向多栏)按特殊行分组后逐组拍平 → 每组一个商品队列。
|
|
141
|
+
* 源表不会被 repack 改写,队列是纯函数,重复执行结果不变(幂等)。
|
|
142
|
+
*/
|
|
143
|
+
export const buildSourceGroupQueues = (rows, colNumber) =>
|
|
144
|
+
splitRowsIntoGroups(rows).map(group =>
|
|
145
|
+
flattenHorizontalPackedRows(
|
|
146
|
+
(rows || []).slice(group.begin, group.end),
|
|
147
|
+
colNumber
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
118
151
|
const assignItemToRow = (row, item, suffix) => {
|
|
119
152
|
const clean = stripMultiSuffixFields(item) || {}
|
|
120
153
|
Object.keys(clean).forEach(key => {
|
|
@@ -441,39 +474,34 @@ export const renumberSegmentSerialsColumnMajor = (
|
|
|
441
474
|
|
|
442
475
|
/**
|
|
443
476
|
* 按分页区间把纵向多栏数据改成「每页先左后右」。
|
|
444
|
-
* -
|
|
445
|
-
*
|
|
446
|
-
*
|
|
477
|
+
* - 按特殊行(分类小计等)把整表切成若干组,每组一个商品队列:
|
|
478
|
+
* 商品只从本组队列取数,永不跨组 —— 奇数商品的组余数留在本组末段空格,
|
|
479
|
+
* 不会挤占下一组(修复分类合并错位)
|
|
480
|
+
* - 每组队列优先用外部传入的源表顺序(groupQueues;源表不被 repack 改写,
|
|
481
|
+
* 重复执行幂等);缺失时按「各页段贡献」从当前行拼接(重排的不动点,
|
|
482
|
+
* 同样幂等,但首趟不做每页重排)
|
|
483
|
+
* - 特殊行钉在原地;非特殊行都是新建对象,清除旧右列残留
|
|
484
|
+
* - fillIndex 时整段按列重编序号,有数据/无数据同一套规则,序号跨段跨组连续
|
|
447
485
|
*/
|
|
448
486
|
export const repackVerticalTableByPageRanges = (
|
|
449
487
|
rows,
|
|
450
488
|
colNumber,
|
|
451
489
|
pageRanges,
|
|
452
490
|
fillIndex = false,
|
|
453
|
-
|
|
491
|
+
groupQueues = null
|
|
454
492
|
) => {
|
|
455
493
|
if (!rows?.length || !pageRanges?.length || colNumber < 2) return rows
|
|
456
|
-
const items = (sourceItems && sourceItems.length
|
|
457
|
-
? sourceItems
|
|
458
|
-
: flattenVerticalSegment(rows, colNumber)
|
|
459
|
-
).map(stripMultiSuffixFields)
|
|
460
494
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const result = new Array(rows.length)
|
|
465
|
-
for (let k = 0; k < rows.length; k++) {
|
|
466
|
-
result[k] = rows[k]
|
|
467
|
-
}
|
|
495
|
+
const groups = splitRowsIntoGroups(rows)
|
|
496
|
+
// 全新数组,避免与旧行对象共享引用;特殊行沿用原引用(钉原地)
|
|
497
|
+
const result = rows.slice()
|
|
468
498
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
pageRanges.forEach(({ begin, end }) => {
|
|
499
|
+
// 页 range 与组边界取交集得到页段,并记录所属组
|
|
500
|
+
const segments = pageRanges.reduce((list, { begin, end }) => {
|
|
472
501
|
const packEnd = Math.min(end, rows.length)
|
|
473
502
|
let i = begin
|
|
474
503
|
while (i < packEnd) {
|
|
475
504
|
if (isSpecialTableRow(rows[i])) {
|
|
476
|
-
result[i] = rows[i]
|
|
477
505
|
i++
|
|
478
506
|
continue
|
|
479
507
|
}
|
|
@@ -481,32 +509,60 @@ export const repackVerticalTableByPageRanges = (
|
|
|
481
509
|
while (j < packEnd && !isSpecialTableRow(rows[j])) {
|
|
482
510
|
j++
|
|
483
511
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
512
|
+
if (j > i) {
|
|
513
|
+
list.push({
|
|
514
|
+
begin: i,
|
|
515
|
+
end: j,
|
|
516
|
+
groupIndex: groups.findIndex(g => i >= g.begin && i < g.end)
|
|
517
|
+
})
|
|
489
518
|
}
|
|
519
|
+
i = j
|
|
520
|
+
}
|
|
521
|
+
return list
|
|
522
|
+
}, [])
|
|
523
|
+
|
|
524
|
+
const externalQueues = groupQueues || []
|
|
525
|
+
const queues = groups.map((_, gi) => {
|
|
526
|
+
const external = externalQueues[gi]
|
|
527
|
+
if (external && external.length) {
|
|
528
|
+
return external
|
|
529
|
+
}
|
|
530
|
+
return segments
|
|
531
|
+
.filter(s => s.groupIndex === gi)
|
|
532
|
+
.reduce(
|
|
533
|
+
(list, s) =>
|
|
534
|
+
list.concat(
|
|
535
|
+
flattenVerticalSegment(rows.slice(s.begin, s.end), colNumber)
|
|
536
|
+
),
|
|
537
|
+
[]
|
|
538
|
+
)
|
|
539
|
+
})
|
|
490
540
|
|
|
491
|
-
|
|
492
|
-
const chunk = items.slice(consumed, consumed + capacity)
|
|
493
|
-
const packed = packVerticalNewspaper(chunk, colNumber, rowCount, false)
|
|
494
|
-
packed.forEach((row, offset) => {
|
|
495
|
-
result[i + offset] = row
|
|
496
|
-
})
|
|
497
|
-
consumed += chunk.length
|
|
498
|
-
|
|
499
|
-
if (fillIndex) {
|
|
500
|
-
nextSerial = renumberSegmentSerialsColumnMajor(
|
|
501
|
-
result,
|
|
502
|
-
i,
|
|
503
|
-
j,
|
|
504
|
-
colNumber,
|
|
505
|
-
nextSerial
|
|
506
|
-
)
|
|
507
|
-
}
|
|
541
|
+
if (!queues.some(q => q.length) && !fillIndex) return rows
|
|
508
542
|
|
|
509
|
-
|
|
543
|
+
const consumed = groups.map(() => 0)
|
|
544
|
+
let nextSerial = 1
|
|
545
|
+
segments.forEach(({ begin, end, groupIndex }) => {
|
|
546
|
+
const rowCount = end - begin
|
|
547
|
+
const queue = queues[groupIndex]
|
|
548
|
+
const chunk = queue.slice(
|
|
549
|
+
consumed[groupIndex],
|
|
550
|
+
consumed[groupIndex] + rowCount * colNumber
|
|
551
|
+
)
|
|
552
|
+
consumed[groupIndex] += chunk.length
|
|
553
|
+
packVerticalNewspaper(chunk, colNumber, rowCount, false).forEach(
|
|
554
|
+
(row, offset) => {
|
|
555
|
+
result[begin + offset] = row
|
|
556
|
+
}
|
|
557
|
+
)
|
|
558
|
+
if (fillIndex) {
|
|
559
|
+
nextSerial = renumberSegmentSerialsColumnMajor(
|
|
560
|
+
result,
|
|
561
|
+
begin,
|
|
562
|
+
end,
|
|
563
|
+
colNumber,
|
|
564
|
+
nextSerial
|
|
565
|
+
)
|
|
510
566
|
}
|
|
511
567
|
})
|
|
512
568
|
return result
|
package/src/printer/store.js
CHANGED
|
@@ -29,7 +29,9 @@ import {
|
|
|
29
29
|
packHorizontalRowMajor,
|
|
30
30
|
createEmptyRows,
|
|
31
31
|
createEmptyRowSkeleton,
|
|
32
|
-
|
|
32
|
+
isSpecialTableRow,
|
|
33
|
+
splitRowsIntoGroups,
|
|
34
|
+
buildSourceGroupQueues
|
|
33
35
|
} from './multi_column'
|
|
34
36
|
|
|
35
37
|
export const TR_BASE_HEIGHT = 23
|
|
@@ -669,13 +671,28 @@ class PrinterStore {
|
|
|
669
671
|
// 无商品时仍可能需要给空行按列编序号
|
|
670
672
|
if (!sourceItems.length && !this.fillIndex) return
|
|
671
673
|
|
|
674
|
+
// 源表按特殊行分组 → 每组一个商品队列:商品永不跨分类小计行
|
|
675
|
+
const groupQueues = buildSourceGroupQueues(sourceRows, sourceColNumber)
|
|
676
|
+
const verticalGroups = splitRowsIntoGroups(verticalRows)
|
|
677
|
+
const lastGroup = verticalGroups[verticalGroups.length - 1]
|
|
678
|
+
const lastGroupAllEmpty =
|
|
679
|
+
lastGroup &&
|
|
680
|
+
verticalRows
|
|
681
|
+
.slice(lastGroup.begin, lastGroup.end)
|
|
682
|
+
.every(row => row?._isEmptyData)
|
|
683
|
+
// 组数对齐(允许纵向表多一个纯空行尾组=行数填充产物)才用源表队列;
|
|
684
|
+
// 否则退回「按页段贡献」兜底:最坏不做每页重排,绝不会跨组串货
|
|
685
|
+
const aligned =
|
|
686
|
+
groupQueues.length === verticalGroups.length ||
|
|
687
|
+
(groupQueues.length === verticalGroups.length - 1 && lastGroupAllEmpty)
|
|
688
|
+
|
|
672
689
|
const pageRanges = this.getTablePageRanges(contentIndex, verticalRows)
|
|
673
690
|
this.data._table[verticalKey] = repackVerticalTableByPageRanges(
|
|
674
691
|
verticalRows,
|
|
675
692
|
colNumber,
|
|
676
693
|
pageRanges,
|
|
677
694
|
this.fillIndex,
|
|
678
|
-
|
|
695
|
+
aligned ? groupQueues : null
|
|
679
696
|
)
|
|
680
697
|
this.dataRevision += 1
|
|
681
698
|
})
|
|
@@ -981,44 +998,16 @@ class PrinterStore {
|
|
|
981
998
|
const emptyCount =
|
|
982
999
|
emptyTable.length > 0 ? emptyTable.length : toFillEmptyCount
|
|
983
1000
|
|
|
984
|
-
//
|
|
1001
|
+
// 纵向多栏:保留真实行(含分类小计等特殊行),仅追加空行补页;
|
|
1002
|
+
// 每页先左后右、按组落位由随后的 repackVerticalMultiByPages 完成
|
|
985
1003
|
if (/_vertical$/.test(dataKey)) {
|
|
986
1004
|
const sourceKey = dataKey.replace(/_vertical$/, '')
|
|
987
|
-
const singleKey = sourceKey.replace(/_multi3?/, '')
|
|
988
1005
|
const colNumber = getMultiNumber(sourceKey)
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
const sourceRows =
|
|
994
|
-
this.data._table[singleKey] || this.data._table[sourceKey] || []
|
|
995
|
-
const sourceColNumber = isMultiTable(singleKey)
|
|
996
|
-
? getMultiNumber(singleKey)
|
|
997
|
-
: isMultiTable(sourceKey)
|
|
998
|
-
? colNumber
|
|
999
|
-
: 1
|
|
1000
|
-
const sourceItems = flattenHorizontalPackedRows(
|
|
1001
|
-
sourceRows,
|
|
1002
|
-
sourceColNumber
|
|
1003
|
-
)
|
|
1004
|
-
const baseRowCount = sourceItems.length
|
|
1005
|
-
? Math.max(1, Math.ceil(sourceItems.length / colNumber))
|
|
1006
|
-
: 0
|
|
1007
|
-
// 钉死总行:left-first repack 后 _isEmptyData 变少,不能用 emptyTable.length 回推
|
|
1008
|
-
const emptyCount = resolveVerticalEmptyCount(
|
|
1009
|
-
tableData.length,
|
|
1010
|
-
baseRowCount,
|
|
1011
|
-
emptyTable.length > 0
|
|
1012
|
-
? emptyTable.length
|
|
1013
|
-
: this.getFilledTableData(table).length,
|
|
1014
|
-
emptyTable.length > 0
|
|
1006
|
+
const sample =
|
|
1007
|
+
table.find(row => row && !isSpecialTableRow(row)) || tableData[0]
|
|
1008
|
+
this.data._table[dataKey] = table.concat(
|
|
1009
|
+
createEmptyRows(emptyCount, sample, colNumber)
|
|
1015
1010
|
)
|
|
1016
|
-
const dataRows = baseRowCount
|
|
1017
|
-
? packVerticalNewspaper(sourceItems, colNumber, baseRowCount, false)
|
|
1018
|
-
: []
|
|
1019
|
-
const sample = dataRows[0] || sourceRows[0]
|
|
1020
|
-
const emptyRows = createEmptyRows(emptyCount, sample, colNumber)
|
|
1021
|
-
this.data._table[dataKey] = dataRows.concat(emptyRows)
|
|
1022
1011
|
return
|
|
1023
1012
|
}
|
|
1024
1013
|
|