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/ComponentContainer.vue |  239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 239 insertions(+), 0 deletions(-)

diff --git a/src/components/DiyEditor/components/ComponentContainer.vue b/src/components/DiyEditor/components/ComponentContainer.vue
new file mode 100644
index 0000000..4856722
--- /dev/null
+++ b/src/components/DiyEditor/components/ComponentContainer.vue
@@ -0,0 +1,239 @@
+<template>
+  <div :class="['component', { active: active }]">
+    <div
+      :style="{
+        ...style
+      }"
+    >
+      <component :is="component.id" :property="component.property" />
+    </div>
+    <div class="component-wrap">
+      <!-- 宸︿晶锛氱粍浠跺悕锛堟偓娴殑灏忚创鏉★級 -->
+      <div class="component-name" v-if="component.name">
+        {{ component.name }}
+      </div>
+      <!-- 鍙充晶锛氱粍浠舵搷浣滃伐鍏锋爮 -->
+      <div class="component-toolbar" v-if="showToolbar && component.name && active">
+        <VerticalButtonGroup type="primary">
+          <el-tooltip content="涓婄Щ" placement="right">
+            <el-button :disabled="!canMoveUp" @click.stop="handleMoveComponent(-1)">
+              <Icon icon="ep:arrow-up" />
+            </el-button>
+          </el-tooltip>
+          <el-tooltip content="涓嬬Щ" placement="right">
+            <el-button :disabled="!canMoveDown" @click.stop="handleMoveComponent(1)">
+              <Icon icon="ep:arrow-down" />
+            </el-button>
+          </el-tooltip>
+          <el-tooltip content="澶嶅埗" placement="right">
+            <el-button @click.stop="handleCopyComponent()">
+              <Icon icon="ep:copy-document" />
+            </el-button>
+          </el-tooltip>
+          <el-tooltip content="鍒犻櫎" placement="right">
+            <el-button @click.stop="handleDeleteComponent()">
+              <Icon icon="ep:delete" />
+            </el-button>
+          </el-tooltip>
+        </VerticalButtonGroup>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+// 娉ㄥ唽鎵�鏈夌殑缁勪欢
+import { components } from '../components/mobile/index'
+export default {
+  components: { ...components }
+}
+</script>
+<script setup lang="ts">
+import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
+import { propTypes } from '@/utils/propTypes'
+import { object } from 'vue-types'
+
+/**
+ * 缁勪欢瀹瑰櫒锛氱洰鍓嶅湪涓棿閮ㄥ垎
+ * 鐢ㄤ簬鍖呰9缁勪欢锛屼负缁勪欢鎻愪緵 鑳屾櫙銆佸杈硅窛銆佸唴杈硅窛銆佽竟妗嗙瓑鏍峰紡
+ */
+defineOptions({ name: 'ComponentContainer' })
+
+type DiyComponentWithStyle = DiyComponent<any> & { property: { style?: ComponentStyle } }
+const props = defineProps({
+  component: object<DiyComponentWithStyle>().isRequired,
+  active: propTypes.bool.def(false),
+  canMoveUp: propTypes.bool.def(false),
+  canMoveDown: propTypes.bool.def(false),
+  showToolbar: propTypes.bool.def(true)
+})
+
+/**
+ * 缁勪欢鏍峰紡
+ */
+const style = computed(() => {
+  let componentStyle = props.component.property.style
+  if (!componentStyle) {
+    return {}
+  }
+  return {
+    marginTop: `${componentStyle.marginTop || 0}px`,
+    marginBottom: `${componentStyle.marginBottom || 0}px`,
+    marginLeft: `${componentStyle.marginLeft || 0}px`,
+    marginRight: `${componentStyle.marginRight || 0}px`,
+    paddingTop: `${componentStyle.paddingTop || 0}px`,
+    paddingRight: `${componentStyle.paddingRight || 0}px`,
+    paddingBottom: `${componentStyle.paddingBottom || 0}px`,
+    paddingLeft: `${componentStyle.paddingLeft || 0}px`,
+    borderTopLeftRadius: `${componentStyle.borderTopLeftRadius || 0}px`,
+    borderTopRightRadius: `${componentStyle.borderTopRightRadius || 0}px`,
+    borderBottomRightRadius: `${componentStyle.borderBottomRightRadius || 0}px`,
+    borderBottomLeftRadius: `${componentStyle.borderBottomLeftRadius || 0}px`,
+    overflow: 'hidden',
+    background:
+      componentStyle.bgType === 'color' ? componentStyle.bgColor : `url(${componentStyle.bgImg})`
+  }
+})
+
+const emits = defineEmits<{
+  (e: 'move', direction: number): void
+  (e: 'copy'): void
+  (e: 'delete'): void
+}>()
+
+/**
+ * 绉诲姩缁勪欢
+ * @param direction 绉诲姩鏂瑰悜
+ */
+const handleMoveComponent = (direction: number) => {
+  emits('move', direction)
+}
+
+/**
+ * 澶嶅埗缁勪欢
+ */
+const handleCopyComponent = () => {
+  emits('copy')
+}
+
+/**
+ * 鍒犻櫎缁勪欢
+ */
+const handleDeleteComponent = () => {
+  emits('delete')
+}
+</script>
+
+<style scoped lang="scss">
+$active-border-width: 2px;
+$hover-border-width: 1px;
+$name-position: -85px;
+$toolbar-position: -55px;
+
+/* 缁勪欢 */
+.component {
+  position: relative;
+  cursor: move;
+
+  .component-wrap {
+    position: absolute;
+    top: 0;
+    left: -$active-border-width;
+    display: block;
+    width: 100%;
+    height: 100%;
+
+    /* 榧犳爣鏀惧埌缁勪欢涓婃椂 */
+    &:hover {
+      border: $hover-border-width dashed var(--el-color-primary);
+      box-shadow: 0 0 5px 0 rgb(24 144 255 / 30%);
+
+      .component-name {
+        top: $hover-border-width;
+
+        /* 闃叉鍔犱簡杈规涔嬪悗锛屼綅缃Щ鍔� */
+        left: $name-position - $hover-border-width;
+      }
+    }
+
+    /* 宸︿晶锛氱粍浠跺悕绉� */
+    .component-name {
+      position: absolute;
+      top: $active-border-width;
+      left: $name-position;
+      display: block;
+      width: 80px;
+      height: 25px;
+      font-size: 12px;
+      color: #6a6a6a;
+      line-height: 25px;
+      text-align: center;
+      background: #fff;
+      box-shadow:
+        0 0 4px #00000014,
+        0 2px 6px #0000000f,
+        0 4px 8px 2px #0000000a;
+
+      /* 鍙充晶灏忎笁瑙� */
+      &::after {
+        position: absolute;
+        top: 7.5px;
+        right: -10px;
+        width: 0;
+        height: 0;
+        border: 5px solid transparent;
+        border-left-color: #fff;
+        content: ' ';
+      }
+    }
+
+    /* 鍙充晶锛氱粍浠舵搷浣滃伐鍏锋爮 */
+    .component-toolbar {
+      position: absolute;
+      top: 0;
+      right: $toolbar-position;
+      display: none;
+
+      /* 宸︿晶灏忎笁瑙� */
+      &::before {
+        position: absolute;
+        top: 10px;
+        left: -10px;
+        width: 0;
+        height: 0;
+        border: 5px solid transparent;
+        border-right-color: #2d8cf0;
+        content: ' ';
+      }
+    }
+  }
+
+  /* 缁勪欢閫変腑鏃� */
+  &.active {
+    margin-bottom: 4px;
+
+    .component-wrap {
+      margin-bottom: $active-border-width + $active-border-width;
+      border: $active-border-width solid var(--el-color-primary) !important;
+      box-shadow: 0 0 10px 0 rgb(24 144 255 / 30%);
+
+      .component-name {
+        top: 0 !important;
+
+        /* 闃叉鍔犱簡杈规涔嬪悗锛屼綅缃Щ鍔� */
+        left: $name-position - $active-border-width !important;
+        color: #fff;
+        background: var(--el-color-primary);
+
+        &::after {
+          border-left-color: var(--el-color-primary);
+        }
+      }
+
+      .component-toolbar {
+        display: block;
+      }
+    }
+  }
+}
+</style>

--
Gitblit v1.8.0