@feedmepos/mf-order-setting 0.0.90 → 0.0.91

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 (46) hide show
  1. package/dist/DisplaySystemView-n7Kqdw-h.js +6564 -0
  2. package/dist/{KioskDevicesView-WuOTJ9Fi.js → KioskDevicesView-Bz6seroM.js} +1 -1
  3. package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-DdHfATyN.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-I39sE8Pe.js} +3 -3
  4. package/dist/{KioskSettingView-Bsja2OqT.js → KioskSettingView-Cajjh4Zm.js} +3 -3
  5. package/dist/{KioskView-BH5qGTM_.js → KioskView-BPSbsMi5.js} +93 -89
  6. package/dist/{OrderSettingsView-D6V1ztiS.js → OrderSettingsView-jPxZ3JDM.js} +5 -5
  7. package/dist/{app-DsMk7W2h.js → app-DIhv5ssA.js} +266 -254
  8. package/dist/app.js +1 -1
  9. package/dist/frontend/mf-order/src/app.d.ts +18 -6
  10. package/dist/frontend/mf-order/src/main.d.ts +18 -6
  11. package/dist/frontend/mf-order/src/modules/display-system/interface.d.ts +6 -3
  12. package/dist/frontend/mf-order/src/modules/kiosk/bindDeviceError.d.ts +20 -0
  13. package/dist/frontend/mf-order/src/views/display-system/CanvasArea.vue.d.ts +48 -0
  14. package/dist/frontend/mf-order/src/views/display-system/DisplayLayoutCanvas.vue.d.ts +17 -14
  15. package/dist/frontend/mf-order/src/views/display-system/DisplayModulePickerDialog.vue.d.ts +2 -0
  16. package/dist/frontend/mf-order/tsconfig.app.tsbuildinfo +1 -1
  17. package/dist/{index-DGDiI0fr.js → index-Clp_YRJ2.js} +1 -1
  18. package/dist/{index-BUDM0Rqn.js → index-CmqNrkNl.js} +1 -1
  19. package/dist/{index-C2n1MV_1.js → index-vaSLX6r3.js} +2 -2
  20. package/dist/{order.dto-BRDWWgMV.js → order.dto-DV1qL3Q_.js} +21 -1
  21. package/dist/package/entity/alert/investigation.dto.d.ts +26 -0
  22. package/dist/package/entity/alert/lark-callback.dto.d.ts +19 -0
  23. package/dist/package/entity/alert/record-resolution.dto.d.ts +35 -0
  24. package/dist/package/entity/index.d.ts +1 -0
  25. package/dist/package/entity/kiosk/kiosk.do.d.ts +105 -0
  26. package/dist/package/entity/kiosk/kiosk.dto.d.ts +76 -0
  27. package/dist/style.css +1 -1
  28. package/package.json +3 -1
  29. package/src/locales/en-US.json +11 -4
  30. package/src/locales/zh-CN.json +9 -4
  31. package/src/modules/display-system/interface.spec.ts +90 -5
  32. package/src/modules/display-system/interface.ts +31 -21
  33. package/src/modules/kiosk/bindDeviceError.spec.ts +42 -0
  34. package/src/modules/kiosk/bindDeviceError.ts +40 -0
  35. package/src/views/display-system/CanvasArea.vue +355 -0
  36. package/src/views/display-system/DisplayLayoutCanvas.spec.ts +57 -0
  37. package/src/views/display-system/DisplayLayoutCanvas.vue +173 -298
  38. package/src/views/display-system/DisplayModulePickerDialog.spec.ts +71 -0
  39. package/src/views/display-system/DisplayModulePickerDialog.vue +107 -0
  40. package/src/views/display-system/DisplayTemplateEditor.spec.ts +151 -0
  41. package/src/views/display-system/DisplayTemplateEditor.vue +233 -193
  42. package/src/views/kiosk/KioskView.vue +2 -4
  43. package/vitest.config.ts +2 -0
  44. package/dist/DisplaySystemView-tosCa7Ej.js +0 -6485
  45. package/dist/frontend/mf-order/src/views/display-system/DisplayModulePalette.vue.d.ts +0 -13
  46. package/src/views/display-system/DisplayModulePalette.vue +0 -140
@@ -0,0 +1,355 @@
1
+ <script setup lang="ts">
2
+ import { useI18n } from '@feedmepos/mf-common'
3
+ import {
4
+ blockDefinition,
5
+ type DisplayZoneDraft,
6
+ type DisplaySplitDraft
7
+ } from '@/modules/display-system/interface'
8
+
9
+ interface EdgeAction {
10
+ direction: DisplaySplitDraft['direction']
11
+ kind: 'bootstrap' | 'split' | 'extend'
12
+ }
13
+ defineProps<{
14
+ zone: DisplayZoneDraft
15
+ areaNumber: number
16
+ percent: number
17
+ weight: number
18
+ removable: boolean
19
+ edgeActions: EdgeAction[]
20
+ selectedZoneId: string
21
+ selectedBlockId: string
22
+ scope: 'area' | 'module'
23
+ dragging: boolean
24
+ dropZoneId: string
25
+ }>()
26
+ const emit = defineEmits<{
27
+ (event: 'select-zone', zoneId: string): void
28
+ (event: 'select-block', payload: { zoneId: string; blockId: string }): void
29
+ (event: 'open-module-picker', zoneId: string): void
30
+ (event: 'remove-area', zoneId: string): void
31
+ (event: 'edge-click', action: EdgeAction): void
32
+ (event: 'block-dragstart', eventData: DragEvent): void
33
+ (event: 'block-dragend'): void
34
+ (event: 'dragover'): void
35
+ (event: 'dragleave'): void
36
+ (event: 'drop'): void
37
+ }>()
38
+ const { t } = useI18n()
39
+ function blockLabel(type: string): string {
40
+ const definition = blockDefinition(type)
41
+ return definition ? t(definition.editor.labelKey) : type
42
+ }
43
+ function blockIcon(type: string): string {
44
+ return blockDefinition(type)?.editor.icon ?? 'widgets'
45
+ }
46
+ function edgeClass(direction: DisplaySplitDraft['direction']): string {
47
+ return direction === 'ROW' ? 'canvas-edge-right' : 'canvas-edge-bottom'
48
+ }
49
+ </script>
50
+
51
+ <template>
52
+ <section
53
+ class="canvas-area"
54
+ :style="{ flexGrow: weight, flexBasis: '0' }"
55
+ @click="emit('select-zone', zone.id)"
56
+ @dragover.prevent="emit('dragover')"
57
+ @dragleave="emit('dragleave')"
58
+ @drop.prevent="emit('drop')"
59
+ >
60
+ <div
61
+ class="canvas-area-card"
62
+ :class="{
63
+ 'canvas-area-active': zone.id === selectedZoneId && scope === 'area',
64
+ 'canvas-area-context': zone.id === selectedZoneId && scope === 'module',
65
+ 'canvas-area-droppable': dragging,
66
+ 'canvas-area-drop-over': dropZoneId === zone.id
67
+ }"
68
+ >
69
+ <header class="canvas-area-head">
70
+ <span class="canvas-area-name">
71
+ {{ t('order.displaySystem.editor.ui.area', { index: areaNumber }) }}
72
+ </span>
73
+ <span class="canvas-area-share">{{ percent }}%</span>
74
+ <button
75
+ v-if="removable"
76
+ type="button"
77
+ class="canvas-area-remove"
78
+ :title="t('order.displaySystem.editor.ui.removeAreaTooltip')"
79
+ @click.stop="emit('remove-area', zone.id)"
80
+ >
81
+ <FmIcon name="close" size="sm" />
82
+ </button>
83
+ </header>
84
+
85
+ <div class="canvas-chips">
86
+ <div
87
+ v-if="zone.block"
88
+ class="canvas-chip"
89
+ :class="{
90
+ 'canvas-chip-active': zone.block.id === selectedBlockId && scope === 'module',
91
+ 'canvas-chip-context': zone.block.id === selectedBlockId && scope === 'area'
92
+ }"
93
+ tabindex="0"
94
+ draggable="true"
95
+ @click.stop="emit('select-block', { zoneId: zone.id, blockId: zone.block!.id })"
96
+ @dragstart="emit('block-dragstart', $event)"
97
+ @dragend="emit('block-dragend')"
98
+ >
99
+ <FmIcon name="open_with" size="sm" class="canvas-chip-grip" />
100
+ <FmIcon :name="blockIcon(zone.block.type)" size="sm" />
101
+ <span class="canvas-chip-label">{{ blockLabel(zone.block.type) }}</span>
102
+ <button
103
+ type="button"
104
+ class="canvas-chip-swap"
105
+ :title="t('order.displaySystem.editor.ui.changeModuleTooltip')"
106
+ @click.stop="emit('open-module-picker', zone.id)"
107
+ >
108
+ <FmIcon name="sync_alt" size="sm" />
109
+ </button>
110
+ </div>
111
+ <button
112
+ v-else
113
+ type="button"
114
+ class="canvas-area-empty"
115
+ @click.stop="emit('open-module-picker', zone.id)"
116
+ >
117
+ {{ t('order.displaySystem.editor.ui.emptyArea') }}
118
+ </button>
119
+ </div>
120
+ </div>
121
+
122
+ <!-- Each border offers whichever "+" the layout has room for: split
123
+ this area, or -- only on the container's last area -- extend it
124
+ with a new sibling. -->
125
+ <button
126
+ v-for="action in edgeActions"
127
+ :key="action.direction"
128
+ type="button"
129
+ class="canvas-edge"
130
+ :class="edgeClass(action.direction)"
131
+ :title="
132
+ action.kind === 'split'
133
+ ? t('order.displaySystem.editor.ui.splitAreaHint', {
134
+ direction: t(`order.displaySystem.editor.values.${action.direction.toLowerCase()}`)
135
+ })
136
+ : t('order.displaySystem.editor.ui.addArea')
137
+ "
138
+ @click.stop="emit('edge-click', action)"
139
+ >
140
+ <FmIcon name="add" size="sm" />
141
+ </button>
142
+ </section>
143
+ </template>
144
+
145
+ <style scoped>
146
+ /* The sizing box has no border/padding, so flex weights match the live preview. */
147
+ .canvas-area {
148
+ position: relative;
149
+ display: flex;
150
+ min-width: 0;
151
+ min-height: 0;
152
+ flex-direction: column;
153
+ }
154
+ .canvas-area-card {
155
+ display: flex;
156
+ flex: 1;
157
+ min-width: 0;
158
+ min-height: 0;
159
+ flex-direction: column;
160
+ gap: 8px;
161
+ overflow: visible;
162
+ border: 1.5px dashed rgb(255 255 255 / 55%);
163
+ border-radius: 10px;
164
+ padding: 6px;
165
+ background: rgb(17 24 39 / 32%);
166
+ text-align: left;
167
+ }
168
+ .canvas-area-card:hover {
169
+ background: rgb(17 24 39 / 42%);
170
+ }
171
+ .canvas-area-active {
172
+ border-style: solid;
173
+ border-color: #f97316;
174
+ background: rgb(249 115 22 / 30%);
175
+ box-shadow: 0 0 0 3px #f973161f;
176
+ }
177
+ .canvas-area-context {
178
+ border-style: solid;
179
+ border-color: #fed7aa;
180
+ background: rgb(253 186 116 / 20%);
181
+ }
182
+ .canvas-area-droppable {
183
+ border-color: #f97316;
184
+ background: rgb(249 115 22 / 36%);
185
+ }
186
+ .canvas-area-drop-over {
187
+ border-style: solid;
188
+ box-shadow: 0 0 0 3px #f9731633;
189
+ }
190
+ .canvas-area-head {
191
+ display: flex;
192
+ align-items: center;
193
+ gap: 8px;
194
+ }
195
+ .canvas-area-name,
196
+ .canvas-area-share {
197
+ color: #f9fafb;
198
+ text-shadow: 0 1px 3px rgb(0 0 0 / 70%);
199
+ font-weight: 700;
200
+ }
201
+ .canvas-area-name {
202
+ font-size: 10px;
203
+ letter-spacing: 0.06em;
204
+ text-transform: uppercase;
205
+ }
206
+ .canvas-area-share {
207
+ margin-left: auto;
208
+ font-size: 12px;
209
+ font-variant-numeric: tabular-nums;
210
+ }
211
+ .canvas-area-remove {
212
+ display: grid;
213
+ flex: 0 0 auto;
214
+ place-items: center;
215
+ border-radius: 999px;
216
+ padding: 2px;
217
+ background: rgb(17 24 39 / 55%);
218
+ color: #f9fafb;
219
+ opacity: 0;
220
+ transition: opacity 0.1s ease;
221
+ }
222
+ .canvas-area-remove:hover {
223
+ background: #fef2f2;
224
+ color: #dc2626;
225
+ }
226
+ /* Controls straddle the border without taking any of the area's layout space. */
227
+ .canvas-edge {
228
+ position: absolute;
229
+ display: grid;
230
+ place-items: center;
231
+ width: 20px;
232
+ height: 20px;
233
+ border-radius: 999px;
234
+ background: white;
235
+ box-shadow: 0 0 0 1.5px #d1d5db;
236
+ color: #9ca3af;
237
+ opacity: 0;
238
+ transition: opacity 0.1s ease;
239
+ z-index: 1;
240
+ }
241
+ .canvas-area:hover .canvas-edge,
242
+ .canvas-area:focus-within .canvas-edge,
243
+ .canvas-area:hover .canvas-area-remove,
244
+ .canvas-area:focus-within .canvas-area-remove {
245
+ opacity: 1;
246
+ }
247
+ .canvas-edge:hover {
248
+ box-shadow: 0 0 0 1.5px #f97316;
249
+ color: #f97316;
250
+ }
251
+ .canvas-edge-right {
252
+ top: 50%;
253
+ right: -10px;
254
+ transform: translateY(-50%);
255
+ }
256
+ .canvas-edge-bottom {
257
+ bottom: -10px;
258
+ left: 50%;
259
+ transform: translateX(-50%);
260
+ }
261
+ .canvas-chips {
262
+ display: flex;
263
+ min-height: 0;
264
+ flex: 1;
265
+ flex-direction: column;
266
+ }
267
+ .canvas-chip {
268
+ display: flex;
269
+ align-items: center;
270
+ align-self: flex-start;
271
+ max-width: 100%;
272
+ gap: 6px;
273
+ border: 1px solid #e5e7eb;
274
+ border-radius: 8px;
275
+ padding: 6px 8px;
276
+ background: rgb(255 255 255 / 92%);
277
+ color: #374151;
278
+ font-size: 12px;
279
+ text-align: left;
280
+ cursor: grab;
281
+ }
282
+ .canvas-chip:hover {
283
+ border-color: #fdba74;
284
+ }
285
+ .canvas-chip-active {
286
+ border-color: #f97316;
287
+ box-shadow:
288
+ inset 4px 0 0 #f97316,
289
+ 0 0 0 3px #f973161f;
290
+ font-weight: 600;
291
+ }
292
+ .canvas-chip-active .canvas-chip-grip {
293
+ color: #f97316;
294
+ }
295
+ .canvas-chip-context {
296
+ border-color: #fed7aa;
297
+ background: #fffdfa;
298
+ }
299
+ .canvas-chip:active {
300
+ cursor: grabbing;
301
+ }
302
+ .canvas-chip-grip {
303
+ flex: 0 0 auto;
304
+ color: #9ca3af;
305
+ }
306
+ .canvas-chip-label {
307
+ min-width: 0;
308
+ flex: 1;
309
+ overflow: hidden;
310
+ text-overflow: ellipsis;
311
+ white-space: nowrap;
312
+ }
313
+ .canvas-chip-swap {
314
+ display: grid;
315
+ flex: 0 0 auto;
316
+ place-items: center;
317
+ margin-left: 2px;
318
+ border-radius: 6px;
319
+ padding: 2px;
320
+ color: #9ca3af;
321
+ opacity: 0;
322
+ transition: opacity 0.1s ease;
323
+ }
324
+ .canvas-chip:hover .canvas-chip-swap,
325
+ .canvas-chip:focus-within .canvas-chip-swap {
326
+ opacity: 1;
327
+ }
328
+ .canvas-chip-swap:hover {
329
+ background: white;
330
+ color: #f97316;
331
+ }
332
+ .canvas-area-empty {
333
+ display: grid;
334
+ flex: 1;
335
+ place-items: center;
336
+ border: 1px dashed rgb(255 255 255 / 60%);
337
+ border-radius: 8px;
338
+ background: transparent;
339
+ color: #f3f4f6;
340
+ font-size: 11px;
341
+ font-family: inherit;
342
+ cursor: pointer;
343
+ }
344
+ .canvas-area-empty:hover {
345
+ border-color: #f97316;
346
+ color: #f97316;
347
+ }
348
+ @media (hover: none), (pointer: coarse) {
349
+ .canvas-edge,
350
+ .canvas-area-remove,
351
+ .canvas-chip-swap {
352
+ opacity: 1;
353
+ }
354
+ }
355
+ </style>
@@ -0,0 +1,57 @@
1
+ // @vitest-environment happy-dom
2
+ import { afterEach, describe, expect, it, vi } from 'vitest'
3
+ import { mount, type VueWrapper } from '@vue/test-utils'
4
+ import {
5
+ defaultDisplayTemplateDraft,
6
+ addArea,
7
+ type DisplaySplitDraft
8
+ } from '@/modules/display-system/interface'
9
+ vi.mock('@feedmepos/mf-common', () => ({ useI18n: () => ({ t: (key: string) => key }) }))
10
+ import Canvas from './DisplayLayoutCanvas.vue'
11
+ let wrapper: VueWrapper
12
+
13
+ afterEach(() => wrapper?.unmount())
14
+ describe('DisplayLayoutCanvas divider gestures', () => {
15
+ it.each([
16
+ ['ROW', []],
17
+ ['COLUMN', [1]]
18
+ ] as const)(
19
+ 'uses raw weights for %s pointer movement without a rounding jump',
20
+ async (direction, path) => {
21
+ const draft = defaultDisplayTemplateDraft(path.length ? 'ads' : 'mixed')
22
+ if (!path.length) addArea(draft, 'ROW')
23
+ const root = draft.root as DisplaySplitDraft
24
+ const group = path.length ? (root.children[1]!.node as DisplaySplitDraft) : root
25
+ if (path.length) group.children.push({ weight: 1, node: { kind: 'ZONE', id: 'third' } })
26
+ group.direction = direction
27
+ group.children.forEach((child, index) => {
28
+ child.weight = [333, 333, 334][index]!
29
+ })
30
+ wrapper = mount(Canvas, {
31
+ props: { root, selectedZoneId: '', selectedBlockId: '', scope: 'area', dragging: false },
32
+ global: { stubs: { FmIcon: true } }
33
+ })
34
+ const surface = path.length ? wrapper.find('.canvas-group') : wrapper
35
+ vi.spyOn(surface.element, 'getBoundingClientRect').mockReturnValue({
36
+ left: 0,
37
+ top: 0,
38
+ width: 1000,
39
+ height: 1000
40
+ } as DOMRect)
41
+ const dividers = path.length
42
+ ? surface.findAll('[role="separator"]')
43
+ : wrapper.findAll('[role="separator"]')
44
+ const divider = dividers[1]!
45
+ Object.assign(divider.element, { setPointerCapture: vi.fn(), releasePointerCapture: vi.fn() })
46
+ await divider.trigger('pointerdown', { pointerId: 1 })
47
+ await divider.trigger('pointermove', { pointerId: 1, clientX: 666, clientY: 666 })
48
+ expect(wrapper.emitted('resize')![0]![0]).toEqual({
49
+ path: [...path],
50
+ index: 1,
51
+ ratio: 333 / 667
52
+ })
53
+ await divider.trigger('pointerup', { pointerId: 1 })
54
+ expect(wrapper.emitted('resize-end')).toHaveLength(1)
55
+ }
56
+ )
57
+ })