@epxing/designer 5.3.0-beta.2 → 5.3.0-beta.4

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 (33) hide show
  1. package/API.md +160 -160
  2. package/README.md +46 -46
  3. package/dist/src/page-designer/PageDesigner.js +11 -0
  4. package/dist/src/page-designer/designer.js +21 -0
  5. package/dist/src/page-designer/previews/add-form/Preview.js +1 -1
  6. package/dist/src/page-designer/previews/add-form/Preview.vue.js +19 -8
  7. package/dist/src/page-designer/setting-panel/Setting.js +46 -10
  8. package/dist/src/visual/config-page/ComponentLibraryDialog.js +8 -2
  9. package/dist/src/visual/config-page/DashboardMobile.js +1 -1
  10. package/dist/style.css +116 -112
  11. package/package.json +8 -8
  12. package/src/index.js +27 -27
  13. package/src/page-designer/PageDesigner.vue +11 -0
  14. package/src/page-designer/designer.js +1322 -1299
  15. package/src/page-designer/previews/add-form/Preview.vue +43 -44
  16. package/src/page-designer/setting-panel/Setting.vue +24 -2
  17. package/src/page-designer/widget-preview/Mixin.js +285 -285
  18. package/src/page-designer/widget-preview/Preview.vue +322 -322
  19. package/src/page-designer/widget-preview/WidgetWrapper.vue +197 -197
  20. package/src/page-designer/widget-preview/directive.js +258 -258
  21. package/src/visual/CategoryList.vue +563 -563
  22. package/src/visual/ComponentList.vue +280 -280
  23. package/src/visual/CreatePage.vue +389 -389
  24. package/src/visual/EntityCardList.vue +449 -449
  25. package/src/visual/EntityList.vue +838 -838
  26. package/src/visual/config-page/ComponentLibraryDialog.vue +7 -1
  27. package/src/visual/config-page/DashboardMobile.vue +934 -934
  28. package/src/visual/widgets/ProcessFormItemVisual.vue +58 -58
  29. package/types/index.d.ts +22 -22
  30. package/types/page-designer.d.ts +3 -3
  31. package/types/visual-component.d.ts +1 -1
  32. package/types/visual-entity-list.d.ts +1 -1
  33. package/types/visual-entity-sub-list.d.ts +1 -1
@@ -1,322 +1,322 @@
1
- <template>
2
- <div :class="['epx-page-designer-widget-preview', 'css_' + designer.page.pageId]">
3
- <div
4
- ref="rootDropZone"
5
- class="epx-page-designer-widget-preview__drop-zone"
6
- @dragenter="onRootDragEnter"
7
- @dragover.prevent="onRootDragOver"
8
- @dragleave="onRootDragLeave"
9
- @drop.prevent="onRootDrop"
10
- >
11
- <div class="epx-page-designer-widget-preview__draggable epx-page-designer-widget-preview__draggable-list el-row">
12
- <template v-for="widget in designer.widgetList" :key="widget.id">
13
- <!-- 模板 -->
14
- <template-preview
15
- v-if="widget.type === 'template'"
16
-
17
- :widget="widget"
18
- :designer="designer"
19
- :parent-widget="null"
20
- :pageRelationList="pageRelationList"
21
- ></template-preview>
22
- <!-- 普通组件 -->
23
- <component
24
- v-else
25
- :key="widget.id"
26
- :is="getWidgetName(widget)"
27
- :widget="widget"
28
- :designer="designer"
29
- :parent-widget="null"
30
- :pageRelationList="pageRelationList"
31
- v-widget-designer="{ widget, designer, parentWidget: null, templateInfo: null }"
32
- ></component>
33
- </template>
34
- <div class="epx-page-designer-widget-preview__no-widget" v-if="designer.widgetList.length===0">拖拽组件到这里</div>
35
- </div>
36
- </div>
37
- </div>
38
- </template>
39
-
40
- <script>
41
- import util from '@epxing/core/src/runtime-utils/util'
42
- import TemplatePreview from './Template'
43
- import widgetDesignerDirective from './directive'
44
- import { resolvePreviewName } from './resolvePreviewName'
45
- import { createDropCache, clearDropCache, insertIndex, insertLineRect } from './dropPosition'
46
-
47
- function appendCss (id, css) {
48
- const formatCss = css.replace(/:current/g, '.css_' + id).replace(/url\s*\(([\w+-/.\s]+)\)/g, (str, $1) => {
49
- return `url(${util.getFileUrl($1)})`
50
- })
51
- const element = document.getElementById('style_' + id)
52
- if (element) {
53
- element.textContent = formatCss
54
- } else {
55
- const style = document.createElement('style')
56
- style.id = 'style_' + id
57
- style.textContent = formatCss
58
-
59
- style.setAttribute('type', 'text/css')
60
- document.head.appendChild(style)
61
- }
62
- }
63
- function removeCss (id) {
64
- const element = document.getElementById('style_' + id)
65
- if (element) document.head.removeChild(element)
66
- }
67
- export default {
68
- name: 'epx-page-designer-widget-preview',
69
-
70
- // T33:原为 module-level `Vue.directive('widget-designer', …)`(Vue3 无全局 Vue.directive)。
71
- // 改成**局部注册** —— 最干净:不依赖 app 单例,也不会有「指令重复注册」的 dev 告警。
72
- directives: { 'widget-designer': widgetDesignerDirective },
73
-
74
- data () {
75
- return {
76
- }
77
- },
78
- components: {
79
- TemplatePreview
80
- },
81
- props: {
82
- designer: Object,
83
- pageRelationList: Array
84
- },
85
- // emits: ['widget-click', 'widget-hover'],
86
- computed: {
87
- isContainer () {
88
- return v => {
89
- const widgetInfo = this.designer.getWidgetByType(v.code) || {}
90
- return widgetInfo.CONTAINER === '1'
91
- }
92
- },
93
- widgetInfo () {
94
- return v => {
95
- return this.designer.getWidgetByType(v.code) || {}
96
- }
97
- },
98
- // 预览组件名解析统一走 resolvePreviewName(命中项有缓存)
99
- getWidgetName () {
100
- return widget => resolvePreviewName(this.designer, widget)
101
- }
102
- },
103
- watch: {
104
- 'designer.pageConfig.css' (v) {
105
- appendCss(this.designer.page.pageId, v)
106
- }
107
- },
108
- methods: {
109
- // 根画布拖拽进入:重新测量一次根列表的 children,之后的 dragover 复用缓存
110
- onRootDragEnter (e) {
111
- if (this._rootDragLeaveTimer) {
112
- clearTimeout(this._rootDragLeaveTimer)
113
- this._rootDragLeaveTimer = null
114
- }
115
- if (!this.isDraggingFromLibrary(e)) return
116
- if (!this._dropCache) this._dropCache = createDropCache()
117
- clearDropCache(this._dropCache)
118
- this.designer.setDragOverTarget({ type: 'root', widgetId: null })
119
- this.designer.setDragOverTargetElement(this.$refs.rootDropZone)
120
- // 同步到大纲树:设置根级拖拽目标
121
- this.designer.setPreviewDragTarget({ widgetId: null, position: 'root' })
122
- },
123
- // 根画布拖拽悬停:只记坐标 + 允许放置;插入位置的计算与状态更新合并到下一帧
124
- onRootDragOver (e) {
125
- if (!this.isDraggingFromLibrary(e)) return
126
- e.preventDefault()
127
- // 拖画布已有组件用 move,组件库 / 模板库用 copy(不能在 dragover 里 getData,读拖拽状态即可)
128
- e.dataTransfer.dropEffect = this.designer.dragState.dragSource === 'preview' ? 'move' : 'copy'
129
- this._dragClientX = e.clientX
130
- this._dragClientY = e.clientY
131
- if (this._dragFrame) return
132
- this._dragFrame = requestAnimationFrame(() => {
133
- this._dragFrame = null
134
- if (!this.designer.dragState.isDragging) return
135
- this.designer.updateDragGhostPosition(this._dragClientX, this._dragClientY)
136
- const listEl = this.$el.querySelector('.epx-page-designer-widget-preview__draggable')
137
- if (!this._dropCache) this._dropCache = createDropCache()
138
- const lineRect = insertLineRect(this._dropCache, listEl, this._dragClientY)
139
- if (lineRect) this.designer.setDragInsertLine(lineRect)
140
- // 同步到大纲树:更新插入位置
141
- this.designer.setPreviewDragTarget({ widgetId: null, index: insertIndex(this._dropCache, listEl, this._dragClientY), position: 'root' })
142
- })
143
- },
144
- onRootDragLeave (e) {
145
- // 使用延迟检查,避免在子元素之间移动时误判
146
- if (this._rootDragLeaveTimer) {
147
- clearTimeout(this._rootDragLeaveTimer)
148
- }
149
-
150
- this._rootDragLeaveTimer = setTimeout(() => {
151
- // 检查 relatedTarget 是否仍在根元素内
152
- if (!this.$refs.rootDropZone || !this.$refs.rootDropZone.contains(e.relatedTarget)) {
153
- this.designer.clearDragOverTarget()
154
- this.designer.clearDragInsertLine()
155
- this.designer.clearPreviewDragTarget()
156
- if (this._dropCache) clearDropCache(this._dropCache)
157
- }
158
- this._rootDragLeaveTimer = null
159
- }, 50)
160
- },
161
- isDraggingFromLibrary (e) {
162
- return e.dataTransfer && e.dataTransfer.types && e.dataTransfer.types.includes('text/plain')
163
- },
164
- onRootDrop (e) {
165
- e.preventDefault()
166
-
167
- // 清除可能存在的离开定时器
168
- if (this._rootDragLeaveTimer) {
169
- clearTimeout(this._rootDragLeaveTimer)
170
- this._rootDragLeaveTimer = null
171
- }
172
-
173
- this.designer.clearDragOverTarget()
174
- this.designer.clearDragInsertLine()
175
- this.designer.clearPreviewDragTarget()
176
- const listEl = this.$el.querySelector('.epx-page-designer-widget-preview__draggable')
177
- if (!this._dropCache) this._dropCache = createDropCache()
178
- const index = insertIndex(this._dropCache, listEl, e.clientY)
179
- clearDropCache(this._dropCache)
180
-
181
- // 使用 designer 的统一拖拽处理方法;不在这里调用 drag-end,让 dragend 事件自然触发
182
- this.designer.handleDrop({ dataTransfer: e.dataTransfer, target: { type: 'root', widgetId: null, index } })
183
- },
184
-
185
- splitTemplate () {
186
- const { CONTENT } = this.widgetInfo
187
- if (CONTENT) {
188
- const config = JSON.parse(CONTENT)
189
- const { id } = this.designer.selectedWidget
190
- const { items, itemConfigs, JS: templateJs } = config
191
- const formatConfig = (arr) => {
192
- arr.forEach(compItem => {
193
- const oldId = compItem.id
194
- const newId = compItem.contentType + '_' + this.$util.genId()
195
- if (itemConfigs[oldId]) {
196
- itemConfigs[newId] = itemConfigs[oldId]
197
- delete itemConfigs[oldId]
198
- }
199
- compItem.id = newId
200
- if (compItem.items) {
201
- formatConfig(compItem.items)
202
- }
203
- })
204
- }
205
- formatConfig(items)
206
- const findWidgetPos = (arr, parent) => {
207
- for (let i = 0; i < arr.length; i++) {
208
- const item = arr[i]
209
- if (item.id === id) {
210
- return { parent: parent, index: i }
211
- } else if (item.items) {
212
- const child = findWidgetPos(item.items, item)
213
- if (child) return child
214
- }
215
- }
216
- }
217
- const widgetPos = findWidgetPos(this.designer.widgetList, null)
218
- if (widgetPos) {
219
- const { parent, index } = widgetPos
220
- if (parent) {
221
- parent.items.splice(index, 1, ...items)
222
- } else {
223
- this.designer.widgetList.splice(index, 1, ...items)
224
- }
225
- this.designer.mergeWidgetConfig(itemConfigs)
226
- delete this.designer.widgetConfig[id]
227
- if (templateJs) {
228
- let { JS = '' } = this.designer.pageConfig
229
- const result = JS.match(/export\sfunction\s(\w+)/g)
230
- const events = []
231
- if (result) {
232
- result.forEach(item => {
233
- events.push(item.replace(/export\sfunction\s/, ''))
234
- })
235
- }
236
- const templateJsResult = templateJs.split(/export\s+function\s+/)
237
- templateJsResult.forEach(item => {
238
- const funtionStr = item.replace(/\/\*(\n|.)+?\*\/[\n\s]+$/, '')
239
- if (funtionStr.replace(/[\n\s]+/g, '').length > 0) {
240
- const funtionName = funtionStr.split(/\s+\(/)[0]
241
- if (![...new Set(events)].includes(funtionName)) {
242
- JS += 'export function ' + funtionStr.replace(/^\w+/, funtionName)
243
- }
244
- }
245
- })
246
- this.designer.updatePageConfig({ JS })
247
- }
248
- this.designer.setSelected(items[0])
249
- }
250
- }
251
- },
252
-
253
- onDragUpdate () {
254
-
255
- },
256
- checkMove () {
257
-
258
- },
259
- handleWidgetClick (data) {
260
- this.$emit('widget-click', data)
261
- },
262
- handleWidgetHover (widgetId) {
263
- this.$emit('widget-hover', widgetId)
264
- }
265
- },
266
- created () {
267
- const { css } = this.designer.pageConfig
268
- if (css) {
269
- appendCss(this.designer.page.pageId, css)
270
- }
271
- },
272
- unmounted () {
273
- removeCss(this.designer.page.pageId)
274
-
275
- // 清除定时器
276
- if (this._rootDragLeaveTimer) {
277
- clearTimeout(this._rootDragLeaveTimer)
278
- this._rootDragLeaveTimer = null
279
- }
280
- if (this._dragFrame) {
281
- cancelAnimationFrame(this._dragFrame)
282
- this._dragFrame = null
283
- }
284
- }
285
- }
286
- </script>
287
-
288
- <style lang="scss">
289
- @include b(page-designer-widget-preview) {
290
- width: 100%;
291
- height: 100%;
292
- overflow: auto;
293
- @include e(draggable) {
294
- width: 100%;
295
- // height: 100%;
296
- min-height: 60px;
297
- position: relative;
298
- }
299
- @include e(draggable-list) {
300
- overflow: auto;
301
- }
302
- @include e(list) {
303
- min-height: 100%;
304
- }
305
- @include e(no-widget) {
306
- height: 100%;
307
- padding: 16px 0;
308
- box-sizing: border-box;
309
- display: flex;
310
- align-items: center;
311
- justify-content: center;
312
- text-align: center;
313
- color: #999999;
314
- background-color: #f0f0f0;
315
- border: 1px dotted #a7b1bd;
316
- pointer-events: none;
317
- }
318
- }
319
-
320
- // 悬停样式已由悬浮窗组件处理,这里不再需要
321
-
322
- </style>
1
+ <template>
2
+ <div :class="['epx-page-designer-widget-preview', 'css_' + designer.page.pageId]">
3
+ <div
4
+ ref="rootDropZone"
5
+ class="epx-page-designer-widget-preview__drop-zone"
6
+ @dragenter="onRootDragEnter"
7
+ @dragover.prevent="onRootDragOver"
8
+ @dragleave="onRootDragLeave"
9
+ @drop.prevent="onRootDrop"
10
+ >
11
+ <div class="epx-page-designer-widget-preview__draggable epx-page-designer-widget-preview__draggable-list el-row">
12
+ <template v-for="widget in designer.widgetList" :key="widget.id">
13
+ <!-- 模板 -->
14
+ <template-preview
15
+ v-if="widget.type === 'template'"
16
+
17
+ :widget="widget"
18
+ :designer="designer"
19
+ :parent-widget="null"
20
+ :pageRelationList="pageRelationList"
21
+ ></template-preview>
22
+ <!-- 普通组件 -->
23
+ <component
24
+ v-else
25
+ :key="widget.id"
26
+ :is="getWidgetName(widget)"
27
+ :widget="widget"
28
+ :designer="designer"
29
+ :parent-widget="null"
30
+ :pageRelationList="pageRelationList"
31
+ v-widget-designer="{ widget, designer, parentWidget: null, templateInfo: null }"
32
+ ></component>
33
+ </template>
34
+ <div class="epx-page-designer-widget-preview__no-widget" v-if="designer.widgetList.length===0">拖拽组件到这里</div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script>
41
+ import util from '@epxing/core/src/runtime-utils/util'
42
+ import TemplatePreview from './Template'
43
+ import widgetDesignerDirective from './directive'
44
+ import { resolvePreviewName } from './resolvePreviewName'
45
+ import { createDropCache, clearDropCache, insertIndex, insertLineRect } from './dropPosition'
46
+
47
+ function appendCss (id, css) {
48
+ const formatCss = css.replace(/:current/g, '.css_' + id).replace(/url\s*\(([\w+-/.\s]+)\)/g, (str, $1) => {
49
+ return `url(${util.getFileUrl($1)})`
50
+ })
51
+ const element = document.getElementById('style_' + id)
52
+ if (element) {
53
+ element.textContent = formatCss
54
+ } else {
55
+ const style = document.createElement('style')
56
+ style.id = 'style_' + id
57
+ style.textContent = formatCss
58
+
59
+ style.setAttribute('type', 'text/css')
60
+ document.head.appendChild(style)
61
+ }
62
+ }
63
+ function removeCss (id) {
64
+ const element = document.getElementById('style_' + id)
65
+ if (element) document.head.removeChild(element)
66
+ }
67
+ export default {
68
+ name: 'epx-page-designer-widget-preview',
69
+
70
+ // T33:原为 module-level `Vue.directive('widget-designer', …)`(Vue3 无全局 Vue.directive)。
71
+ // 改成**局部注册** —— 最干净:不依赖 app 单例,也不会有「指令重复注册」的 dev 告警。
72
+ directives: { 'widget-designer': widgetDesignerDirective },
73
+
74
+ data () {
75
+ return {
76
+ }
77
+ },
78
+ components: {
79
+ TemplatePreview
80
+ },
81
+ props: {
82
+ designer: Object,
83
+ pageRelationList: Array
84
+ },
85
+ // emits: ['widget-click', 'widget-hover'],
86
+ computed: {
87
+ isContainer () {
88
+ return v => {
89
+ const widgetInfo = this.designer.getWidgetByType(v.code) || {}
90
+ return widgetInfo.CONTAINER === '1'
91
+ }
92
+ },
93
+ widgetInfo () {
94
+ return v => {
95
+ return this.designer.getWidgetByType(v.code) || {}
96
+ }
97
+ },
98
+ // 预览组件名解析统一走 resolvePreviewName(命中项有缓存)
99
+ getWidgetName () {
100
+ return widget => resolvePreviewName(this.designer, widget)
101
+ }
102
+ },
103
+ watch: {
104
+ 'designer.pageConfig.css' (v) {
105
+ appendCss(this.designer.page.pageId, v)
106
+ }
107
+ },
108
+ methods: {
109
+ // 根画布拖拽进入:重新测量一次根列表的 children,之后的 dragover 复用缓存
110
+ onRootDragEnter (e) {
111
+ if (this._rootDragLeaveTimer) {
112
+ clearTimeout(this._rootDragLeaveTimer)
113
+ this._rootDragLeaveTimer = null
114
+ }
115
+ if (!this.isDraggingFromLibrary(e)) return
116
+ if (!this._dropCache) this._dropCache = createDropCache()
117
+ clearDropCache(this._dropCache)
118
+ this.designer.setDragOverTarget({ type: 'root', widgetId: null })
119
+ this.designer.setDragOverTargetElement(this.$refs.rootDropZone)
120
+ // 同步到大纲树:设置根级拖拽目标
121
+ this.designer.setPreviewDragTarget({ widgetId: null, position: 'root' })
122
+ },
123
+ // 根画布拖拽悬停:只记坐标 + 允许放置;插入位置的计算与状态更新合并到下一帧
124
+ onRootDragOver (e) {
125
+ if (!this.isDraggingFromLibrary(e)) return
126
+ e.preventDefault()
127
+ // 拖画布已有组件用 move,组件库 / 模板库用 copy(不能在 dragover 里 getData,读拖拽状态即可)
128
+ e.dataTransfer.dropEffect = this.designer.dragState.dragSource === 'preview' ? 'move' : 'copy'
129
+ this._dragClientX = e.clientX
130
+ this._dragClientY = e.clientY
131
+ if (this._dragFrame) return
132
+ this._dragFrame = requestAnimationFrame(() => {
133
+ this._dragFrame = null
134
+ if (!this.designer.dragState.isDragging) return
135
+ this.designer.updateDragGhostPosition(this._dragClientX, this._dragClientY)
136
+ const listEl = this.$el.querySelector('.epx-page-designer-widget-preview__draggable')
137
+ if (!this._dropCache) this._dropCache = createDropCache()
138
+ const lineRect = insertLineRect(this._dropCache, listEl, this._dragClientY)
139
+ if (lineRect) this.designer.setDragInsertLine(lineRect)
140
+ // 同步到大纲树:更新插入位置
141
+ this.designer.setPreviewDragTarget({ widgetId: null, index: insertIndex(this._dropCache, listEl, this._dragClientY), position: 'root' })
142
+ })
143
+ },
144
+ onRootDragLeave (e) {
145
+ // 使用延迟检查,避免在子元素之间移动时误判
146
+ if (this._rootDragLeaveTimer) {
147
+ clearTimeout(this._rootDragLeaveTimer)
148
+ }
149
+
150
+ this._rootDragLeaveTimer = setTimeout(() => {
151
+ // 检查 relatedTarget 是否仍在根元素内
152
+ if (!this.$refs.rootDropZone || !this.$refs.rootDropZone.contains(e.relatedTarget)) {
153
+ this.designer.clearDragOverTarget()
154
+ this.designer.clearDragInsertLine()
155
+ this.designer.clearPreviewDragTarget()
156
+ if (this._dropCache) clearDropCache(this._dropCache)
157
+ }
158
+ this._rootDragLeaveTimer = null
159
+ }, 50)
160
+ },
161
+ isDraggingFromLibrary (e) {
162
+ return e.dataTransfer && e.dataTransfer.types && e.dataTransfer.types.includes('text/plain')
163
+ },
164
+ onRootDrop (e) {
165
+ e.preventDefault()
166
+
167
+ // 清除可能存在的离开定时器
168
+ if (this._rootDragLeaveTimer) {
169
+ clearTimeout(this._rootDragLeaveTimer)
170
+ this._rootDragLeaveTimer = null
171
+ }
172
+
173
+ this.designer.clearDragOverTarget()
174
+ this.designer.clearDragInsertLine()
175
+ this.designer.clearPreviewDragTarget()
176
+ const listEl = this.$el.querySelector('.epx-page-designer-widget-preview__draggable')
177
+ if (!this._dropCache) this._dropCache = createDropCache()
178
+ const index = insertIndex(this._dropCache, listEl, e.clientY)
179
+ clearDropCache(this._dropCache)
180
+
181
+ // 使用 designer 的统一拖拽处理方法;不在这里调用 drag-end,让 dragend 事件自然触发
182
+ this.designer.handleDrop({ dataTransfer: e.dataTransfer, target: { type: 'root', widgetId: null, index } })
183
+ },
184
+
185
+ splitTemplate () {
186
+ const { CONTENT } = this.widgetInfo
187
+ if (CONTENT) {
188
+ const config = JSON.parse(CONTENT)
189
+ const { id } = this.designer.selectedWidget
190
+ const { items, itemConfigs, JS: templateJs } = config
191
+ const formatConfig = (arr) => {
192
+ arr.forEach(compItem => {
193
+ const oldId = compItem.id
194
+ const newId = compItem.contentType + '_' + this.$util.genId()
195
+ if (itemConfigs[oldId]) {
196
+ itemConfigs[newId] = itemConfigs[oldId]
197
+ delete itemConfigs[oldId]
198
+ }
199
+ compItem.id = newId
200
+ if (compItem.items) {
201
+ formatConfig(compItem.items)
202
+ }
203
+ })
204
+ }
205
+ formatConfig(items)
206
+ const findWidgetPos = (arr, parent) => {
207
+ for (let i = 0; i < arr.length; i++) {
208
+ const item = arr[i]
209
+ if (item.id === id) {
210
+ return { parent: parent, index: i }
211
+ } else if (item.items) {
212
+ const child = findWidgetPos(item.items, item)
213
+ if (child) return child
214
+ }
215
+ }
216
+ }
217
+ const widgetPos = findWidgetPos(this.designer.widgetList, null)
218
+ if (widgetPos) {
219
+ const { parent, index } = widgetPos
220
+ if (parent) {
221
+ parent.items.splice(index, 1, ...items)
222
+ } else {
223
+ this.designer.widgetList.splice(index, 1, ...items)
224
+ }
225
+ this.designer.mergeWidgetConfig(itemConfigs)
226
+ delete this.designer.widgetConfig[id]
227
+ if (templateJs) {
228
+ let { JS = '' } = this.designer.pageConfig
229
+ const result = JS.match(/export\sfunction\s(\w+)/g)
230
+ const events = []
231
+ if (result) {
232
+ result.forEach(item => {
233
+ events.push(item.replace(/export\sfunction\s/, ''))
234
+ })
235
+ }
236
+ const templateJsResult = templateJs.split(/export\s+function\s+/)
237
+ templateJsResult.forEach(item => {
238
+ const funtionStr = item.replace(/\/\*(\n|.)+?\*\/[\n\s]+$/, '')
239
+ if (funtionStr.replace(/[\n\s]+/g, '').length > 0) {
240
+ const funtionName = funtionStr.split(/\s+\(/)[0]
241
+ if (![...new Set(events)].includes(funtionName)) {
242
+ JS += 'export function ' + funtionStr.replace(/^\w+/, funtionName)
243
+ }
244
+ }
245
+ })
246
+ this.designer.updatePageConfig({ JS })
247
+ }
248
+ this.designer.setSelected(items[0])
249
+ }
250
+ }
251
+ },
252
+
253
+ onDragUpdate () {
254
+
255
+ },
256
+ checkMove () {
257
+
258
+ },
259
+ handleWidgetClick (data) {
260
+ this.$emit('widget-click', data)
261
+ },
262
+ handleWidgetHover (widgetId) {
263
+ this.$emit('widget-hover', widgetId)
264
+ }
265
+ },
266
+ created () {
267
+ const { css } = this.designer.pageConfig
268
+ if (css) {
269
+ appendCss(this.designer.page.pageId, css)
270
+ }
271
+ },
272
+ unmounted () {
273
+ removeCss(this.designer.page.pageId)
274
+
275
+ // 清除定时器
276
+ if (this._rootDragLeaveTimer) {
277
+ clearTimeout(this._rootDragLeaveTimer)
278
+ this._rootDragLeaveTimer = null
279
+ }
280
+ if (this._dragFrame) {
281
+ cancelAnimationFrame(this._dragFrame)
282
+ this._dragFrame = null
283
+ }
284
+ }
285
+ }
286
+ </script>
287
+
288
+ <style lang="scss">
289
+ @include b(page-designer-widget-preview) {
290
+ width: 100%;
291
+ height: 100%;
292
+ overflow: auto;
293
+ @include e(draggable) {
294
+ width: 100%;
295
+ // height: 100%;
296
+ min-height: 60px;
297
+ position: relative;
298
+ }
299
+ @include e(draggable-list) {
300
+ overflow: auto;
301
+ }
302
+ @include e(list) {
303
+ min-height: 100%;
304
+ }
305
+ @include e(no-widget) {
306
+ height: 100%;
307
+ padding: 16px 0;
308
+ box-sizing: border-box;
309
+ display: flex;
310
+ align-items: center;
311
+ justify-content: center;
312
+ text-align: center;
313
+ color: #999999;
314
+ background-color: #f0f0f0;
315
+ border: 1px dotted #a7b1bd;
316
+ pointer-events: none;
317
+ }
318
+ }
319
+
320
+ // 悬停样式已由悬浮窗组件处理,这里不再需要
321
+
322
+ </style>