gm-printer 10.39.4-beta.2 → 10.39.4-beta.21
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/data_key_util.js +35 -0
- package/src/common/editor_edit_field.js +288 -167
- package/src/common/editor_store.js +230 -42
- package/src/common/hoc_with_store.js +9 -0
- package/src/common/style.lesss +43 -0
- package/src/common/util.js +58 -4
- package/src/editor/context_menu.js +17 -0
- package/src/editor/store.js +13 -0
- package/src/editor_purchase/editor.js +2 -1
- package/src/editor_purchase/editor_special_table.js +39 -17
- package/src/editor_purchase/editor_sum_table.js +5 -1
- package/src/editor_purchase/store.js +48 -45
- package/src/finance_voucher/components/table_subtotal_tr.js +12 -18
- package/src/index.js +6 -2
- package/src/printer/block.js +154 -4
- package/src/printer/compute_pages.js +122 -0
- package/src/printer/index.js +3 -1
- package/src/printer/long_print_table/index.js +14 -4
- package/src/printer/multi_column.js +1 -0
- package/src/printer/page_summary.js +3 -1
- package/src/printer/printer.js +23 -3
- package/src/printer/store.js +141 -91
- package/src/printer/table.js +11 -3
- package/src/printer/table_diy_overallOrder_tr.js +8 -15
- package/src/printer/table_diy_summary_tr.js +18 -35
- package/src/printer/table_overallOrder_tr.js +49 -37
- package/src/printer/table_special_tr.js +17 -2
- package/src/printer/table_subtotal_tr.js +100 -16
- package/src/util.js +34 -8
- package/yarn-error.log +372 -152
|
@@ -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)
|
|
@@ -25,6 +25,21 @@ const SpecialTr = ({ data, config }) => {
|
|
|
25
25
|
} = specialConfig
|
|
26
26
|
const { list, type, fixedSize } = data
|
|
27
27
|
|
|
28
|
+
// 「显示分类名称/小计文案修改」实时生效:数据行带 _prefix 原料时,按当前 specialConfig 重拼前缀
|
|
29
|
+
// 打印时配置与数据层拼前缀所用配置一致,重拼结果不变;编辑器预览改配置时实时刷新;导出(paint.js)不走本组件不受影响
|
|
30
|
+
const applySubtotalText = html => {
|
|
31
|
+
if (typeof html !== 'string' || data._prefix === undefined) {
|
|
32
|
+
return html
|
|
33
|
+
}
|
|
34
|
+
const showCategoryName = specialConfig?.showCategoryName ?? true
|
|
35
|
+
const subtotalText = specialConfig?.subtotalText ?? '小计'
|
|
36
|
+
const newPrefix = showCategoryName
|
|
37
|
+
? `${data._categoryName ?? ''}${subtotalText}:`
|
|
38
|
+
: `${subtotalText}:`
|
|
39
|
+
// 前缀位于字符串头部,首次命中即替换;用函数替换避免 newPrefix 含 $ 序列时被特俗解释
|
|
40
|
+
return html.replace(data._prefix, () => newPrefix)
|
|
41
|
+
}
|
|
42
|
+
|
|
28
43
|
let compiled
|
|
29
44
|
try {
|
|
30
45
|
compiled = _.template(template_text, { interpolate: /{{([\s\S]+?)}}/g })
|
|
@@ -119,7 +134,7 @@ const SpecialTr = ({ data, config }) => {
|
|
|
119
134
|
className='gm-flex-page gm-flex-justify-between-page'
|
|
120
135
|
style={{ 'justify-content': 'space-between' }}
|
|
121
136
|
dangerouslySetInnerHTML={{
|
|
122
|
-
__html: htmlStr || data.text
|
|
137
|
+
__html: applySubtotalText(htmlStr || data.text)
|
|
123
138
|
}}
|
|
124
139
|
/>
|
|
125
140
|
</td>
|
|
@@ -145,7 +160,7 @@ const SpecialTr = ({ data, config }) => {
|
|
|
145
160
|
colSpan={99}
|
|
146
161
|
style={Object.assign({ fontWeight: 'bold' }, style)}
|
|
147
162
|
dangerouslySetInnerHTML={{
|
|
148
|
-
__html: getHtml() || data.text
|
|
163
|
+
__html: applySubtotalText(getHtml() || data.text)
|
|
149
164
|
}}
|
|
150
165
|
/>
|
|
151
166
|
</tr>
|
|
@@ -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 => {
|
|
@@ -134,6 +131,93 @@ const SubtotalTr = props => {
|
|
|
134
131
|
</tr>
|
|
135
132
|
)
|
|
136
133
|
} else {
|
|
134
|
+
// 单元格拆分展示:第一格(左侧文案+数值)拆分为两个单元格,对齐复用每页合计设置的 textAlign;
|
|
135
|
+
// 与打印账户总计金额支持共存(2026-09 交互确认):拆分只作用于第一格,其余格按原 colSpan 渲染(与导出侧 paintSubtotal 行为一致)
|
|
136
|
+
if (get(subtotal, 'isSplitCells')) {
|
|
137
|
+
const item = fields[0]
|
|
138
|
+
// 第一格总 colSpan 拆一半给左侧文案,剩余给数值(colSpan 缺省 99 表示整行);
|
|
139
|
+
// 宽度分配沿用原有逻辑:各格按 store 侧 fields[n].colSpan 照画,渲染端不调宽度
|
|
140
|
+
const totalColSpan = item.colSpan ?? 99
|
|
141
|
+
const leftColSpan = Math.floor(totalColSpan / 2)
|
|
142
|
+
const cellStyle = {
|
|
143
|
+
fontWeight: 'bold',
|
|
144
|
+
justifyContent: flexStyle[subtotal.style?.textAlign],
|
|
145
|
+
...subtotal.style
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<tr>
|
|
150
|
+
<td colSpan={leftColSpan}>
|
|
151
|
+
<div style={cellStyle} className='gm-flex-page'>
|
|
152
|
+
{item.name}
|
|
153
|
+
</div>
|
|
154
|
+
</td>
|
|
155
|
+
<td colSpan={totalColSpan - leftColSpan}>
|
|
156
|
+
<div style={cellStyle} className='gm-flex-page'>
|
|
157
|
+
<div
|
|
158
|
+
className={classNames('gm-flex-page', {
|
|
159
|
+
'gm-flex-justify-between-page': isUpperLowerCaseSeparate,
|
|
160
|
+
'gm-flex-grow-page': isUpperLowerCaseSeparate
|
|
161
|
+
})}
|
|
162
|
+
>
|
|
163
|
+
<span
|
|
164
|
+
className={
|
|
165
|
+
isUpperCaseBefore
|
|
166
|
+
? 'gm-printer-subtotal-isUpperCaseBefore-inter'
|
|
167
|
+
: ''
|
|
168
|
+
}
|
|
169
|
+
>
|
|
170
|
+
{item.type === 'useSummarize'
|
|
171
|
+
? getData(item.valueField)
|
|
172
|
+
: sumData2(list, item.valueField)}
|
|
173
|
+
</span>
|
|
174
|
+
{subtotal?.needUpperCase && (
|
|
175
|
+
<span>
|
|
176
|
+
{item.type === 'useSummarize'
|
|
177
|
+
? '大写:' +
|
|
178
|
+
coverDigit2Uppercase(getData(item.valueField))
|
|
179
|
+
: '大写:' +
|
|
180
|
+
coverDigit2Uppercase(sumData2(list, item.valueField))}
|
|
181
|
+
</span>
|
|
182
|
+
)}
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</td>
|
|
186
|
+
{/* 拆分只拆第一格;其余格(打印账户总计金额等)沿用普通多格渲染语义 */}
|
|
187
|
+
{_.map(fields.slice(1), (extra, extraIndex) => (
|
|
188
|
+
<td
|
|
189
|
+
colSpan={extra.colSpan ?? 99}
|
|
190
|
+
key={`split_extra_${extraIndex}`}
|
|
191
|
+
>
|
|
192
|
+
<div style={cellStyle} className='gm-flex-page'>
|
|
193
|
+
{extra.name}
|
|
194
|
+
<div
|
|
195
|
+
className={classNames('gm-flex-page', {
|
|
196
|
+
'gm-flex-justify-between-page': isUpperLowerCaseSeparate,
|
|
197
|
+
'gm-flex-grow-page': isUpperLowerCaseSeparate
|
|
198
|
+
})}
|
|
199
|
+
>
|
|
200
|
+
<span>
|
|
201
|
+
{/* 账户总计金额等固定取数字段走 useSummarize;拆分场景其余格不参与当页求和 */}
|
|
202
|
+
{extra.type === 'useSummarize'
|
|
203
|
+
? getData(extra.valueField)
|
|
204
|
+
: ''}
|
|
205
|
+
</span>
|
|
206
|
+
{subtotal?.needUpperCase &&
|
|
207
|
+
extra.type === 'useSummarize' && (
|
|
208
|
+
<span>
|
|
209
|
+
{'大写:' +
|
|
210
|
+
coverDigit2Uppercase(getData(extra.valueField))}
|
|
211
|
+
</span>
|
|
212
|
+
)}
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
</td>
|
|
216
|
+
))}
|
|
217
|
+
</tr>
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
137
221
|
return (
|
|
138
222
|
<tr>
|
|
139
223
|
{_.map(fields, (item, index) => {
|
package/src/util.js
CHANGED
|
@@ -86,13 +86,12 @@ function exchange(arr, target, source) {
|
|
|
86
86
|
return arr
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
let timer
|
|
90
|
-
|
|
91
89
|
function afterImgAndSvgLoaded(callback, $printer) {
|
|
92
90
|
const $imgList = $printer.querySelectorAll('img')
|
|
93
91
|
const $svgList = $printer.querySelectorAll('svg')
|
|
94
92
|
|
|
95
|
-
|
|
93
|
+
// timer 为函数内局部变量:computePages(导出测高)与 doPrint(打印)可能并发调用本函数,
|
|
94
|
+
// 若共享模块级 timer,后调用方会 clearTimeout 掉前一方的轮询,导致其 callback 永不执行
|
|
96
95
|
|
|
97
96
|
const everyThingIsOk =
|
|
98
97
|
_.every($imgList, img => img.complete) &&
|
|
@@ -100,7 +99,7 @@ function afterImgAndSvgLoaded(callback, $printer) {
|
|
|
100
99
|
if (everyThingIsOk) {
|
|
101
100
|
callback()
|
|
102
101
|
} else {
|
|
103
|
-
|
|
102
|
+
setTimeout(afterImgAndSvgLoaded.bind(this, callback, $printer), 300)
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
105
|
|
|
@@ -121,7 +120,23 @@ function getOverallOrderTrHeight(overallOrder) {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
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
|
+
|
|
124
137
|
const coverDigit2Uppercase = n => {
|
|
138
|
+
// 脱敏值直接透传:否则 Math.abs('***') 得 NaN,Big(NaN) 会抛异常
|
|
139
|
+
if (isMaskedValue(n)) return MASKED_VALUE
|
|
125
140
|
if (_.isNil(n) || _.isNaN(n)) {
|
|
126
141
|
return '-'
|
|
127
142
|
}
|
|
@@ -237,16 +252,24 @@ const caclSingleDetailsPageHeight = (detailsHeights, curRemainPageHeight) => {
|
|
|
237
252
|
* @param {*} arr
|
|
238
253
|
*/
|
|
239
254
|
const getArrayMid = arr => {
|
|
255
|
+
let majority = 23
|
|
256
|
+
|
|
257
|
+
if (arr.length === 0) return majority
|
|
258
|
+
|
|
259
|
+
// 行数少时直接取最小行高,跳过多轮 Map 统计
|
|
260
|
+
if (arr.length <= 30) {
|
|
261
|
+
const min = Math.min(...arr)
|
|
262
|
+
if (min / 23 > 10) return 23
|
|
263
|
+
return min
|
|
264
|
+
}
|
|
265
|
+
|
|
240
266
|
/** 数组元素出现次数的集合 */
|
|
241
267
|
const mapArr = []
|
|
242
268
|
const map = new Map()
|
|
243
|
-
let majority = 23
|
|
244
269
|
/** 次数相同的元素集合 */
|
|
245
270
|
const majorityArr = []
|
|
246
271
|
const min = Math.min(...arr)
|
|
247
272
|
|
|
248
|
-
if (arr.length === 0) return majority
|
|
249
|
-
|
|
250
273
|
_.forEach(arr, (val, key) => {
|
|
251
274
|
if (map.has(val)) {
|
|
252
275
|
map.set(val, map.get(val) + 1)
|
|
@@ -377,5 +400,8 @@ export {
|
|
|
377
400
|
caclSingleDetailsPageHeight,
|
|
378
401
|
getArrayMid,
|
|
379
402
|
getColSpanLength,
|
|
380
|
-
getOverallOrderTrHeight
|
|
403
|
+
getOverallOrderTrHeight,
|
|
404
|
+
MASKED_VALUE,
|
|
405
|
+
isMaskedValue,
|
|
406
|
+
maskedSum
|
|
381
407
|
}
|