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.
Files changed (37) hide show
  1. package/build/demo.js +9 -9
  2. package/locales/en.json +3 -0
  3. package/locales/th.json +3 -0
  4. package/locales/zh-HK.json +3 -0
  5. package/package.json +1 -1
  6. package/src/common/common_context_menu.js +6 -4
  7. package/src/common/component.js +64 -8
  8. package/src/common/data_key_util.js +35 -0
  9. package/src/common/editor_edit_field.js +288 -167
  10. package/src/common/editor_store.js +230 -42
  11. package/src/common/hoc_with_store.js +9 -0
  12. package/src/common/style.lesss +43 -0
  13. package/src/common/util.js +58 -4
  14. package/src/editor/context_menu.js +17 -0
  15. package/src/editor/store.js +13 -0
  16. package/src/editor_purchase/editor.js +2 -1
  17. package/src/editor_purchase/editor_special_table.js +39 -17
  18. package/src/editor_purchase/editor_sum_table.js +5 -1
  19. package/src/editor_purchase/store.js +48 -45
  20. package/src/finance_voucher/components/table_subtotal_tr.js +12 -18
  21. package/src/index.js +6 -2
  22. package/src/printer/block.js +154 -4
  23. package/src/printer/compute_pages.js +122 -0
  24. package/src/printer/index.js +3 -1
  25. package/src/printer/long_print_table/index.js +14 -4
  26. package/src/printer/multi_column.js +1 -0
  27. package/src/printer/page_summary.js +3 -1
  28. package/src/printer/printer.js +23 -3
  29. package/src/printer/store.js +141 -91
  30. package/src/printer/table.js +11 -3
  31. package/src/printer/table_diy_overallOrder_tr.js +8 -15
  32. package/src/printer/table_diy_summary_tr.js +18 -35
  33. package/src/printer/table_overallOrder_tr.js +49 -37
  34. package/src/printer/table_special_tr.js +17 -2
  35. package/src/printer/table_subtotal_tr.js +100 -16
  36. package/src/util.js +34 -8
  37. package/yarn-error.log +372 -152
@@ -0,0 +1,122 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+ import _ from 'lodash'
4
+ import { toJS } from 'mobx'
5
+ import Printer from './printer'
6
+ import getCSS from './get_css'
7
+ import { afterImgAndSvgLoaded } from '../util'
8
+ import { LONG_PRINT } from '../config'
9
+
10
+ // 与 do_print.js 的容器隔离,使用独立 iframe,避免和打印任务互相 unmount 对方内容
11
+ const printerId = '_gm-printer-compute-pages_' + Math.random()
12
+ let $printer = null
13
+
14
+ /**
15
+ * 初始化隐藏渲染容器
16
+ * 复制自 do_print.js 的 init({ isTest: true }) 分支(iframe 创建 + getCSS 注入),
17
+ * 差异仅 id 前缀与「永远隐藏」。⚠️ get_css / 容器初始化逻辑变更时两处需同步,
18
+ * 否则测量环境与打印环境漂移,分页边界不再一致
19
+ */
20
+ function init() {
21
+ if (!$printer) {
22
+ $printer = window.document.createElement('iframe')
23
+ $printer.id = printerId
24
+ $printer.style.position = 'fixed'
25
+ $printer.style.top = '0'
26
+ $printer.style.width = '100%'
27
+ // 隐藏起来,用户不可见
28
+ $printer.style.left = '-2000px'
29
+ window.document.body.appendChild($printer)
30
+
31
+ const idocument = $printer.contentDocument
32
+ idocument.open()
33
+ idocument.write('<!DOCTYPE html><html><head></head><body></body></html>')
34
+ idocument.close()
35
+
36
+ const doc = $printer.contentWindow.document
37
+
38
+ const style = doc.createElement('style')
39
+ style.appendChild(doc.createTextNode(getCSS()))
40
+ doc.head.appendChild(style)
41
+
42
+ const div = doc.createElement('div')
43
+ div.id = 'appContainer'
44
+
45
+ doc.body.appendChild(div)
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 按打印分页逻辑计算分页结果(不触发打印)
51
+ *
52
+ * 场景:导出功能需要拿到与打印完全一致的分页边界
53
+ *
54
+ * 不支持的模板类型(返回空 pages,调用方需自行降级):
55
+ * - batchPrintConfig === 2(合并打印):componentDidMount 不跑 computedPages,pages 恒空
56
+ * - page.type === LONG_PRINT(长条打印):走 renderLongPage 全量渲染,pages 不对应真实布局
57
+ *
58
+ * @param {Object} options
59
+ * @param {Object} options.data 打印数据(结构同 doPrint 的 data,含 _table)
60
+ * @param {Object} options.config 模板配置(结构同 doPrint 的 config)
61
+ * @param {boolean} [options.isSomeSubtotalTr] 每页合计是否展示多个字段(对齐 doPrint 第三参,
62
+ * 影响合计行渲染与行高,进而影响分页边界)
63
+ * @returns {Promise<{pages: Array, remainPageHeight: number, tableCustomerRowHeight: number}>}
64
+ * pages: [[{type, index, begin, end}, ...], ...] 对 data._table[contents[i].dataKey] 行号的切片
65
+ * remainPageHeight: 最后一页剩余高度(供行数填充换算)
66
+ * tableCustomerRowHeight: 表格行高(供行数填充换算)
67
+ */
68
+ function computePages({ data, config, isSomeSubtotalTr }) {
69
+ // 不支持的模板类型提前告警(不阻断,返回结果交由调用方降级处理)
70
+ if (config.batchPrintConfig === 2 || config.page?.type === LONG_PRINT) {
71
+ console.warn(
72
+ '[gm-printer] computePages: 当前模板为合并打印或长条打印,computedPages 不生效,pages 将为空'
73
+ )
74
+ }
75
+
76
+ return new window.Promise(resolve => {
77
+ init()
78
+
79
+ const $app = $printer.contentWindow.document.getElementById('appContainer')
80
+ ReactDOM.unmountComponentAtNode($app)
81
+
82
+ // computedPages 处理采购明细拆行时会原地 splice data._table,
83
+ // 深拷贝一份,避免污染调用方数据
84
+ const clonedData = _.cloneDeep(data)
85
+ // computedPages 会往 config 顶层写 isSave(store.js),浅拷贝隔离开调用方的
86
+ // template 对象(stationv2 导出时同一 template 跨多个 sheet 复用)
87
+ const clonedConfig = { ...config }
88
+
89
+ // 依赖 WithStorePrinter 实例字段 printerStore(printer.js)读取分页结果,
90
+ // Printer 组件重构(store 挂载方式变化)时此处需同步
91
+ let printerRef = null
92
+ ReactDOM.render(
93
+ <Printer
94
+ ref={ref => {
95
+ printerRef = ref
96
+ }}
97
+ isSomeSubtotalTr={isSomeSubtotalTr}
98
+ config={clonedConfig}
99
+ data={clonedData}
100
+ onReady={() => {
101
+ // onReady 触发时 componentDidMount 已同步执行完 computedPages(),pages 就绪
102
+ // 模板含图片时等图片加载完成,避免图片撑高导致测量偏差
103
+ afterImgAndSvgLoaded(() => {
104
+ const store = printerRef.printerStore
105
+ const result = {
106
+ pages: toJS(store.pages),
107
+ remainPageHeight: store.remainPageHeight,
108
+ tableCustomerRowHeight: store.computedTableCustomerRowHeight
109
+ }
110
+
111
+ // 读取完成后卸载,避免 DOM 累积
112
+ ReactDOM.unmountComponentAtNode($app)
113
+ resolve(result)
114
+ }, $app)
115
+ }}
116
+ />,
117
+ $app
118
+ )
119
+ })
120
+ }
121
+
122
+ export { computePages }
@@ -7,6 +7,7 @@ import {
7
7
  doBatchFinancePrint,
8
8
  setPrintStyle
9
9
  } from './do_print'
10
+ import { computePages } from './compute_pages'
10
11
  import getCSS from './get_css'
11
12
 
12
13
  export {
@@ -17,5 +18,6 @@ export {
17
18
  getCSS,
18
19
  getPrintContainerHTML,
19
20
  doBatchFinancePrint,
20
- setPrintStyle
21
+ setPrintStyle,
22
+ computePages
21
23
  }
@@ -111,7 +111,8 @@ class Table extends React.Component {
111
111
  range,
112
112
  pageIndex,
113
113
  printerStore,
114
- isSomeSubtotalTr
114
+ isSomeSubtotalTr,
115
+ isLastTablePage
115
116
  } = this.props
116
117
  // 数据
117
118
  dataKey = getDataKey(dataKey, arrange)
@@ -202,7 +203,8 @@ class Table extends React.Component {
202
203
  ? printerStore.templateSpecialDetails(
203
204
  col,
204
205
  dataKey,
205
- i
206
+ i,
207
+ config.specialConfig?.template_text
206
208
  )
207
209
  : printerStore
208
210
  .templateTable(
@@ -227,6 +229,7 @@ class Table extends React.Component {
227
229
  range={range}
228
230
  config={config}
229
231
  printerStore={printerStore}
232
+ isLastTablePage={isLastTablePage}
230
233
  />
231
234
  <DiyOverallOrder
232
235
  range={range}
@@ -307,7 +310,8 @@ class Table extends React.Component {
307
310
  ? printerStore.templateSpecialDetails(
308
311
  col,
309
312
  dataKey,
310
- i
313
+ i,
314
+ config.specialConfig?.template_text
311
315
  )
312
316
  : printerStore
313
317
  .templateTable(col.text, dataKey, i, pageIndex)
@@ -327,6 +331,7 @@ class Table extends React.Component {
327
331
  range={range}
328
332
  config={config}
329
333
  printerStore={printerStore}
334
+ isLastTablePage={isLastTablePage}
330
335
  />
331
336
  <DiyOverallOrder
332
337
  range={range}
@@ -385,7 +390,12 @@ Table.propTypes = {
385
390
  pageIndex: PropTypes.number.isRequired,
386
391
  placeholder: PropTypes.string,
387
392
  printerStore: PropTypes.object,
388
- isSomeSubtotalTr: PropTypes.bool
393
+ isSomeSubtotalTr: PropTypes.bool,
394
+ isLastTablePage: PropTypes.bool
395
+ }
396
+
397
+ Table.defaultProps = {
398
+ isLastTablePage: true
389
399
  }
390
400
 
391
401
  export default Table
@@ -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'
@@ -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
@@ -14,6 +14,20 @@ import { LONG_PRINT } from '../config'
14
14
  import { getDataKey } from '../util'
15
15
  import Big from 'big.js'
16
16
 
17
+ /** 当前 panel 是否为该表格 content 在全部分页中的最后一次出现 */
18
+ const isLastTablePanel = (pages, pageIndex, panelIndexInPage, tableIndex) => {
19
+ for (let pi = pages.length - 1; pi >= 0; pi--) {
20
+ const page = pages[pi] || []
21
+ for (let pji = page.length - 1; pji >= 0; pji--) {
22
+ const p = page[pji]
23
+ if (p?.type === 'table' && p.index === tableIndex) {
24
+ return pi === pageIndex && pji === panelIndexInPage
25
+ }
26
+ }
27
+ }
28
+ return true
29
+ }
30
+
17
31
  // Header Sign Footer 相对特殊,要单独处理
18
32
  const Header = props => (
19
33
  <Panel {...props} name='header' placeholder={i18next.t('页眉')} />
@@ -104,9 +118,7 @@ class Printer extends React.Component {
104
118
  componentDidMount() {
105
119
  const { printerStore, config, getremainpageHeight } = this.props
106
120
  const batchPrintConfig = config.batchPrintConfig
107
- // didMount 代表第一次渲染完成
108
- printerStore.setReady(true)
109
- // 连续打印不需要分页计算
121
+ // didMount 代表第一次渲染完成,先分页再 ready,避免空 pages 触发 renderPage
110
122
  if (batchPrintConfig !== 2) {
111
123
  // 先分页拿到剩余高度,再补空行,最后按补空后的数据重新分页
112
124
  // (若先分页后补空却不重算,panel.end 仍是补空前行数,空行/后半数据会被裁掉)
@@ -121,8 +133,10 @@ class Printer extends React.Component {
121
133
  printerStore.changeTableData()
122
134
  printerStore.computedPages()
123
135
  }
136
+ // 获取剩余空白高度,传到 editor
124
137
  getremainpageHeight && getremainpageHeight(printerStore.remainPageHeight)
125
138
  }
139
+ printerStore.setReady(true)
126
140
 
127
141
  // Printer 不是立马就呈现出最终样式,有个过程。这个过程需要时间,什么 ready,不太清楚,估借 setState 来获取过程结束时刻
128
142
  this.setState({}, () => {
@@ -292,6 +306,12 @@ class Printer extends React.Component {
292
306
  placeholder={`${i18next.t('区域')} ${panel.index}`}
293
307
  pageIndex={i}
294
308
  isSomeSubtotalTr={isSomeSubtotalTr}
309
+ isLastTablePage={isLastTablePanel(
310
+ printerStore.pages,
311
+ i,
312
+ ii,
313
+ panel.index
314
+ )}
295
315
  />
296
316
  )
297
317