gm-printer 10.42.2 → 10.42.3-beta.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/locales/en.json +3 -0
- package/locales/th.json +3 -0
- package/locales/zh-HK.json +3 -0
- package/package.json +1 -1
- package/src/common/common_context_menu.js +6 -4
- package/src/common/component.js +64 -8
- package/src/common/editor_edit_field.js +6 -1
- package/src/common/editor_store.js +13 -3
- package/src/common/hoc_with_store.js +9 -0
- package/src/common/style.lesss +43 -0
- package/src/editor/store.js +13 -0
- package/src/finance_voucher/components/table_subtotal_tr.js +12 -18
- package/src/index.js +2 -0
- package/src/printer/block.js +154 -4
- package/src/printer/multi_column.js +53 -0
- package/src/printer/page_summary.js +3 -1
- package/src/printer/printer.js +1 -1
- package/src/printer/store.js +15 -7
- package/src/printer/table_diy_overallOrder_tr.js +8 -15
- package/src/printer/table_diy_summary_tr.js +18 -35
- package/src/printer/table_subtotal_tr.js +13 -16
- package/src/util.js +20 -1
- package/yarn-error.log +372 -152
|
@@ -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'
|
|
@@ -345,6 +346,58 @@ export const ensureRowSerialKeys = (
|
|
|
345
346
|
return next
|
|
346
347
|
}
|
|
347
348
|
|
|
349
|
+
/**
|
|
350
|
+
* 统一收敛多栏序号,修复「半行续号」与「空行起始序号」两处独立计算导致的序号重复
|
|
351
|
+
* (如 5 条数据双栏:第三行第二列续号为 6,第四行空行起始又编出 6)。
|
|
352
|
+
* - 先给最后一个实数据行的右侧空格续号并写回(渲染侧 ensureRowSerialKeys 不再另行补号)
|
|
353
|
+
* - 空行序号以「全表已用最大序号 + 1」连续重编,与半行续号同源
|
|
354
|
+
* 幂等,重复执行结果不变;仅 fillIndex 开启时生效
|
|
355
|
+
*/
|
|
356
|
+
export const normalizeMultiSerials = (rows, colNumber, fillIndex) => {
|
|
357
|
+
if (!fillIndex || !rows?.length || colNumber < 1) return rows
|
|
358
|
+
const keys = getSerialKeys(colNumber)
|
|
359
|
+
const isFill = row => row && !row._isEmptyData && !isSpecialTableRow(row)
|
|
360
|
+
|
|
361
|
+
const result = rows.slice()
|
|
362
|
+
|
|
363
|
+
// 实数据行已用最大序号
|
|
364
|
+
let max = 0
|
|
365
|
+
result.forEach(row => {
|
|
366
|
+
if (!isFill(row)) return
|
|
367
|
+
keys.forEach(key => {
|
|
368
|
+
const n = toSerialNumber(row?.[key])
|
|
369
|
+
if (n != null && n > max) max = n
|
|
370
|
+
})
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
// 1. 最后一个实数据行的空格续号(写回数据,保证序号只有一处来源)
|
|
374
|
+
for (let i = result.length - 1; i >= 0; i--) {
|
|
375
|
+
if (!isFill(result[i])) continue
|
|
376
|
+
const next = { ...result[i] }
|
|
377
|
+
keys.forEach(key => {
|
|
378
|
+
if (!isFilledIndexValue(next[key])) {
|
|
379
|
+
max += 1
|
|
380
|
+
next[key] = max
|
|
381
|
+
}
|
|
382
|
+
})
|
|
383
|
+
result[i] = next
|
|
384
|
+
break
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// 2. 空行从 max+1 连续重编,不会与实数据序号/半行续号撞号
|
|
388
|
+
result.forEach((row, i) => {
|
|
389
|
+
if (!row?._isEmptyData || isSpecialTableRow(row)) return
|
|
390
|
+
const next = { ...row }
|
|
391
|
+
keys.forEach(key => {
|
|
392
|
+
max += 1
|
|
393
|
+
next[key] = max
|
|
394
|
+
})
|
|
395
|
+
result[i] = next
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
return result
|
|
399
|
+
}
|
|
400
|
+
|
|
348
401
|
/** 最后一行右侧空单元格续编序号 */
|
|
349
402
|
export const fillPartialLastRow = (rows, colNumber, fillIndex) => {
|
|
350
403
|
if (!fillIndex || !rows?.length || colNumber <= 1) return rows
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import _ from 'lodash'
|
|
3
|
-
import { getDataKey, isMultiTable } from '../util'
|
|
3
|
+
import { getDataKey, isMultiTable, isMaskedValue, MASKED_VALUE } from '../util'
|
|
4
4
|
import Big from 'big.js'
|
|
5
5
|
import { observer } from 'mobx-react'
|
|
6
6
|
import { get } from 'mobx'
|
|
@@ -19,6 +19,8 @@ const regExp = text => {
|
|
|
19
19
|
* @returns {*|string}
|
|
20
20
|
*/
|
|
21
21
|
const sumCol = (key, dataList, summaryFieldsResultToNumber = []) => {
|
|
22
|
+
// 任一值脱敏 '***' 则合计显 '***'(原逻辑 Big('***') 抛异常被 catch,合计显空串)
|
|
23
|
+
if (dataList.some(item => isMaskedValue(item[key]))) return MASKED_VALUE
|
|
22
24
|
let result
|
|
23
25
|
try {
|
|
24
26
|
result = dataList
|
package/src/printer/printer.js
CHANGED
|
@@ -132,7 +132,7 @@ class Printer extends React.Component {
|
|
|
132
132
|
printerStore.changeTableData()
|
|
133
133
|
printerStore.computedPages()
|
|
134
134
|
}
|
|
135
|
-
// 获取剩余空白高度,传到editor
|
|
135
|
+
// 获取剩余空白高度,传到 editor
|
|
136
136
|
getremainpageHeight && getremainpageHeight(printerStore.remainPageHeight)
|
|
137
137
|
}
|
|
138
138
|
printerStore.setReady(true)
|
package/src/printer/store.js
CHANGED
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
getDataKey,
|
|
8
8
|
caclSingleDetailsPageHeight,
|
|
9
9
|
getArrayMid,
|
|
10
|
-
getOverallOrderTrHeight
|
|
10
|
+
getOverallOrderTrHeight,
|
|
11
|
+
isMaskedValue
|
|
11
12
|
} from '../util'
|
|
12
13
|
import {
|
|
13
14
|
isDetailOneRowSelectKey,
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
detectColNumber,
|
|
24
25
|
ensureRowSerialKeys,
|
|
25
26
|
flattenHorizontalPackedRows,
|
|
27
|
+
normalizeMultiSerials,
|
|
26
28
|
repackVerticalTableByPageRanges,
|
|
27
29
|
packVerticalNewspaper,
|
|
28
30
|
packHorizontalRowMajor,
|
|
@@ -45,6 +47,8 @@ const canSplitRowDetails = (dataKey, row) => {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
const price = (n, f = 2) => {
|
|
50
|
+
// 脱敏值 '***' 原样返回(不能走 isNaN 判空,空单元格仍需显空)
|
|
51
|
+
if (isMaskedValue(n)) return n
|
|
48
52
|
if (isNaN(n)) return null
|
|
49
53
|
return Big(n || 0).toFixed(f)
|
|
50
54
|
}
|
|
@@ -394,7 +398,7 @@ class PrinterStore {
|
|
|
394
398
|
const currentPageMinimumHeight =
|
|
395
399
|
allPagesHaveThisHeight + allTableHaveThisHeight
|
|
396
400
|
// 最后一项是表格时,末页仍要渲染签名:装行可用高度预留签名,避免空行顶进签名区
|
|
397
|
-
const isLastContent = index ===
|
|
401
|
+
const isLastContent = index === contentsLength - 1
|
|
398
402
|
const signReserve = isLastContent ? this.getSignHeight() : 0
|
|
399
403
|
/** 当前page可容纳的table高度 */
|
|
400
404
|
let pageAccomodateTableHeight = roundHeight(
|
|
@@ -486,7 +490,7 @@ class PrinterStore {
|
|
|
486
490
|
)
|
|
487
491
|
break
|
|
488
492
|
}
|
|
489
|
-
//
|
|
493
|
+
// 行无法拆分(普通长文本列)或拆分失败时,强制推进 end 防止死循环
|
|
490
494
|
if (end === begin) {
|
|
491
495
|
// 新一页可容纳的 table 高度(页高 - 页眉页脚)
|
|
492
496
|
const fullPageAccomodateTableHeight = roundHeight(
|
|
@@ -605,9 +609,8 @@ class PrinterStore {
|
|
|
605
609
|
currentPageHeight += this.getSignHeight()
|
|
606
610
|
}
|
|
607
611
|
|
|
608
|
-
this.remainPageHeight = Math.
|
|
609
|
-
0,
|
|
610
|
-
Math.round(pageHeight - currentPageHeight)
|
|
612
|
+
this.remainPageHeight = Math.round(
|
|
613
|
+
Math.max(0, pageHeight - currentPageHeight)
|
|
611
614
|
)
|
|
612
615
|
this.isSave = false
|
|
613
616
|
this.config.isSave = false
|
|
@@ -1045,7 +1048,12 @@ class PrinterStore {
|
|
|
1045
1048
|
)
|
|
1046
1049
|
)
|
|
1047
1050
|
withPartial.push(...fillList)
|
|
1048
|
-
|
|
1051
|
+
// 半行续号与空行起始序号统一收敛,防止两处各自计算造成序号重复(如双栏 5 条出现两个 6)
|
|
1052
|
+
this.data._table[dataKey] = normalizeMultiSerials(
|
|
1053
|
+
withPartial,
|
|
1054
|
+
colNumber,
|
|
1055
|
+
this.fillIndex
|
|
1056
|
+
)
|
|
1049
1057
|
}
|
|
1050
1058
|
|
|
1051
1059
|
@action.bound
|
|
@@ -2,10 +2,9 @@ import React from 'react'
|
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import _ from 'lodash'
|
|
4
4
|
// import Big from 'big.js'
|
|
5
|
-
import { coverDigit2Uppercase, getDataKey } from '../util'
|
|
5
|
+
import { coverDigit2Uppercase, getDataKey, maskedSum } from '../util'
|
|
6
6
|
import { observer } from 'mobx-react'
|
|
7
7
|
import classNames from 'classnames'
|
|
8
|
-
import Big from 'big.js'
|
|
9
8
|
|
|
10
9
|
const DiyOverallOrder = props => {
|
|
11
10
|
const {
|
|
@@ -15,20 +14,14 @@ const DiyOverallOrder = props => {
|
|
|
15
14
|
} = props
|
|
16
15
|
const tableData = printerStore.data._table[getDataKey(dataKey)] || []
|
|
17
16
|
|
|
18
|
-
//
|
|
17
|
+
// 计算合计:任一渲染结果脱敏 '***' 则合计显 '***'(整格判定假设同 table_diy_summary_tr)
|
|
19
18
|
const sumData = field => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
.replace(/\(\)/g, '')
|
|
27
|
-
result = a.plus(+bRes || 0)
|
|
28
|
-
return result
|
|
29
|
-
},
|
|
30
|
-
Big(0)
|
|
31
|
-
).toFixed(2)
|
|
19
|
+
const values = _.map(tableData, (b, i) =>
|
|
20
|
+
printerStore
|
|
21
|
+
.templateTable(field, dataKey, i, pageIndex)
|
|
22
|
+
.replace(/\(\)/g, '')
|
|
23
|
+
)
|
|
24
|
+
return maskedSum(values)
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
if (!diyOverallOrder?.show || !printerStore?.ready) {
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
import _ from 'lodash'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
coverDigit2Uppercase,
|
|
6
|
+
getDataKey,
|
|
7
|
+
isMultiTable,
|
|
8
|
+
maskedSum
|
|
9
|
+
} from '../util'
|
|
5
10
|
import { MULTI_SUFFIX, MULTI_SUFFIX3 } from '../config'
|
|
6
11
|
import { observer } from 'mobx-react'
|
|
7
12
|
import classNames from 'classnames'
|
|
8
|
-
import Big from 'big.js'
|
|
9
13
|
|
|
10
14
|
function buildTemplateField(fieldStr, suffix) {
|
|
11
15
|
// 如果 field 是 "{{列.下单数}}",提取出 "下单数"
|
|
@@ -45,39 +49,18 @@ const DiySummary = props => {
|
|
|
45
49
|
|
|
46
50
|
// 计算合计
|
|
47
51
|
const sumData = field => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// 三栏
|
|
62
|
-
const multiField3 = buildTemplateField(field, MULTI_SUFFIX3)
|
|
63
|
-
result = result.plus(+getRes(multiField3, i) || 0)
|
|
64
|
-
|
|
65
|
-
return result
|
|
66
|
-
},
|
|
67
|
-
Big(0)
|
|
68
|
-
).toFixed(2)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return _.reduce(
|
|
72
|
-
tableData,
|
|
73
|
-
(a, b, i) => {
|
|
74
|
-
let result = a
|
|
75
|
-
const bRes = getRes(field, i)
|
|
76
|
-
result = a.plus(+bRes || 0)
|
|
77
|
-
return result
|
|
78
|
-
},
|
|
79
|
-
Big(0)
|
|
80
|
-
).toFixed(2)
|
|
52
|
+
// 收集本列渲染结果(含多栏后缀列),任一脱敏 '***' 则合计显 '***'
|
|
53
|
+
// 注意:基于渲染后字符串判定,假设模板整格就是脱敏值;带前后缀的模板(如 '{{列.金额}}元')无法识别
|
|
54
|
+
const values = []
|
|
55
|
+
_.each(tableData, (b, i) => {
|
|
56
|
+
values.push(getRes(field, i))
|
|
57
|
+
if (isMulti) {
|
|
58
|
+
// 双栏/三栏取后缀字段
|
|
59
|
+
values.push(getRes(buildTemplateField(field, MULTI_SUFFIX), i))
|
|
60
|
+
values.push(getRes(buildTemplateField(field, MULTI_SUFFIX3), i))
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
return maskedSum(values)
|
|
81
64
|
|
|
82
65
|
function getRes(field, i) {
|
|
83
66
|
return printerStore
|
|
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
|
|
|
4
4
|
import _ from 'lodash'
|
|
5
5
|
import { MULTI_SUFFIX, MULTI_SUFFIX3 } from '../config'
|
|
6
6
|
import Big from 'big.js'
|
|
7
|
-
import { coverDigit2Uppercase, getDataKey } from '../util'
|
|
7
|
+
import { coverDigit2Uppercase, getDataKey, maskedSum } from '../util'
|
|
8
8
|
import { observer } from 'mobx-react'
|
|
9
9
|
import { get } from 'mobx'
|
|
10
10
|
import classNames from 'classnames'
|
|
@@ -76,21 +76,18 @@ const SubtotalTr = props => {
|
|
|
76
76
|
if (field === 'real_item_price') field = '出库金额'
|
|
77
77
|
if (field === 'settle_money2') field = '结算金额'
|
|
78
78
|
if (field === 'total_money2') field = '金额'
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
Big(0)
|
|
93
|
-
).toFixed(2)
|
|
79
|
+
// 收集本列所有值(含多栏后缀列),任一脱敏 '***' 则合计显 '***',否则 Big('***') 会崩溃
|
|
80
|
+
const values = []
|
|
81
|
+
_.each(list, b => {
|
|
82
|
+
values.push(b[field])
|
|
83
|
+
if (b?.[field + MULTI_SUFFIX]) {
|
|
84
|
+
values.push(b[field + MULTI_SUFFIX])
|
|
85
|
+
}
|
|
86
|
+
if (b?.[field + MULTI_SUFFIX3]) {
|
|
87
|
+
values.push(b[field + MULTI_SUFFIX3])
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
return maskedSum(values)
|
|
94
91
|
}
|
|
95
92
|
|
|
96
93
|
const getData = field => {
|
package/src/util.js
CHANGED
|
@@ -120,7 +120,23 @@ function getOverallOrderTrHeight(overallOrder) {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
// eslint-disable-next-line
|
|
123
|
+
// 成本权限脱敏值:后端对无成本权限用户的金额字段返回 '***'(商品维度混合脱敏)
|
|
124
|
+
const MASKED_VALUE = '***'
|
|
125
|
+
const isMaskedValue = v => v === MASKED_VALUE
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 脱敏感知求和:任一值为 '***' 则整体返回 '***'(口径:合计不能暴露脱敏行的贡献)
|
|
129
|
+
* 非数字值按 0 容错,同时兼容原始数值字段与渲染后字符串
|
|
130
|
+
* @param {Array} values 参与求和的值
|
|
131
|
+
*/
|
|
132
|
+
const maskedSum = values => {
|
|
133
|
+
if (values.some(isMaskedValue)) return MASKED_VALUE
|
|
134
|
+
return values.reduce((a, b) => a.plus(+b || 0), Big(0)).toFixed(2)
|
|
135
|
+
}
|
|
136
|
+
|
|
123
137
|
const coverDigit2Uppercase = n => {
|
|
138
|
+
// 脱敏值直接透传:否则 Math.abs('***') 得 NaN,Big(NaN) 会抛异常
|
|
139
|
+
if (isMaskedValue(n)) return MASKED_VALUE
|
|
124
140
|
if (_.isNil(n) || _.isNaN(n)) {
|
|
125
141
|
return '-'
|
|
126
142
|
}
|
|
@@ -384,5 +400,8 @@ export {
|
|
|
384
400
|
caclSingleDetailsPageHeight,
|
|
385
401
|
getArrayMid,
|
|
386
402
|
getColSpanLength,
|
|
387
|
-
getOverallOrderTrHeight
|
|
403
|
+
getOverallOrderTrHeight,
|
|
404
|
+
MASKED_VALUE,
|
|
405
|
+
isMaskedValue,
|
|
406
|
+
maskedSum
|
|
388
407
|
}
|