gm-printer 10.41.5 → 10.41.6-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-printer",
3
- "version": "10.41.5",
3
+ "version": "10.41.6-beta.1",
4
4
  "description": "diy printer",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -109,7 +109,7 @@ class CommonContextMenu extends React.Component {
109
109
  })
110
110
  }
111
111
 
112
- handleInsertBlock = (type, link) => {
112
+ handleInsertBlock = (type, link, ratio) => {
113
113
  const { editStore } = this.props
114
114
  const { name, block } = this.state
115
115
 
@@ -120,7 +120,8 @@ class CommonContextMenu extends React.Component {
120
120
  left: block.left + 'px',
121
121
  top: block.top + 'px'
122
122
  },
123
- link
123
+ link,
124
+ ratio
124
125
  )
125
126
 
126
127
  this.setState({
@@ -160,8 +161,8 @@ class CommonContextMenu extends React.Component {
160
161
  })
161
162
  }
162
163
 
163
- handleInsertImage = imgURL => {
164
- this.handleInsertBlock('image', imgURL)
164
+ handleInsertImage = (imgURL, ratio) => {
165
+ this.handleInsertBlock('image', imgURL, ratio)
165
166
  }
166
167
 
167
168
  handleRemove = () => {
@@ -327,6 +328,7 @@ class CommonContextMenu extends React.Component {
327
328
  onSuccess={this.handleInsertImage}
328
329
  key={v.value}
329
330
  text={v.text}
331
+ imageConfig={this.props.editStore.imageConfig}
330
332
  />
331
333
  ) : (
332
334
  <div
@@ -391,12 +391,26 @@ Line.propTypes = {
391
391
 
392
392
  class Size extends React.Component {
393
393
  handleChange = (type, value) => {
394
- const { onChange, style } = this.props
394
+ const { onChange, style, ratio } = this.props
395
395
 
396
- onChange({
396
+ const next = {
397
397
  ...style,
398
398
  [type]: value
399
- })
399
+ }
400
+
401
+ // 电子签章:有原始比例时宽高联动,不允许拉变形
402
+ if (ratio && value !== '' && !value.endsWith('%')) {
403
+ const num = parseFloat(value)
404
+ if (!_.isNaN(num) && num > 0) {
405
+ if (type === 'width') {
406
+ next.height = num / ratio + 'px'
407
+ } else {
408
+ next.width = num * ratio + 'px'
409
+ }
410
+ }
411
+ }
412
+
413
+ onChange(next)
400
414
  }
401
415
 
402
416
  render() {
@@ -420,7 +434,8 @@ class Size extends React.Component {
420
434
 
421
435
  Size.propTypes = {
422
436
  style: PropTypes.object.isRequired,
423
- onChange: PropTypes.func.isRequired
437
+ onChange: PropTypes.func.isRequired,
438
+ ratio: PropTypes.number
424
439
  }
425
440
 
426
441
  class ImageUploader extends React.Component {
@@ -437,7 +452,26 @@ class ImageUploader extends React.Component {
437
452
  : event.target.files
438
453
  const file = droppedFiles[0]
439
454
 
440
- if (file.size > 512 * 1024) {
455
+ if (!file) return
456
+
457
+ const { imageConfig } = this.props
458
+
459
+ if (imageConfig) {
460
+ // 增强模式(电子签章):校验类型与大小,提示文案由配置方给出
461
+ const acceptTypes = imageConfig.acceptTypes || [
462
+ 'image/jpeg',
463
+ 'image/jpg',
464
+ 'image/png'
465
+ ]
466
+ if (!_.includes(acceptTypes, file.type)) {
467
+ Tip.warning(imageConfig.wrongTypeTip)
468
+ return
469
+ }
470
+ if (file.size > imageConfig.maxSize) {
471
+ Tip.warning(imageConfig.overSizeTip)
472
+ return
473
+ }
474
+ } else if (file.size > 512 * 1024) {
441
475
  Tip.warning(i18next.t('图片大小不能超过500Kb'))
442
476
  return
443
477
  }
@@ -463,7 +497,21 @@ class ImageUploader extends React.Component {
463
497
  .post()
464
498
  .then(json => {
465
499
  const imgURL = `${url.imgUrl}/${json.data.img_path_id}`
466
- this.props.onSuccess(imgURL)
500
+
501
+ // 增强模式下加载原图尺寸,记录原始比例供锁比例使用
502
+ if (imageConfig) {
503
+ const img = document.createElement('img')
504
+ img.onload = () => {
505
+ this.props.onSuccess(imgURL, img.naturalWidth / img.naturalHeight)
506
+ }
507
+ img.onerror = () => {
508
+ // 拿不到尺寸时降级:只插入不锁比例
509
+ this.props.onSuccess(imgURL)
510
+ }
511
+ img.src = imgURL
512
+ } else {
513
+ this.props.onSuccess(imgURL)
514
+ }
467
515
  })
468
516
  }
469
517
 
@@ -473,16 +521,23 @@ class ImageUploader extends React.Component {
473
521
  }
474
522
 
475
523
  render() {
524
+ const { imageConfig } = this.props
525
+
476
526
  return (
477
527
  <>
478
528
  <div onClick={this.handleClick} onDrop={this.handleUpload}>
479
529
  {this.props.text}
530
+ {imageConfig && imageConfig.acceptHint && (
531
+ <div className='gm-printer-contextmenu-hint'>
532
+ {imageConfig.acceptHint}
533
+ </div>
534
+ )}
480
535
  </div>
481
536
  <input
482
537
  style={{ display: 'none' }}
483
538
  type='file'
484
539
  ref={this.input}
485
- accept='image/*'
540
+ accept={(imageConfig && imageConfig.accept) || 'image/*'}
486
541
  onChange={this.handleUpload}
487
542
  />
488
543
  </>
@@ -492,7 +547,8 @@ class ImageUploader extends React.Component {
492
547
 
493
548
  ImageUploader.propTypes = {
494
549
  onSuccess: PropTypes.func.isRequired,
495
- text: PropTypes.string.isRequired
550
+ text: PropTypes.string.isRequired,
551
+ imageConfig: PropTypes.object
496
552
  }
497
553
 
498
554
  class InputWithUnit extends React.Component {
@@ -100,7 +100,7 @@ class EditorField extends React.Component {
100
100
 
101
101
  renderBlocks() {
102
102
  const { editStore, showNewDate } = this.props
103
- const { type, text, style, link } = editStore.computedSelectedInfo
103
+ const { type, text, style, link, ratio } = editStore.computedSelectedInfo
104
104
 
105
105
  return (
106
106
  <div>
@@ -149,6 +149,11 @@ class EditorField extends React.Component {
149
149
  <Size
150
150
  style={style}
151
151
  onChange={this.handleChangeBlock.bind(this, 'style')}
152
+ ratio={
153
+ editStore.imageConfig && editStore.imageConfig.resizable
154
+ ? ratio
155
+ : undefined
156
+ }
152
157
  />
153
158
  <Gap />
154
159
 
@@ -17,6 +17,10 @@ class EditorStore {
17
17
  @observable
18
18
  tableCustomStyle = 'default'
19
19
 
20
+ // 插入图片增强配置(电子签章),null 时保持旧行为(500Kb/image/*)
21
+ // { maxSize, maxSizeLabel, accept, acceptHint, resizable }
22
+ imageConfig = null
23
+
20
24
  @observable
21
25
  emptyTableData = []
22
26
 
@@ -556,7 +560,7 @@ class EditorStore {
556
560
  }
557
561
 
558
562
  @action
559
- addConfigBlock(name, type, pos = {}, link = '') {
563
+ addConfigBlock(name, type, pos = {}, link = '', ratio) {
560
564
  let blocks
561
565
  const arr = name.split('.')
562
566
 
@@ -600,6 +604,8 @@ class EditorStore {
600
604
  blocks.push({
601
605
  type: 'image',
602
606
  link: link,
607
+ // 电子签章:记录原图宽高比,锁比例用;旧数据无此字段则不锁
608
+ ratio: ratio,
603
609
  style: {
604
610
  position: 'absolute',
605
611
  left: pos.left || '0px',
@@ -1,13 +1,22 @@
1
1
  import React from 'react'
2
+ import PropTypes from 'prop-types'
2
3
  import { Provider } from 'mobx-react'
3
4
  import { getStyleWithDiff } from '../util'
4
5
 
5
6
  const withStore = store => WrapComponent =>
6
7
  class extends React.Component {
8
+ static propTypes = {
9
+ config: PropTypes.object,
10
+ mockData: PropTypes.object,
11
+ imageConfig: PropTypes.object
12
+ }
13
+
7
14
  constructor(props) {
8
15
  super(props)
9
16
  this.store = store
10
17
  this.store.init(props.config, props.mockData)
18
+ // 插入图片增强配置(电子签章):由业务侧 props 传入,不传为 null 保持旧行为
19
+ this.store.imageConfig = props.imageConfig || null
11
20
  }
12
21
 
13
22
  componentDidMount() {
@@ -166,6 +166,18 @@
166
166
  color: white;
167
167
  background: rgb(82, 146, 247);
168
168
  }
169
+
170
+ // 电子签章:插入图片菜单项下的格式提示小字
171
+ .gm-printer-contextmenu-hint {
172
+ font-size: 10px;
173
+ color: #f5222d;
174
+ line-height: 1.4;
175
+ padding: 0;
176
+ &:hover {
177
+ color: #f5222d;
178
+ background: transparent;
179
+ }
180
+ }
169
181
  }
170
182
  }
171
183
 
@@ -244,6 +256,37 @@
244
256
  outline: 1px solid rgb(82, 146, 247);
245
257
  z-index: 11;
246
258
  }
259
+
260
+ // 电子签章:图片四角黑色加粗拖拽手柄
261
+ .gm-printer-resize-handle {
262
+ position: absolute;
263
+ width: 10px;
264
+ height: 10px;
265
+ background: #000;
266
+ border: 2px solid #fff;
267
+ z-index: 12;
268
+
269
+ &.gm-printer-resize-lt {
270
+ left: -6px;
271
+ top: -6px;
272
+ cursor: nwse-resize;
273
+ }
274
+ &.gm-printer-resize-rt {
275
+ right: -6px;
276
+ top: -6px;
277
+ cursor: nesw-resize;
278
+ }
279
+ &.gm-printer-resize-lb {
280
+ left: -6px;
281
+ bottom: -6px;
282
+ cursor: nesw-resize;
283
+ }
284
+ &.gm-printer-resize-rb {
285
+ right: -6px;
286
+ bottom: -6px;
287
+ cursor: nwse-resize;
288
+ }
289
+ }
247
290
  }
248
291
 
249
292
  .gm-printer-table {
@@ -1,6 +1,19 @@
1
1
  import EditorStore from '../common/editor_store'
2
2
  import i18next from '../../locales'
3
3
 
4
+ // 配送单"电子签章"插入图片增强预设(1056076):2M/指定格式/锁比例/四角拖拽
5
+ // 由业务侧显式传入 <Editor imageConfig={imageConfigDelivery} /> 才生效,不传保持旧行为
6
+ export const imageConfigDelivery = {
7
+ maxSize: 2 * 1024 * 1024,
8
+ maxSizeLabel: '2M',
9
+ accept: 'image/jpeg,image/jpg,image/png',
10
+ acceptTypes: ['image/jpeg', 'image/jpg', 'image/png'],
11
+ acceptHint: i18next.t('支持插入2M以内的jpg、jpeg、png格式图片'),
12
+ overSizeTip: i18next.t('图片大小不能超过2M'),
13
+ wrongTypeTip: i18next.t('仅支持jpg、jpeg、png格式的图片'),
14
+ resizable: true
15
+ }
16
+
4
17
  class Store extends EditorStore {
5
18
  // 复写父类方法
6
19
  setTableDataKeyEffect(target, dataKey) {
package/src/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // ‼️优先初始化语言设置(必须先初始化语言)
2
2
  import '../locales'
3
3
  import Editor, { Editor2 } from './editor'
4
+ import { imageConfigDelivery } from './editor/store'
4
5
 
5
6
  import EditorPurchase from './editor_purchase'
6
7
  import EditorExaminingReport from './examining_report_editor'
@@ -30,6 +31,7 @@ export { setLocale } from '../locales'
30
31
  export {
31
32
  Editor,
32
33
  Editor2,
34
+ imageConfigDelivery,
33
35
  EditorStockIn,
34
36
  EditorStockOut,
35
37
  EditorPurchase,
@@ -8,7 +8,7 @@ import BarCode from './barcode'
8
8
  import QrCode from './qrcode'
9
9
  import Tag from './tag'
10
10
 
11
- @inject('printerStore')
11
+ @inject('printerStore', 'editStore')
12
12
  @observer
13
13
  class Block extends React.Component {
14
14
  constructor(props) {
@@ -16,8 +16,10 @@ class Block extends React.Component {
16
16
  this.state = {
17
17
  clientX: null,
18
18
  clientY: null,
19
- isEdit: false
19
+ isEdit: false,
20
+ isResizing: false
20
21
  }
22
+ this.resizeState = null
21
23
  }
22
24
 
23
25
  componentDidMount() {
@@ -32,6 +34,7 @@ class Block extends React.Component {
32
34
  'gm-printer-block-edit',
33
35
  this.handleBlockEdit
34
36
  )
37
+ this.teardownResize()
35
38
  }
36
39
 
37
40
  handleBlockEdit = e => {
@@ -112,6 +115,116 @@ class Block extends React.Component {
112
115
  })
113
116
  }
114
117
 
118
+ // 电子签章:图片四角等比例拖拽缩放
119
+ handleResizeStart = (direction, e) => {
120
+ // 阻止触发块的选中/拖动
121
+ e.stopPropagation()
122
+ e.preventDefault()
123
+
124
+ const {
125
+ config: { style, ratio }
126
+ } = this.props
127
+
128
+ const initW = parseFloat(style.width) || 0
129
+ const initH = parseFloat(style.height) || 0
130
+ // 旧模板无 ratio 时按当前显示宽高锁定
131
+ this.resizeState = {
132
+ direction,
133
+ startX: e.clientX,
134
+ startY: e.clientY,
135
+ initW,
136
+ initH,
137
+ initL: parseFloat(style.left) || 0,
138
+ initT: parseFloat(style.top) || 0,
139
+ // ratio = 原始宽/高
140
+ ratio: ratio || (initH > 0 ? initW / initH : 1),
141
+ baseStyle: style
142
+ }
143
+
144
+ this.setState({
145
+ isResizing: true
146
+ })
147
+
148
+ window.addEventListener('mousemove', this.handleResizeMove)
149
+ window.addEventListener('mouseup', this.handleResizeEnd)
150
+ }
151
+
152
+ handleResizeMove = e => {
153
+ if (!this.resizeState) return
154
+
155
+ // rAF 节流,避免高频 mousemove 打爆渲染
156
+ if (this.resizePending) return
157
+ this.resizePending = e
158
+ window.requestAnimationFrame(() => {
159
+ const evt = this.resizePending
160
+ this.resizePending = null
161
+ if (!evt || !this.resizeState) return
162
+ this.doResize(evt)
163
+ })
164
+ }
165
+
166
+ doResize = e => {
167
+ const {
168
+ direction,
169
+ startX,
170
+ initW,
171
+ initH,
172
+ initL,
173
+ initT,
174
+ ratio,
175
+ baseStyle
176
+ } = this.resizeState
177
+ const dx = e.clientX - startX
178
+
179
+ // 右侧角向右放大,左侧角向左放大
180
+ let width =
181
+ direction === 'rb' || direction === 'rt' ? initW + dx : initW - dx
182
+ // 最小尺寸兜底,防止翻转
183
+ width = Math.max(width, 10)
184
+ const height = Math.round(width / ratio)
185
+ width = Math.round(width)
186
+
187
+ // 锚定对角:左向角拖拽时右/下边不动,上向角拖拽时下边不动
188
+ let left = initL
189
+ let top = initT
190
+ if (direction === 'lb' || direction === 'lt') {
191
+ left = initL + initW - width
192
+ }
193
+ if (direction === 'rt' || direction === 'lt') {
194
+ top = initT + initH - height
195
+ }
196
+
197
+ dispatchMsg('gm-printer-block-style-set', {
198
+ style: {
199
+ ...baseStyle,
200
+ width: width + 'px',
201
+ height: height + 'px',
202
+ left: left + 'px',
203
+ top: top + 'px'
204
+ }
205
+ })
206
+ }
207
+
208
+ handleResizeEnd = () => {
209
+ // 先 flush 掉节流里排队中的最后一帧,避免松手回退
210
+ if (this.resizePending) {
211
+ const evt = this.resizePending
212
+ this.resizePending = null
213
+ this.doResize(evt)
214
+ }
215
+ this.teardownResize()
216
+ this.setState({
217
+ isResizing: false
218
+ })
219
+ }
220
+
221
+ teardownResize = () => {
222
+ window.removeEventListener('mousemove', this.handleResizeMove)
223
+ window.removeEventListener('mouseup', this.handleResizeEnd)
224
+ this.resizeState = null
225
+ this.resizePending = null
226
+ }
227
+
115
228
  render() {
116
229
  let {
117
230
  name,
@@ -119,6 +232,7 @@ class Block extends React.Component {
119
232
  pageIndex,
120
233
  className,
121
234
  printerStore,
235
+ editStore,
122
236
  ...rest
123
237
  } = this.props
124
238
  const { isEdit } = this.state
@@ -186,6 +300,14 @@ class Block extends React.Component {
186
300
  }
187
301
 
188
302
  const active = name === printerStore.selected
303
+ const { isResizing } = this.state
304
+ const showResizeHandles = !!(
305
+ active &&
306
+ type === 'image' &&
307
+ editStore &&
308
+ editStore.imageConfig &&
309
+ editStore.imageConfig.resizable
310
+ )
189
311
 
190
312
  return (
191
313
  <div
@@ -193,7 +315,7 @@ class Block extends React.Component {
193
315
  className={classNames('gm-printer-block', className, {
194
316
  active
195
317
  })}
196
- draggable
318
+ draggable={!isResizing}
197
319
  onDragStart={this.handleDragStart}
198
320
  onDragEnd={this.handleDragEnd}
199
321
  onClick={this.handleClick}
@@ -221,6 +343,26 @@ class Block extends React.Component {
221
343
  />
222
344
  )}
223
345
  {content}
346
+ {showResizeHandles && (
347
+ <>
348
+ <div
349
+ className='gm-printer-resize-handle gm-printer-resize-lt'
350
+ onMouseDown={this.handleResizeStart.bind(this, 'lt')}
351
+ />
352
+ <div
353
+ className='gm-printer-resize-handle gm-printer-resize-rt'
354
+ onMouseDown={this.handleResizeStart.bind(this, 'rt')}
355
+ />
356
+ <div
357
+ className='gm-printer-resize-handle gm-printer-resize-lb'
358
+ onMouseDown={this.handleResizeStart.bind(this, 'lb')}
359
+ />
360
+ <div
361
+ className='gm-printer-resize-handle gm-printer-resize-rb'
362
+ onMouseDown={this.handleResizeStart.bind(this, 'rb')}
363
+ />
364
+ </>
365
+ )}
224
366
  </div>
225
367
  )
226
368
  }
@@ -231,7 +373,8 @@ Block.propTypes = {
231
373
  config: PropTypes.object.isRequired,
232
374
  pageIndex: PropTypes.number.isRequired,
233
375
  className: PropTypes.string,
234
- printerStore: PropTypes.object
376
+ printerStore: PropTypes.object,
377
+ editStore: PropTypes.object
235
378
  }
236
379
 
237
380
  export default Block