gm-printer 10.39.4-beta.2 → 10.41.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 +0 -3
- package/src/common/editor_edit_field.js +10 -4
- package/src/common/editor_store.js +42 -242
- package/src/common/util.js +58 -4
- package/src/editor_purchase/editor_special_table.js +28 -9
- package/src/editor_purchase/store.js +7 -4
- package/src/printer/long_print_table/index.js +10 -2
- package/src/printer/printer.js +37 -34
- package/src/printer/store.js +34 -308
- package/src/printer/table.js +16 -5
- package/src/printer/table_overallOrder_tr.js +49 -37
- package/src/util.js +6 -10
- package/src/printer/multi_column.js +0 -461
|
@@ -12,54 +12,66 @@ const OverallOrder = props => {
|
|
|
12
12
|
printerStore,
|
|
13
13
|
printerStore: {
|
|
14
14
|
data: { common }
|
|
15
|
-
}
|
|
15
|
+
},
|
|
16
|
+
isLastTablePage
|
|
16
17
|
} = props
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
// showEachPage 默认 true(老模板缺省视为每页展示);false 时仅表格最后一页渲染
|
|
20
|
+
const showEachPage = overallOrder?.showEachPage !== false
|
|
21
|
+
const shouldShow =
|
|
19
22
|
overallOrder?.show &&
|
|
20
|
-
printerStore?.ready &&
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
printerStore?.ready &&
|
|
24
|
+
(showEachPage || isLastTablePage)
|
|
25
|
+
|
|
26
|
+
if (!shouldShow) return null
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<tr>
|
|
30
|
+
{_.map(overallOrder.fields, (item, index) => {
|
|
31
|
+
return (
|
|
32
|
+
<td colSpan={item.colSpan} key={index}>
|
|
33
|
+
<div style={{ ...item.style }} className='gm-flex-page'>
|
|
34
|
+
{item.name}
|
|
35
|
+
<div
|
|
36
|
+
className={classNames('gm-flex-page', {
|
|
37
|
+
'gm-flex-justify-between-page':
|
|
38
|
+
overallOrder?.isUpperLowerCaseSeparate,
|
|
39
|
+
'gm-flex-grow-page': overallOrder?.isUpperLowerCaseSeparate
|
|
40
|
+
})}
|
|
41
|
+
>
|
|
42
|
+
<span
|
|
43
|
+
className={
|
|
44
|
+
overallOrder?.isUpperCaseBefore
|
|
45
|
+
? 'gm-printer-subtotal-isUpperCaseBefore-inter'
|
|
46
|
+
: ''
|
|
47
|
+
}
|
|
33
48
|
>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{common?.[item.valueField] ?? ''}
|
|
49
|
+
{common?.[item.valueField] ?? ''}
|
|
50
|
+
</span>
|
|
51
|
+
{overallOrder?.needUpperCase && (
|
|
52
|
+
<span>
|
|
53
|
+
{common?.[item.valueField]
|
|
54
|
+
? coverDigit2Uppercase(common[item.valueField])
|
|
55
|
+
: ''}
|
|
42
56
|
</span>
|
|
43
|
-
|
|
44
|
-
<span>
|
|
45
|
-
{common?.[item.valueField]
|
|
46
|
-
? coverDigit2Uppercase(common[item.valueField])
|
|
47
|
-
: ''}
|
|
48
|
-
</span>
|
|
49
|
-
)}
|
|
50
|
-
</div>
|
|
57
|
+
)}
|
|
51
58
|
</div>
|
|
52
|
-
</
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
</div>
|
|
60
|
+
</td>
|
|
61
|
+
)
|
|
62
|
+
})}
|
|
63
|
+
</tr>
|
|
57
64
|
)
|
|
58
65
|
}
|
|
59
66
|
OverallOrder.propTypes = {
|
|
60
67
|
config: PropTypes.object.isRequired,
|
|
61
68
|
range: PropTypes.object.isRequired,
|
|
62
|
-
printerStore: PropTypes.object
|
|
69
|
+
printerStore: PropTypes.object,
|
|
70
|
+
isLastTablePage: PropTypes.bool
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
OverallOrder.defaultProps = {
|
|
74
|
+
isLastTablePage: true
|
|
63
75
|
}
|
|
64
76
|
|
|
65
77
|
export default observer(OverallOrder)
|
package/src/util.js
CHANGED
|
@@ -2,23 +2,19 @@ import _ from 'lodash'
|
|
|
2
2
|
import Big from 'big.js'
|
|
3
3
|
|
|
4
4
|
function getHeight(el) {
|
|
5
|
-
|
|
6
|
-
// 否则 parent window.getComputedStyle 可能得到错误值、测高为 0
|
|
7
|
-
const view = (el.ownerDocument && el.ownerDocument.defaultView) || window
|
|
8
|
-
const styles = view.getComputedStyle(el)
|
|
5
|
+
const styles = window.getComputedStyle(el)
|
|
9
6
|
const height = el.offsetHeight
|
|
10
|
-
const borderTopWidth = parseFloat(styles.borderTopWidth)
|
|
11
|
-
const borderBottomWidth = parseFloat(styles.borderBottomWidth)
|
|
12
|
-
const paddingTop = parseFloat(styles.paddingTop)
|
|
13
|
-
const paddingBottom = parseFloat(styles.paddingBottom)
|
|
7
|
+
const borderTopWidth = parseFloat(styles.borderTopWidth)
|
|
8
|
+
const borderBottomWidth = parseFloat(styles.borderBottomWidth)
|
|
9
|
+
const paddingTop = parseFloat(styles.paddingTop)
|
|
10
|
+
const paddingBottom = parseFloat(styles.paddingBottom)
|
|
14
11
|
return (
|
|
15
12
|
height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom
|
|
16
13
|
)
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
function getWidth(el) {
|
|
20
|
-
const
|
|
21
|
-
const styles = view.getComputedStyle(el)
|
|
17
|
+
const styles = window.getComputedStyle(el)
|
|
22
18
|
// 取width保留小数点用 getBoundClientRect
|
|
23
19
|
const style = el.getBoundingClientRect()
|
|
24
20
|
const width = Math.round(style.width * 100) / 100 // 保留两位小数并四舍五入
|
|
@@ -1,461 +0,0 @@
|
|
|
1
|
-
import { MULTI_SUFFIX, MULTI_SUFFIX3 } from '../config'
|
|
2
|
-
import { getMultiNumber, isMultiTable } from '../util'
|
|
3
|
-
|
|
4
|
-
export const INDEX_KEY = '序号'
|
|
5
|
-
|
|
6
|
-
const SPECIAL_ROW_KEYS = [
|
|
7
|
-
'_special',
|
|
8
|
-
'_diyCategorySubtotal',
|
|
9
|
-
'_diyTagSubtotal',
|
|
10
|
-
'_customTr'
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
export const getColSuffix = colIndex => {
|
|
14
|
-
if (colIndex <= 0) return ''
|
|
15
|
-
if (colIndex === 1) return MULTI_SUFFIX
|
|
16
|
-
return MULTI_SUFFIX3
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const getSerialKeys = colNumber =>
|
|
20
|
-
Array.from({ length: colNumber }, (_, c) => INDEX_KEY + getColSuffix(c))
|
|
21
|
-
|
|
22
|
-
/** 栏数:dataKey 的 multi/multi3,并用行上是否已有 _MULTI_SUFFIX 字段兜底 */
|
|
23
|
-
export const detectColNumber = (dataKey, rows) => {
|
|
24
|
-
let n = isMultiTable(dataKey) ? getMultiNumber(dataKey) : 1
|
|
25
|
-
const sample = (rows || []).find(
|
|
26
|
-
row => row && !row._isEmptyData && !isSpecialTableRow(row)
|
|
27
|
-
)
|
|
28
|
-
if (sample) {
|
|
29
|
-
const keys = Object.keys(sample)
|
|
30
|
-
if (keys.some(key => key.endsWith(MULTI_SUFFIX3))) {
|
|
31
|
-
n = Math.max(n, 3)
|
|
32
|
-
} else if (keys.some(key => key.endsWith(MULTI_SUFFIX))) {
|
|
33
|
-
n = Math.max(n, 2)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return n
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const isSpecialTableRow = row =>
|
|
40
|
-
!!(row && SPECIAL_ROW_KEYS.some(key => row[key]))
|
|
41
|
-
|
|
42
|
-
export const isFilledIndexValue = value => value !== '' && value != null
|
|
43
|
-
|
|
44
|
-
export const toSerialNumber = value => {
|
|
45
|
-
if (!isFilledIndexValue(value)) return null
|
|
46
|
-
const n = Number(value)
|
|
47
|
-
return Number.isFinite(n) ? n : null
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const splitKeyCol = key => {
|
|
51
|
-
if (key.endsWith(MULTI_SUFFIX3)) {
|
|
52
|
-
return { col: 2, base: key.slice(0, -MULTI_SUFFIX3.length) }
|
|
53
|
-
}
|
|
54
|
-
if (key.endsWith(MULTI_SUFFIX)) {
|
|
55
|
-
return { col: 1, base: key.slice(0, -MULTI_SUFFIX.length) }
|
|
56
|
-
}
|
|
57
|
-
return { col: 0, base: key }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** 把多栏打包行拆成各列的原始行数据 */
|
|
61
|
-
export const splitPackedRow = (row, colNumber) => {
|
|
62
|
-
const cols = Array.from({ length: colNumber }, () => ({}))
|
|
63
|
-
Object.keys(row || {}).forEach(key => {
|
|
64
|
-
if (key === '_isEmptyData') return
|
|
65
|
-
const { col, base } = splitKeyCol(key)
|
|
66
|
-
if (col < colNumber) {
|
|
67
|
-
cols[col][base] = row[key]
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
return cols
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const isRealItem = item => isFilledIndexValue(item?.[INDEX_KEY])
|
|
74
|
-
|
|
75
|
-
/** 去掉多栏后缀字段,避免旧右列残留被 assign 进新行 */
|
|
76
|
-
export const stripMultiSuffixFields = item => {
|
|
77
|
-
if (!item || typeof item !== 'object') return item
|
|
78
|
-
const next = {}
|
|
79
|
-
Object.keys(item).forEach(key => {
|
|
80
|
-
if (key === '_isEmptyData') return
|
|
81
|
-
if (key.endsWith(MULTI_SUFFIX) || key.endsWith(MULTI_SUFFIX3)) return
|
|
82
|
-
next[key] = item[key]
|
|
83
|
-
})
|
|
84
|
-
return next
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** 横向多栏:每行从左到右拆出商品,得到原始顺序 */
|
|
88
|
-
export const flattenHorizontalPackedRows = (rows, colNumber) => {
|
|
89
|
-
const items = []
|
|
90
|
-
const cols = Math.max(colNumber || 1, 1)
|
|
91
|
-
;(rows || []).forEach(row => {
|
|
92
|
-
if (!row || row._isEmptyData || isSpecialTableRow(row)) return
|
|
93
|
-
if (cols <= 1) {
|
|
94
|
-
items.push(stripMultiSuffixFields(row))
|
|
95
|
-
return
|
|
96
|
-
}
|
|
97
|
-
splitPackedRow(row, cols).forEach(item => {
|
|
98
|
-
if (isRealItem(item)) items.push(stripMultiSuffixFields(item))
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
return items
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** 纵向整单打包:左列全部 + 右列全部,还原商品原始顺序 */
|
|
105
|
-
export const flattenVerticalSegment = (rows, colNumber) => {
|
|
106
|
-
const columns = Array.from({ length: colNumber }, () => [])
|
|
107
|
-
rows.forEach(row => {
|
|
108
|
-
if (isSpecialTableRow(row)) return
|
|
109
|
-
splitPackedRow(row, colNumber).forEach((item, col) => {
|
|
110
|
-
if (isRealItem(item)) {
|
|
111
|
-
columns[col].push(stripMultiSuffixFields(item))
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
return columns.reduce((list, col) => list.concat(col), [])
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const assignItemToRow = (row, item, suffix) => {
|
|
119
|
-
const clean = stripMultiSuffixFields(item) || {}
|
|
120
|
-
Object.keys(clean).forEach(key => {
|
|
121
|
-
row[key + suffix] = clean[key]
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 按「先填满当前页左列,再填右列」打包。
|
|
127
|
-
* row r 的第 c 列对应 items[c * rowCount + r]
|
|
128
|
-
* 空单元格补序号也按列优先(先下后右),与商品落位一致。
|
|
129
|
-
* @param {object} [options]
|
|
130
|
-
* @param {number} [options.serialStart] 填充序号的起始值(含)
|
|
131
|
-
*/
|
|
132
|
-
export const packVerticalNewspaper = (
|
|
133
|
-
items,
|
|
134
|
-
colNumber,
|
|
135
|
-
rowCount,
|
|
136
|
-
fillIndex = false,
|
|
137
|
-
options = {}
|
|
138
|
-
) => {
|
|
139
|
-
const { serialStart } = options
|
|
140
|
-
const rows = Array.from({ length: rowCount }, () => ({}))
|
|
141
|
-
let maxSerial = 0
|
|
142
|
-
;(items || []).forEach(item => {
|
|
143
|
-
const n = toSerialNumber(item?.[INDEX_KEY])
|
|
144
|
-
if (n != null && n > maxSerial) maxSerial = n
|
|
145
|
-
})
|
|
146
|
-
if (serialStart != null && serialStart - 1 > maxSerial) {
|
|
147
|
-
maxSerial = serialStart - 1
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
for (let c = 0; c < colNumber; c++) {
|
|
151
|
-
for (let r = 0; r < rowCount; r++) {
|
|
152
|
-
const item = (items || [])[c * rowCount + r]
|
|
153
|
-
if (!isRealItem(item)) continue
|
|
154
|
-
assignItemToRow(rows[r], item, getColSuffix(c))
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (fillIndex) {
|
|
159
|
-
let nextSerial = maxSerial
|
|
160
|
-
for (let c = 0; c < colNumber; c++) {
|
|
161
|
-
for (let r = 0; r < rowCount; r++) {
|
|
162
|
-
const key = INDEX_KEY + getColSuffix(c)
|
|
163
|
-
if (isFilledIndexValue(rows[r][key])) {
|
|
164
|
-
const n = toSerialNumber(rows[r][key])
|
|
165
|
-
if (n != null && n > nextSerial) nextSerial = n
|
|
166
|
-
continue
|
|
167
|
-
}
|
|
168
|
-
rows[r][key] = ++nextSerial
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
} else {
|
|
172
|
-
for (let c = 0; c < colNumber; c++) {
|
|
173
|
-
for (let r = 0; r < rowCount; r++) {
|
|
174
|
-
const key = INDEX_KEY + getColSuffix(c)
|
|
175
|
-
if (!isFilledIndexValue(rows[r][key])) {
|
|
176
|
-
rows[r][key] = ''
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
rows.forEach((row, r) => {
|
|
183
|
-
let hasRealItem = false
|
|
184
|
-
for (let c = 0; c < colNumber; c++) {
|
|
185
|
-
if (isRealItem((items || [])[c * rowCount + r])) {
|
|
186
|
-
hasRealItem = true
|
|
187
|
-
break
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (!hasRealItem) {
|
|
191
|
-
row._isEmptyData = true
|
|
192
|
-
}
|
|
193
|
-
})
|
|
194
|
-
return rows
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* 横向多栏:每行从左到右落位(row r 的第 c 列 ← items[r * colNumber + c])
|
|
199
|
-
* 用于缺省 multi/multi3 表时从单栏商品生成打包数据。
|
|
200
|
-
*/
|
|
201
|
-
export const packHorizontalRowMajor = (items, colNumber) => {
|
|
202
|
-
const cols = Math.max(colNumber || 1, 1)
|
|
203
|
-
const list = items || []
|
|
204
|
-
const rowCount = list.length ? Math.ceil(list.length / cols) : 0
|
|
205
|
-
const rows = Array.from({ length: rowCount }, () => ({}))
|
|
206
|
-
for (let r = 0; r < rowCount; r++) {
|
|
207
|
-
for (let c = 0; c < cols; c++) {
|
|
208
|
-
const item = list[r * cols + c]
|
|
209
|
-
if (!isRealItem(item)) continue
|
|
210
|
-
assignItemToRow(rows[r], item, getColSuffix(c))
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return rows
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export const getMaxSerial = (rows, colNumber) => {
|
|
217
|
-
let max = 0
|
|
218
|
-
const keys = getSerialKeys(colNumber)
|
|
219
|
-
;(rows || []).forEach(row => {
|
|
220
|
-
keys.forEach(key => {
|
|
221
|
-
const n = toSerialNumber(row?.[key])
|
|
222
|
-
if (n != null && n > max) max = n
|
|
223
|
-
})
|
|
224
|
-
})
|
|
225
|
-
return max
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/** 空白行补齐每一栏的序号 */
|
|
229
|
-
export const fillEmptyRowIndex = (
|
|
230
|
-
item,
|
|
231
|
-
index,
|
|
232
|
-
lastKey,
|
|
233
|
-
colNumber,
|
|
234
|
-
fillIndex
|
|
235
|
-
) => {
|
|
236
|
-
const next = { ...item }
|
|
237
|
-
getSerialKeys(colNumber).forEach((key, col) => {
|
|
238
|
-
next[key] = fillIndex ? lastKey + index * colNumber + col : ''
|
|
239
|
-
})
|
|
240
|
-
return next
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* 按样板行生成空行骨架(拷贝字段为 ''),避免多栏模板读 undefined 抛错。
|
|
245
|
-
* 并预留各栏序号字段。
|
|
246
|
-
*/
|
|
247
|
-
export const createEmptyRowSkeleton = (sampleRow, colNumber = 1) => {
|
|
248
|
-
const skeleton = { _isEmptyData: true }
|
|
249
|
-
if (sampleRow && typeof sampleRow === 'object') {
|
|
250
|
-
Object.keys(sampleRow).forEach(key => {
|
|
251
|
-
if (key === '_isEmptyData') return
|
|
252
|
-
skeleton[key] = ''
|
|
253
|
-
})
|
|
254
|
-
}
|
|
255
|
-
const cols = Math.max(colNumber || 1, 1)
|
|
256
|
-
getSerialKeys(cols).forEach(key => {
|
|
257
|
-
if (skeleton[key] === undefined) skeleton[key] = ''
|
|
258
|
-
})
|
|
259
|
-
return skeleton
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
export const createEmptyRows = (count, sampleRow, colNumber = 1) => {
|
|
263
|
-
if (count <= 0) return []
|
|
264
|
-
const skeleton = createEmptyRowSkeleton(sampleRow, colNumber)
|
|
265
|
-
return Array.from({ length: count }, () => ({ ...skeleton }))
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* 纵向多栏空行数:
|
|
270
|
-
* - 仍有 _isEmptyData 时:用「总行 - 对半商品行」钉死(开关填充序号,避免 repack 吃空行)
|
|
271
|
-
* - 已无空行标记时:走 fallback(remain/行高),供多栏/排列切换清空后重补
|
|
272
|
-
* (left-fill 会留下无 _isEmptyData 的多余商品行,不能当总行钉死)
|
|
273
|
-
*/
|
|
274
|
-
export const resolveVerticalEmptyCount = (
|
|
275
|
-
tableLength,
|
|
276
|
-
baseRowCount,
|
|
277
|
-
fallbackEmptyCount = 0,
|
|
278
|
-
hasEmptyMarked = false
|
|
279
|
-
) => {
|
|
280
|
-
const base = Math.max(0, baseRowCount || 0)
|
|
281
|
-
const pinned = Math.max(0, (tableLength || 0) - base)
|
|
282
|
-
if (hasEmptyMarked && pinned > 0) return pinned
|
|
283
|
-
return Math.max(0, fallbackEmptyCount || 0)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* 渲染/插值前补齐当前行每一栏序号。
|
|
288
|
-
* 纵向表(_vertical)序号由 repack 统一生成,这里不再按横向公式补,避免断号/残留错觉。
|
|
289
|
-
*/
|
|
290
|
-
export const ensureRowSerialKeys = (
|
|
291
|
-
list,
|
|
292
|
-
index,
|
|
293
|
-
colNumber,
|
|
294
|
-
fillIndex,
|
|
295
|
-
dataKey
|
|
296
|
-
) => {
|
|
297
|
-
const row = list?.[index]
|
|
298
|
-
if (!row || !fillIndex || colNumber < 1 || isSpecialTableRow(row)) {
|
|
299
|
-
return row
|
|
300
|
-
}
|
|
301
|
-
// 纵向多栏:信任 repack 结果
|
|
302
|
-
if (dataKey && /_vertical$/.test(dataKey)) {
|
|
303
|
-
return row
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const keys = getSerialKeys(colNumber)
|
|
307
|
-
const missing = keys.filter(key => !isFilledIndexValue(row[key]))
|
|
308
|
-
if (!missing.length) return row
|
|
309
|
-
|
|
310
|
-
const realRows = (list || []).filter(
|
|
311
|
-
item => item && !item._isEmptyData && !isSpecialTableRow(item)
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
if (row._isEmptyData) {
|
|
315
|
-
let max = getMaxSerial(realRows, colNumber)
|
|
316
|
-
const lastReal = realRows[realRows.length - 1]
|
|
317
|
-
if (lastReal) {
|
|
318
|
-
keys.forEach(key => {
|
|
319
|
-
if (!isFilledIndexValue(lastReal[key])) max += 1
|
|
320
|
-
})
|
|
321
|
-
}
|
|
322
|
-
const emptyIndex = (list || [])
|
|
323
|
-
.slice(0, index)
|
|
324
|
-
.filter(item => item?._isEmptyData).length
|
|
325
|
-
const next = { ...row }
|
|
326
|
-
keys.forEach((key, col) => {
|
|
327
|
-
next[key] = max + 1 + emptyIndex * colNumber + col
|
|
328
|
-
})
|
|
329
|
-
return next
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const lastRealIndex = (list || []).reduce((acc, item, i) => {
|
|
333
|
-
if (item && !item._isEmptyData && !isSpecialTableRow(item)) return i
|
|
334
|
-
return acc
|
|
335
|
-
}, -1)
|
|
336
|
-
if (index !== lastRealIndex) return row
|
|
337
|
-
|
|
338
|
-
let max = getMaxSerial(realRows, colNumber)
|
|
339
|
-
const next = { ...row }
|
|
340
|
-
keys.forEach(key => {
|
|
341
|
-
if (!isFilledIndexValue(next[key])) {
|
|
342
|
-
next[key] = ++max
|
|
343
|
-
}
|
|
344
|
-
})
|
|
345
|
-
return next
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/** 最后一行右侧空单元格续编序号 */
|
|
349
|
-
export const fillPartialLastRow = (rows, colNumber, fillIndex) => {
|
|
350
|
-
if (!fillIndex || !rows?.length || colNumber <= 1) return rows
|
|
351
|
-
const lastIndex = rows.length - 1
|
|
352
|
-
const last = rows[lastIndex]
|
|
353
|
-
if (!last || last._isEmptyData || isSpecialTableRow(last)) return rows
|
|
354
|
-
|
|
355
|
-
let max = getMaxSerial(rows, colNumber)
|
|
356
|
-
const next = { ...last }
|
|
357
|
-
let changed = false
|
|
358
|
-
getSerialKeys(colNumber).forEach(key => {
|
|
359
|
-
if (!isFilledIndexValue(next[key])) {
|
|
360
|
-
next[key] = ++max
|
|
361
|
-
changed = true
|
|
362
|
-
}
|
|
363
|
-
})
|
|
364
|
-
if (!changed) return rows
|
|
365
|
-
const result = rows.slice()
|
|
366
|
-
result[lastIndex] = next
|
|
367
|
-
return result
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/** 整段按列优先重编序号(先左列上→下,再右列),数据行与空行连续不断号 */
|
|
371
|
-
export const renumberSegmentSerialsColumnMajor = (
|
|
372
|
-
rows,
|
|
373
|
-
begin,
|
|
374
|
-
end,
|
|
375
|
-
colNumber,
|
|
376
|
-
startSerial = 1
|
|
377
|
-
) => {
|
|
378
|
-
let next = startSerial
|
|
379
|
-
for (let c = 0; c < colNumber; c++) {
|
|
380
|
-
for (let r = begin; r < end; r++) {
|
|
381
|
-
const row = rows[r]
|
|
382
|
-
if (!row || isSpecialTableRow(row)) continue
|
|
383
|
-
const key = INDEX_KEY + getColSuffix(c)
|
|
384
|
-
rows[r] = { ...row, [key]: next++ }
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
return next
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* 按分页区间把纵向多栏数据改成「每页先左后右」。
|
|
392
|
-
* - 商品按序号灌满当前段左列再排右列(含空行的整段行数)
|
|
393
|
-
* - 每一行都是新建对象,清除旧右列残留
|
|
394
|
-
* - fillIndex 时整段按列重编序号,有数据/无数据同一套规则
|
|
395
|
-
*/
|
|
396
|
-
export const repackVerticalTableByPageRanges = (
|
|
397
|
-
rows,
|
|
398
|
-
colNumber,
|
|
399
|
-
pageRanges,
|
|
400
|
-
fillIndex = false,
|
|
401
|
-
sourceItems
|
|
402
|
-
) => {
|
|
403
|
-
if (!rows?.length || !pageRanges?.length || colNumber < 2) return rows
|
|
404
|
-
const items = (sourceItems && sourceItems.length
|
|
405
|
-
? sourceItems
|
|
406
|
-
: flattenVerticalSegment(rows, colNumber)
|
|
407
|
-
).map(stripMultiSuffixFields)
|
|
408
|
-
|
|
409
|
-
if (!items.length && !fillIndex) return rows
|
|
410
|
-
|
|
411
|
-
// 全新数组,避免与旧行对象共享引用
|
|
412
|
-
const result = new Array(rows.length)
|
|
413
|
-
for (let k = 0; k < rows.length; k++) {
|
|
414
|
-
result[k] = rows[k]
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
let consumed = 0
|
|
418
|
-
let nextSerial = 1
|
|
419
|
-
pageRanges.forEach(({ begin, end }) => {
|
|
420
|
-
const packEnd = Math.min(end, rows.length)
|
|
421
|
-
let i = begin
|
|
422
|
-
while (i < packEnd) {
|
|
423
|
-
if (isSpecialTableRow(rows[i])) {
|
|
424
|
-
result[i] = rows[i]
|
|
425
|
-
i++
|
|
426
|
-
continue
|
|
427
|
-
}
|
|
428
|
-
let j = i
|
|
429
|
-
while (j < packEnd && !isSpecialTableRow(rows[j])) {
|
|
430
|
-
j++
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const rowCount = j - i
|
|
434
|
-
if (rowCount <= 0) {
|
|
435
|
-
i = j
|
|
436
|
-
continue
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
const capacity = rowCount * colNumber
|
|
440
|
-
const chunk = items.slice(consumed, consumed + capacity)
|
|
441
|
-
const packed = packVerticalNewspaper(chunk, colNumber, rowCount, false)
|
|
442
|
-
packed.forEach((row, offset) => {
|
|
443
|
-
result[i + offset] = row
|
|
444
|
-
})
|
|
445
|
-
consumed += chunk.length
|
|
446
|
-
|
|
447
|
-
if (fillIndex) {
|
|
448
|
-
nextSerial = renumberSegmentSerialsColumnMajor(
|
|
449
|
-
result,
|
|
450
|
-
i,
|
|
451
|
-
j,
|
|
452
|
-
colNumber,
|
|
453
|
-
nextSerial
|
|
454
|
-
)
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
i = j
|
|
458
|
-
}
|
|
459
|
-
})
|
|
460
|
-
return result
|
|
461
|
-
}
|