沙钢智慧能源系统前端代码
houzhongjian
2024-10-09 314507f8ddadd9c66e98d260c3b2a5dad1a04015
提交 | 用户 | 时间
314507 1 <template>
H 2   <div :class="['component', { active: active }]">
3     <div
4       :style="{
5         ...style
6       }"
7     >
8       <component :is="component.id" :property="component.property" />
9     </div>
10     <div class="component-wrap">
11       <!-- 左侧:组件名(悬浮的小贴条) -->
12       <div class="component-name" v-if="component.name">
13         {{ component.name }}
14       </div>
15       <!-- 右侧:组件操作工具栏 -->
16       <div class="component-toolbar" v-if="showToolbar && component.name && active">
17         <VerticalButtonGroup type="primary">
18           <el-tooltip content="上移" placement="right">
19             <el-button :disabled="!canMoveUp" @click.stop="handleMoveComponent(-1)">
20               <Icon icon="ep:arrow-up" />
21             </el-button>
22           </el-tooltip>
23           <el-tooltip content="下移" placement="right">
24             <el-button :disabled="!canMoveDown" @click.stop="handleMoveComponent(1)">
25               <Icon icon="ep:arrow-down" />
26             </el-button>
27           </el-tooltip>
28           <el-tooltip content="复制" placement="right">
29             <el-button @click.stop="handleCopyComponent()">
30               <Icon icon="ep:copy-document" />
31             </el-button>
32           </el-tooltip>
33           <el-tooltip content="删除" placement="right">
34             <el-button @click.stop="handleDeleteComponent()">
35               <Icon icon="ep:delete" />
36             </el-button>
37           </el-tooltip>
38         </VerticalButtonGroup>
39       </div>
40     </div>
41   </div>
42 </template>
43
44 <script lang="ts">
45 // 注册所有的组件
46 import { components } from '../components/mobile/index'
47 export default {
48   components: { ...components }
49 }
50 </script>
51 <script setup lang="ts">
52 import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
53 import { propTypes } from '@/utils/propTypes'
54 import { object } from 'vue-types'
55
56 /**
57  * 组件容器:目前在中间部分
58  * 用于包裹组件,为组件提供 背景、外边距、内边距、边框等样式
59  */
60 defineOptions({ name: 'ComponentContainer' })
61
62 type DiyComponentWithStyle = DiyComponent<any> & { property: { style?: ComponentStyle } }
63 const props = defineProps({
64   component: object<DiyComponentWithStyle>().isRequired,
65   active: propTypes.bool.def(false),
66   canMoveUp: propTypes.bool.def(false),
67   canMoveDown: propTypes.bool.def(false),
68   showToolbar: propTypes.bool.def(true)
69 })
70
71 /**
72  * 组件样式
73  */
74 const style = computed(() => {
75   let componentStyle = props.component.property.style
76   if (!componentStyle) {
77     return {}
78   }
79   return {
80     marginTop: `${componentStyle.marginTop || 0}px`,
81     marginBottom: `${componentStyle.marginBottom || 0}px`,
82     marginLeft: `${componentStyle.marginLeft || 0}px`,
83     marginRight: `${componentStyle.marginRight || 0}px`,
84     paddingTop: `${componentStyle.paddingTop || 0}px`,
85     paddingRight: `${componentStyle.paddingRight || 0}px`,
86     paddingBottom: `${componentStyle.paddingBottom || 0}px`,
87     paddingLeft: `${componentStyle.paddingLeft || 0}px`,
88     borderTopLeftRadius: `${componentStyle.borderTopLeftRadius || 0}px`,
89     borderTopRightRadius: `${componentStyle.borderTopRightRadius || 0}px`,
90     borderBottomRightRadius: `${componentStyle.borderBottomRightRadius || 0}px`,
91     borderBottomLeftRadius: `${componentStyle.borderBottomLeftRadius || 0}px`,
92     overflow: 'hidden',
93     background:
94       componentStyle.bgType === 'color' ? componentStyle.bgColor : `url(${componentStyle.bgImg})`
95   }
96 })
97
98 const emits = defineEmits<{
99   (e: 'move', direction: number): void
100   (e: 'copy'): void
101   (e: 'delete'): void
102 }>()
103
104 /**
105  * 移动组件
106  * @param direction 移动方向
107  */
108 const handleMoveComponent = (direction: number) => {
109   emits('move', direction)
110 }
111
112 /**
113  * 复制组件
114  */
115 const handleCopyComponent = () => {
116   emits('copy')
117 }
118
119 /**
120  * 删除组件
121  */
122 const handleDeleteComponent = () => {
123   emits('delete')
124 }
125 </script>
126
127 <style scoped lang="scss">
128 $active-border-width: 2px;
129 $hover-border-width: 1px;
130 $name-position: -85px;
131 $toolbar-position: -55px;
132
133 /* 组件 */
134 .component {
135   position: relative;
136   cursor: move;
137
138   .component-wrap {
139     position: absolute;
140     top: 0;
141     left: -$active-border-width;
142     display: block;
143     width: 100%;
144     height: 100%;
145
146     /* 鼠标放到组件上时 */
147     &:hover {
148       border: $hover-border-width dashed var(--el-color-primary);
149       box-shadow: 0 0 5px 0 rgb(24 144 255 / 30%);
150
151       .component-name {
152         top: $hover-border-width;
153
154         /* 防止加了边框之后,位置移动 */
155         left: $name-position - $hover-border-width;
156       }
157     }
158
159     /* 左侧:组件名称 */
160     .component-name {
161       position: absolute;
162       top: $active-border-width;
163       left: $name-position;
164       display: block;
165       width: 80px;
166       height: 25px;
167       font-size: 12px;
168       line-height: 25px;
169       text-align: center;
170       background: #fff;
171       box-shadow:
172         0 0 4px #00000014,
173         0 2px 6px #0000000f,
174         0 4px 8px 2px #0000000a;
175
176       /* 右侧小三角 */
177       &::after {
178         position: absolute;
179         top: 7.5px;
180         right: -10px;
181         width: 0;
182         height: 0;
183         border: 5px solid transparent;
184         border-left-color: #fff;
185         content: ' ';
186       }
187     }
188
189     /* 右侧:组件操作工具栏 */
190     .component-toolbar {
191       position: absolute;
192       top: 0;
193       right: $toolbar-position;
194       display: none;
195
196       /* 左侧小三角 */
197       &::before {
198         position: absolute;
199         top: 10px;
200         left: -10px;
201         width: 0;
202         height: 0;
203         border: 5px solid transparent;
204         border-right-color: #2d8cf0;
205         content: ' ';
206       }
207     }
208   }
209
210   /* 组件选中时 */
211   &.active {
212     margin-bottom: 4px;
213
214     .component-wrap {
215       margin-bottom: $active-border-width + $active-border-width;
216       border: $active-border-width solid var(--el-color-primary) !important;
217       box-shadow: 0 0 10px 0 rgb(24 144 255 / 30%);
218
219       .component-name {
220         top: 0 !important;
221
222         /* 防止加了边框之后,位置移动 */
223         left: $name-position - $active-border-width !important;
224         color: #fff;
225         background: var(--el-color-primary);
226
227         &::after {
228           border-left-color: var(--el-color-primary);
229         }
230       }
231
232       .component-toolbar {
233         display: block;
234       }
235     }
236   }
237 }
238 </style>