fix:完善预览模式

This commit is contained in:
lhj
2024-11-17 14:47:36 +08:00
parent 8424202fc8
commit f601417913
13 changed files with 130 additions and 124 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
VITE_BASE_URL=/

2
components.d.ts vendored
View File

@ -8,7 +8,9 @@ export {}
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
AdaptivePage: typeof import('./src/components/AdaptivePage.vue')['default'] AdaptivePage: typeof import('./src/components/AdaptivePage.vue')['default']
Designer: typeof import('./src/components/Designer.vue')['default']
DynamicComponent: typeof import('./src/components/DynamicComponent.vue')['default'] DynamicComponent: typeof import('./src/components/DynamicComponent.vue')['default']
MainView: typeof import('./src/components/MainView.vue')['default']
NestedFunction: typeof import('./src/components/NestedFunction.vue')['default'] NestedFunction: typeof import('./src/components/NestedFunction.vue')['default']
PropertyEditor: typeof import('./src/components/PropertyEditor.vue')['default'] PropertyEditor: typeof import('./src/components/PropertyEditor.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']

View File

@ -26,6 +26,7 @@
}, },
"devDependencies": { "devDependencies": {
"@arco-design/web-vue": "^2.56.0", "@arco-design/web-vue": "^2.56.0",
"@types/lodash": "^4.17.13",
"@types/node": "^22.9.0", "@types/node": "^22.9.0",
"@vitejs/plugin-vue": "^5.0.5", "@vitejs/plugin-vue": "^5.0.5",
"concurrently": "^9.1.0", "concurrently": "^9.1.0",

View File

@ -1,5 +0,0 @@
import { createPinia } from 'pinia';
const store = createPinia();
export default store;

View File

@ -1,27 +0,0 @@
<template>
<div v-if="!isEmpty(data)" class="box">
<template v-for="item in data" :key="item.id">
<!-- <component :is="componentsList[item.code]" :data="item"></component>-->
</template>
</div>
</template>
<script setup lang="ts">
import {onBeforeMount, shallowRef, ref} from "vue";
import {isEmpty} from "lodash";
import _ from "lodash";
const data = shallowRef<any>({});
onBeforeMount(() => {
// 接收客户端posemessage传递过来的消息
const obj = JSON.parse(localStorage.getItem("lowcode") || "");
console.log("数据哈哈哈", obj);
data.value = obj;
});
</script>
<style lang="scss" scoped>
.box {
width: 1000px;
height: 600px;
overflow: hidden;
}
</style>

View File

@ -1,12 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import MainView from "../preview/views/MainView.vue";
</script> </script>
<template> <template>
<div> <router-view></router-view>
<MainView></MainView>
</div>
</template> </template>
<style scoped> <style scoped>

View File

@ -5,19 +5,19 @@
:id="componentId" :id="componentId"
:class="[ :class="[
'dynamic-component', 'dynamic-component',
{ 'hover-state': isHovered }, { 'hover-state': isHovered && store.designerMode },
{ 'click-state': componentSelected } { 'click-state': componentSelected && store.designerMode }
]" ]"
@click.stop="handleClick" @click.stop="handleClick"
@mouseover="isHovered = true" @mouseover="isHovered = true"
@mouseleave="isHovered = false" @mouseleave="isHovered = false"
> >
<div v-if="isHovered" class="component-header"> <div v-if="isHovered && store.designerMode" class="component-header">
<span>{{ componentName }}</span> <span>{{ componentName }}</span>
</div> </div>
<div v-if="componentSelected" class="component-header" :style="headerStyle"> <div v-if="componentSelected && store.designerMode" class="component-header" :style="headerStyle">
<div style="background-color:#3457cc;color: #ffffff;padding: 5px ;margin-right: 2px">{{ componentName }}</div> <div style="background-color:#3457cc;color: #ffffff;padding: 5px ;margin-right: 2px">{{ componentName }}</div>
<div v-if="componentSelected" style="background-color:#3457cc;color:#ffffff;padding: 6px 5px 5px 5px;display: flex;width: fit-content;flex-wrap: nowrap"> <div style="background-color:#3457cc;color:#ffffff;padding: 6px 5px 5px 5px;display: flex;width: fit-content;flex-wrap: nowrap">
<icon-copy class="clickable" size="20" /> <icon-copy class="clickable" size="20" />
<icon-edit class="clickable" @click="handleEditFunc" size="20" /> <icon-edit class="clickable" @click="handleEditFunc" size="20" />
<icon-delete class="clickable" @click="handleDeleteFunc" size="20" /> <icon-delete class="clickable" @click="handleDeleteFunc" size="20" />
@ -82,16 +82,16 @@ const isHovered = ref(false);
const handleClick = () => { const handleClick = () => {
const currentComponent = getCurrentSchemeObj(); const currentComponent = getCurrentSchemeObj();
if (currentComponent) { if (currentComponent) {
store.updateNowScheme(currentComponent); store.updateNowScheme(currentComponent);
console.log(`Component with id ${currentComponent?.id} was clicked.`); console.log(`Component with id ${currentComponent?.id} was clicked.`);
// 你可以在这里执行更多的逻辑,例如发出一个事件或调用一个方法 // 你可以在这里执行更多的逻辑,例如发出一个事件或调用一个方法
} }
}; };
const handleEditFunc = () => { const handleEditFunc = () => {
// 编辑功能
}; };
const handleDeleteFunc = () => { const handleDeleteFunc = () => {
store.deleteScheme(componentId.value); store.deleteScheme(componentId.value);
}; };
@ -117,26 +117,25 @@ const adjustHeaderPosition = () => {
const containerRect = containerEl.getBoundingClientRect(); const containerRect = containerEl.getBoundingClientRect();
debugger
// 计算上下左右的可用空间 // 计算上下左右的可用空间
const topSpace = componentRect.top - containerRect.top; const topSpace = componentRect.top - containerRect.top;
const bottomSpace = containerRect.bottom - componentRect.bottom; const bottomSpace = containerRect.bottom - componentRect.bottom;
// 检查上方是否有足够的空间 // 检查上方是否有足够的空间
if (topSpace >= headerRect.height) { if (topSpace >= headerRect.height) {
top = -headerRect.height + 2; top = -headerRect.height + 2;
} else if (bottomSpace >= headerRect.height) { } else if (bottomSpace >= headerRect.height) {
top = componentRect.height - 2; top = componentRect.height - 2;
} }
if (headerRect.width>componentRect.width)
{ if (headerRect.width > componentRect.width) {
left = -2; left = -2;
justification = 'flex-start'; justification = 'flex-start';
}else } else {
{
left = componentRect.width - headerRect.width - 2; left = componentRect.width - headerRect.width - 2;
justification = 'flex-end'; justification = 'flex-end';
} }
headerStyle.value = { headerStyle.value = {
top: `${top}px`, top: `${top}px`,
left: `${left}px`, left: `${left}px`,
@ -145,8 +144,7 @@ const adjustHeaderPosition = () => {
}; };
onMounted(() => { onMounted(() => {
adjustHeaderPosition() adjustHeaderPosition();
// console.log("组件挂载后",props.componentData);
}); });
watch(() => componentSelected.value, () => { watch(() => componentSelected.value, () => {
@ -158,11 +156,10 @@ watch(() => componentSelected.value, () => {
}); });
</script> </script>
<style scoped> <style scoped>
.dynamic-component { .dynamic-component {
position: relative; position: relative;
border: 1px solid transparent; /* 默认透明边框 */
transition: box-shadow 0.1s;
width: fit-content; width: fit-content;
} }

View File

@ -2,7 +2,7 @@ import { createApp } from 'vue'
import './style.css' import './style.css'
import App from './App.vue' import App from './App.vue'
import ArcoVue from '@arco-design/web-vue'; import ArcoVue from '@arco-design/web-vue';
import router from "./router"; import router from "@/router/index.ts";
// 额外引入图标库 // 额外引入图标库
import ArcoVueIcon from '@arco-design/web-vue/es/icon'; import ArcoVueIcon from '@arco-design/web-vue/es/icon';
import '@arco-design/web-vue/dist/arco.css'; import '@arco-design/web-vue/dist/arco.css';

View File

@ -1,19 +1,37 @@
[
{ {
"type": "AdaptivePage", "id": "Card-b22544833910000",
"name": "AdaptivePage", "name": "card",
"id": "a31c7fb13910000", "type": "Card",
"version": "2.0", "props": {
"title": "Card"
},
"class": "arco-card arco-card-size-medium arco-card-bordered",
"designer": "",
"text": "ByteDance's core product, Toutiao (\"Headlines\"), is a content platform in China and around the world. Toutiao started out as a news recommendation engine and gradually evolved into a platform delivering content in various formats.",
"children": [],
"style": "width:360px",
"visible": true,
"slots": {
"extra": {
"id": "9f8289a12910000",
"name": "avatar",
"type": "Avatar",
"props": {}, "props": {},
"class": "", "class": "",
"style": "", "designer": "",
"variables": {}, "text": "",
"dataSources": {},
"functions": {},
"orchestrations": {},
"events": {},
"slots": {},
"header": {},
"footer": {},
"children": [], "children": [],
"meta": {} "style": "",
"visible": "",
"slots": {},
"disable": "",
"events": {},
"loop": {}
} }
},
"disable": true,
"events": {},
"loop": {}
}
]

View File

@ -1,15 +0,0 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
const routes: Array<RouteRecordRaw> = [
{
path: "/:pathMatch(.*)*",
component: () => import("../preview/views/MainView.vue"),
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;

View File

@ -1,18 +1,23 @@
import { createRouter, createWebHashHistory } from "vue-router"; import { createRouter, createWebHistory } from 'vue-router';
import Designer from '../views/Designer.vue';
import Preview from '../views/Preview.vue';
const routes = [ const routes = [
// { {
// path: "/lowcode", path: '/',
// name: "活动生成", name: 'Designer',
// meta: { component: Designer
// title: "活动生成", },
// icon: "Calendar", {
// }, path: '/preview',
// component: () => import("@/pages/lowCode/index.vue"), name: 'Preview',
// }, component: Preview
}
]; ];
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHistory(import.meta.env.VITE_BASE_URL),
routes, routes
}); });
export { router, routes };
export default router;

View File

@ -45,6 +45,7 @@
group="designer" group="designer"
ghost-class="ghost" ghost-class="ghost"
class="canvas" class="canvas"
@start="onPreviewStart"
@update="onPreviewUpdate" @update="onPreviewUpdate"
@stop="onPreviewStop" @stop="onPreviewStop"
@add="onPreViewAdd" @add="onPreViewAdd"
@ -65,9 +66,9 @@
import { RadioGroup, Radio } from '@arco-design/web-vue'; import { RadioGroup, Radio } from '@arco-design/web-vue';
import { onMounted, ref, watch } from 'vue'; import { onMounted, ref, watch } from 'vue';
import { uuid } from 'lsp-uuid'; import { uuid } from 'lsp-uuid';
import { componentScheme } from '@/schemes/scheme'; import { componentScheme } from '@/schemes/scheme.ts';
import { useSchemeStore } from '@/stores/useSchemeStore'; import { useSchemeStore } from '@/stores/useSchemeStore.ts';
import { IComponent } from '@/type/IComponent'; import { IComponent } from '@/type/IComponent.ts';
import DynamicComponent from '@/components/DynamicComponent.vue'; import DynamicComponent from '@/components/DynamicComponent.vue';
import PropertyEditor from '@/components/PropertyEditor.vue'; import PropertyEditor from '@/components/PropertyEditor.vue';
import { DraggableEvent, VueDraggable } from 'vue-draggable-plus'; import { DraggableEvent, VueDraggable } from 'vue-draggable-plus';
@ -193,7 +194,13 @@ const save = async () => {
const view = () => { const view = () => {
localStorage.setItem("lowcode", JSON.stringify(store.previewScheme)); localStorage.setItem("lowcode", JSON.stringify(store.previewScheme));
window.open(location.href.replace("/#/", "/preview/#/")); //
const newWindow = window.open('/preview', '_blank');
if (newWindow) {
newWindow.focus();
} else {
alert('弹窗被阻止,请允许弹窗');
}
}; };
</script> </script>

27
src/views/Preview.vue Normal file
View File

@ -0,0 +1,27 @@
<template>
<DynamicComponent v-for="component in preView" :key="component.id" :componentData="component">
{{ component.id }}
</DynamicComponent>
</template>
<script setup lang="ts">
import {onBeforeMount, shallowRef, ref} from "vue";
import DynamicComponent from "@/components/DynamicComponent.vue";
import { useSchemeStore } from '../stores/useSchemeStore';
const store = useSchemeStore();
let preView=ref([])
onBeforeMount(() => {
store.designerMode=false
preView = JSON.parse(localStorage.getItem("lowcode") || "");
console.log(preView)
});
</script>
<style lang="scss" scoped>
.box {
width: 1000px;
height: 600px;
overflow: hidden;
}
</style>