From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/components/DiyEditor/components/mobile/HotZone/components/HotZoneEditDialog/index.vue | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 236 insertions(+), 0 deletions(-)
diff --git a/src/components/DiyEditor/components/mobile/HotZone/components/HotZoneEditDialog/index.vue b/src/components/DiyEditor/components/mobile/HotZone/components/HotZoneEditDialog/index.vue
new file mode 100644
index 0000000..3925057
--- /dev/null
+++ b/src/components/DiyEditor/components/mobile/HotZone/components/HotZoneEditDialog/index.vue
@@ -0,0 +1,236 @@
+<template>
+ <Dialog v-model="dialogVisible" title="璁剧疆鐑尯" width="780" @close="handleClose">
+ <div ref="container" class="relative h-full w-750px">
+ <el-image :src="imgUrl" class="pointer-events-none h-full w-750px select-none" />
+ <div
+ v-for="(item, hotZoneIndex) in formData"
+ :key="hotZoneIndex"
+ class="hot-zone"
+ :style="{
+ width: `${item.width}px`,
+ height: `${item.height}px`,
+ top: `${item.top}px`,
+ left: `${item.left}px`
+ }"
+ @mousedown="handleMove(item, $event)"
+ @dblclick="handleShowAppLinkDialog(item)"
+ >
+ <span class="pointer-events-none select-none">{{ item.name || '鍙屽嚮閫夋嫨閾炬帴' }}</span>
+ <Icon icon="ep:close" class="delete" :size="14" @click="handleRemove(item)" />
+
+ <!-- 8涓帶鍒剁偣 -->
+ <span
+ class="ctrl-dot"
+ v-for="(dot, dotIndex) in CONTROL_DOT_LIST"
+ :key="dotIndex"
+ :style="dot.style"
+ @mousedown="handleResize(item, dot, $event)"
+ ></span>
+ </div>
+ </div>
+ <template #footer>
+ <el-button @click="handleAdd" type="primary" plain>
+ <Icon icon="ep:plus" class="mr-5px" />
+ 娣诲姞鐑尯
+ </el-button>
+ <el-button @click="handleSubmit" type="primary" plain>
+ <Icon icon="ep:check" class="mr-5px" />
+ 纭畾
+ </el-button>
+ </template>
+ </Dialog>
+ <AppLinkSelectDialog ref="appLinkDialogRef" @app-link-change="handleAppLinkChange" />
+</template>
+
+<script setup lang="ts">
+import { HotZoneItemProperty } from '@/components/DiyEditor/components/mobile/HotZone/config'
+import { array, string } from 'vue-types'
+import {
+ CONTROL_DOT_LIST,
+ CONTROL_TYPE_ENUM,
+ ControlDot,
+ HOT_ZONE_MIN_SIZE,
+ useDraggable,
+ zoomIn,
+ zoomOut
+} from './controller'
+import { AppLink } from '@/components/AppLinkInput/data'
+import { remove } from 'lodash-es'
+
+/** 鐑尯缂栬緫瀵硅瘽妗� */
+defineOptions({ name: 'HotZoneEditDialog' })
+
+// 瀹氫箟灞炴��
+const props = defineProps({
+ modelValue: array<HotZoneItemProperty>(),
+ imgUrl: string().def('')
+})
+const emit = defineEmits(['update:modelValue'])
+const formData = ref<HotZoneItemProperty[]>([])
+
+// 寮圭獥鐨勬槸鍚︽樉绀�
+const dialogVisible = ref(false)
+// 鎵撳紑寮圭獥
+const open = () => {
+ // 鏀惧ぇ
+ formData.value = zoomIn(props.modelValue)
+ dialogVisible.value = true
+}
+// 鎻愪緵 open 鏂规硶锛岀敤浜庢墦寮�寮圭獥
+defineExpose({ open })
+
+// 鐑尯瀹瑰櫒
+const container = ref<HTMLDivElement>()
+
+// 澧炲姞鐑尯
+const handleAdd = () => {
+ formData.value.push({
+ width: HOT_ZONE_MIN_SIZE,
+ height: HOT_ZONE_MIN_SIZE,
+ top: 0,
+ left: 0
+ } as HotZoneItemProperty)
+}
+// 鍒犻櫎鐑尯
+const handleRemove = (hotZone: HotZoneItemProperty) => {
+ remove(formData.value, hotZone)
+}
+
+// 绉诲姩鐑尯
+const handleMove = (item: HotZoneItemProperty, e: MouseEvent) => {
+ useDraggable(item, e, (left, top, _, __, moveWidth, moveHeight) => {
+ setLeft(item, left + moveWidth)
+ setTop(item, top + moveHeight)
+ })
+}
+
+// 璋冩暣鐑尯澶у皬銆佷綅缃�
+const handleResize = (item: HotZoneItemProperty, ctrlDot: ControlDot, e: MouseEvent) => {
+ useDraggable(item, e, (left, top, width, height, moveWidth, moveHeight) => {
+ ctrlDot.types.forEach((type) => {
+ switch (type) {
+ case CONTROL_TYPE_ENUM.LEFT:
+ setLeft(item, left + moveWidth)
+ break
+ case CONTROL_TYPE_ENUM.TOP:
+ setTop(item, top + moveHeight)
+ break
+ case CONTROL_TYPE_ENUM.WIDTH:
+ {
+ // 涓婄Щ鏃讹紝楂樺害涓哄噺灏�
+ const direction = ctrlDot.types.includes(CONTROL_TYPE_ENUM.LEFT) ? -1 : 1
+ setWidth(item, width + moveWidth * direction)
+ }
+ break
+ case CONTROL_TYPE_ENUM.HEIGHT:
+ {
+ // 宸︾Щ鏃讹紝瀹藉害涓哄噺灏�
+ const direction = ctrlDot.types.includes(CONTROL_TYPE_ENUM.TOP) ? -1 : 1
+ setHeight(item, height + moveHeight * direction)
+ }
+ break
+ }
+ })
+ })
+}
+
+// 璁剧疆X杞村潗鏍�
+const setLeft = (item: HotZoneItemProperty, left: number) => {
+ // 涓嶈兘瓒呭嚭瀹瑰櫒
+ if (left >= 0 && left <= container.value!.offsetWidth - item.width) {
+ item.left = left
+ }
+}
+// 璁剧疆Y杞村潗鏍�
+const setTop = (item: HotZoneItemProperty, top: number) => {
+ // 涓嶈兘瓒呭嚭瀹瑰櫒
+ if (top >= 0 && top <= container.value!.offsetHeight - item.height) {
+ item.top = top
+ }
+}
+// 璁剧疆瀹藉害
+const setWidth = (item: HotZoneItemProperty, width: number) => {
+ // 涓嶈兘灏忎簬鏈�灏忓搴� && 涓嶈兘瓒呭嚭瀹瑰櫒鍙宠竟
+ if (width >= HOT_ZONE_MIN_SIZE && item.left + width <= container.value!.offsetWidth) {
+ item.width = width
+ }
+}
+// 璁剧疆楂樺害
+const setHeight = (item: HotZoneItemProperty, height: number) => {
+ // 涓嶈兘灏忎簬鏈�灏忛珮搴� && 涓嶈兘瓒呭嚭瀹瑰櫒搴曢儴
+ if (height >= HOT_ZONE_MIN_SIZE && item.top + height <= container.value!.offsetHeight) {
+ item.height = height
+ }
+}
+
+// 澶勭悊瀵硅瘽妗嗗叧闂�
+const handleSubmit = () => {
+ // 浼氳嚜鍔ㄨЕ鍙慼andleClose
+ dialogVisible.value = false
+}
+
+// 澶勭悊瀵硅瘽妗嗗叧闂�
+const handleClose = () => {
+ // 缂╁皬
+ const list = zoomOut(formData.value)
+ emit('update:modelValue', list)
+}
+
+const activeHotZone = ref<HotZoneItemProperty>()
+const appLinkDialogRef = ref()
+const handleShowAppLinkDialog = (hotZone: HotZoneItemProperty) => {
+ activeHotZone.value = hotZone
+ appLinkDialogRef.value.open(hotZone.url)
+}
+const handleAppLinkChange = (appLink: AppLink) => {
+ if (!appLink || !activeHotZone.value) return
+ activeHotZone.value.name = appLink.name
+ activeHotZone.value.url = appLink.path
+}
+</script>
+
+<style scoped lang="scss">
+.hot-zone {
+ position: absolute;
+ background: var(--el-color-primary-light-7);
+ opacity: 0.8;
+ border: 1px solid var(--el-color-primary);
+ color: var(--el-color-primary);
+ font-size: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: move;
+ z-index: 10;
+
+ /* 鎺у埗鐐� */
+ .ctrl-dot {
+ position: absolute;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ border: inherit;
+ background-color: #fff;
+ z-index: 11;
+ }
+
+ .delete {
+ display: none;
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 2px 2px 6px 6px;
+ background-color: var(--el-color-primary);
+ border-radius: 0 0 0 80%;
+ cursor: pointer;
+ color: #fff;
+ text-align: right;
+ }
+
+ &:hover {
+ .delete {
+ display: block;
+ }
+ }
+}
+</style>
--
Gitblit v1.8.0