wangrong
2026-08-30 4c949c0dc9bcae785c281c9d8125295f09810b15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import eventBus from '@/utils/eventBus'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { copyStoreWithOut } from '@/store/modules/data-visualization/copy'
import { composeStoreWithOut } from '@/store/modules/data-visualization/compose'
import { lockStoreWithOut } from '@/store/modules/data-visualization/lock'
import { storeToRefs } from 'pinia'
import { getCurInfo } from '@/store/modules/data-visualization/common'
import { isGroupCanvas, isTabCanvas } from '@/utils/canvasUtils'
import { groupStyleRevert } from '@/utils/style'
 
const dvMainStore = dvMainStoreWithOut()
const composeStore = composeStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const copyStore = copyStoreWithOut()
const lockStore = lockStoreWithOut()
const { curComponent, editMode } = storeToRefs(dvMainStore)
const { areaData } = storeToRefs(composeStore)
 
const ctrlKey = 17,
  shiftKey = 16, // shift
  commandKey = 91, // mac command
  leftKey = 37, // 向左
  upKey = 38, // 向上
  rightKey = 39, // 向右
  downKey = 40, // 向下
  vKey = 86, // 粘贴
  cKey = 67, // 复制
  xKey = 88, // 剪切
  yKey = 89, // 重做
  zKey = 90, // 撤销
  gKey = 71, // 组合
  bKey = 66, // 拆分
  lKey = 76, // 锁定
  uKey = 85, // 解锁
  sKey = 83, // 保存
  pKey = 80, // 预览
  dKey = 68, // 删除
  deleteKey = 46, // 删除
  macDeleteKey = 8, // 删除
  eKey = 69, // 清空画布
  spaceKey = 32 // 空格键
 
export const keycodes = [8, 37, 38, 39, 40, 66, 67, 68, 69, 71, 76, 80, 83, 85, 86, 88, 89, 90]
 
// 与组件状态无关的操作
const basemap = {
  [vKey]: paste,
  [yKey]: redo,
  [zKey]: undo,
  [sKey]: save,
  [pKey]: preview,
  [eKey]: clearCanvas
}
 
// 当处于大屏状态时 按上下左右键 可以移动位置
const positionMoveKey = {
  [leftKey]: move,
  [upKey]: move,
  [rightKey]: move,
  [downKey]: move
}
 
// 组件锁定状态下可以执行的操作
const lockMap = {
  ...basemap,
  [uKey]: unlock
}
 
// 组件未锁定状态下可以执行的操作
const unlockMap = {
  ...basemap,
  [cKey]: copy,
  [xKey]: cut,
  [gKey]: compose,
  [bKey]: decompose,
  [dKey]: deleteComponent,
  [deleteKey]: deleteComponent,
  [lKey]: lock
}
 
// 检查当前页面是否有弹框
const checkDialog = () => {
  let haveDialog = false
  document.querySelectorAll('.ed-overlay').forEach(element => {
    if (window.getComputedStyle(element).getPropertyValue('display') != 'none') {
      haveDialog = true
    }
  })
  document.querySelectorAll('.ed-popper').forEach(element => {
    if (
      !element.classList?.contains('template-popper-tips') &&
      window.getComputedStyle(element).getPropertyValue('display') != 'none'
    ) {
      haveDialog = true
    }
  })
  // 富文本单框
  if (document.querySelector('.tox-dialog-wrap')) {
    haveDialog = true
  }
 
  return haveDialog
}
 
let isCtrlOrCommandDown = false
let isShiftDown = false
// 全局监听按键操作并执行相应命令
export function listenGlobalKeyDown() {
  window.onkeydown = e => {
    if (editMode.value === 'preview' || checkDialog()) return
    const { keyCode } = e
    if (positionMoveKey[keyCode] && curComponent.value) {
      positionMoveKey[keyCode](keyCode)
      e.preventDefault()
      e.stopPropagation()
    } else if (keyCode === shiftKey) {
      isShiftDown = true
      composeStore.setIsShiftDownStatus(true)
      releaseKeyCheck('shift')
    } else if (keyCode === ctrlKey || keyCode === commandKey) {
      isCtrlOrCommandDown = true
      composeStore.setIsCtrlOrCmdDownStatus(true)
      releaseKeyCheck('ctrl')
    } else if (keyCode === spaceKey) {
      composeStore.setSpaceDownStatus(true)
      e.preventDefault()
      e.stopPropagation()
    } else if ((keyCode == deleteKey || keyCode == macDeleteKey) && curComponent.value) {
      deleteComponent()
    } else if (isCtrlOrCommandDown) {
      if (unlockMap[keyCode] && (!curComponent.value || !curComponent.value.isLock)) {
        e.preventDefault()
        unlockMap[keyCode]()
      } else if (lockMap[keyCode] && curComponent.value && curComponent.value.isLock) {
        e.preventDefault()
        lockMap[keyCode]()
      }
    }
  }
 
  window.onkeyup = e => {
    if (e.keyCode === ctrlKey || e.keyCode === commandKey) {
      isCtrlOrCommandDown = false
      composeStore.setIsCtrlOrCmdDownStatus(false)
    } else if (e.keyCode === shiftKey) {
      isShiftDown = true
      composeStore.setIsShiftDownStatus(false)
    } else if (e.keyCode === spaceKey) {
      composeStore.setSpaceDownStatus(false)
      e.preventDefault()
      e.stopPropagation()
    }
  }
 
  window.onmousedown = () => {
    dvMainStore.setInEditorStatus(false)
  }
}
 
export function releaseAttachKey() {
  isCtrlOrCommandDown = false
  composeStore.setIsCtrlOrCmdDownStatus(false)
  isShiftDown = false
  composeStore.setIsShiftDownStatus(false)
}
 
//当前不支持同时ctrl + shift操作
function releaseKeyCheck(keyType) {
  if (keyType === 'shift' && isCtrlOrCommandDown) {
    isCtrlOrCommandDown = false
    composeStore.setIsCtrlOrCmdDownStatus(false)
  } else if (keyType === 'ctrl' && isShiftDown) {
    isShiftDown = false
    composeStore.setIsShiftDownStatus(false)
  }
}
 
function copy() {
  copyStore.copy()
}
 
function paste() {
  copyStore.paste(false)
  snapshotStore.recordSnapshotCache('key-paste')
}
 
function move(keyCode) {
  if (curComponent.value) {
    const scale = dvMainStore.canvasStyleData.scale / 100
    if (keyCode === leftKey) {
      curComponent.value.style.left = curComponent.value.style.left - scale
      groupAreaAdaptor(-scale, 0)
    } else if (keyCode === rightKey) {
      curComponent.value.style.left = curComponent.value.style.left + scale
      groupAreaAdaptor(scale, 0)
    } else if (keyCode === upKey) {
      curComponent.value.style.top = curComponent.value.style.top - scale
      groupAreaAdaptor(0, -scale)
    } else if (keyCode === downKey) {
      curComponent.value.style.top = curComponent.value.style.top + scale
      groupAreaAdaptor(0, scale)
    }
    snapshotStore.recordSnapshotCache('key-move')
  }
}
 
function groupAreaAdaptor(leftOffset = 0, topOffset = 0) {
  const canvasId = curComponent.value.canvasId
  const parentNode = document.querySelector('#editor-' + canvasId)
 
  //如果当前画布是Group内部画布 则对应组件定位在resize时要还原到groupStyle中
  if (isGroupCanvas(canvasId) || isTabCanvas(canvasId)) {
    groupStyleRevert(curComponent.value, {
      width: parentNode.offsetWidth,
      height: parentNode.offsetHeight
    })
  } else if (curComponent.value.component === 'GroupArea' && areaData.value.components.length > 0) {
    areaData.value.components.forEach(component => {
      component.style.top = component.style.top + topOffset
      component.style.left = component.style.left + leftOffset
    })
  }
}
 
function cut() {
  copyStore.cut()
}
 
function redo() {
  snapshotStore.redo()
}
 
function undo() {
  snapshotStore.undo()
}
 
function compose() {
  if (areaData.value.components.length) {
    composeStore.compose()
    snapshotStore.recordSnapshotCache('key-compose')
  }
}
 
function decompose() {
  const curComponentLink = curComponent.value
  if (curComponentLink && !curComponentLink.isLock && curComponentLink.component == 'Group') {
    composeStore.decompose()
    snapshotStore.recordSnapshotCache('key-decompose')
  }
}
 
function save() {
  eventBus.emit('save')
}
 
function preview() {
  eventBus.emit('preview')
}
 
function deleteComponent() {
  if (curComponent.value && curComponent.value.component !== 'GroupArea') {
    const curInfo = getCurInfo()
    if (curInfo) {
      dvMainStore.deleteComponent(curInfo.index, curInfo.componentData)
    }
  } else if (areaData.value.components.length) {
    areaData.value.components.forEach(component => {
      dvMainStore.deleteComponentById(component.id)
    })
    eventBus.emit('hideArea-canvas-main')
  }
  snapshotStore.recordSnapshotCache('listenGlobalKeyDown')
}
 
function clearCanvas() {
  eventBus.emit('clearCanvas')
}
 
function lock() {
  lockStore.lock()
}
 
function unlock() {
  lockStore.unlock()
}