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