| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- <template>
- <div class="pcEdit-pages">
- <el-header class="flex items-center h-[50px] bg-primary px-[20px]">
- <div class="text-white cursor-pointer flex items-center" @click="goBack">
- <el-icon size="14">
- <ArrowLeft />
- </el-icon>
- <span class="pl-[5px] text-[14px]">返回</span>
- </div>
- <div class="text-white ml-[10px] mr-[20px] flex items-center">
- <span class="mr-[5px] text-[rgba(255,255,255,.5)]">|</span>
- <span class="mr-[5px] text-[14px]">正在装修:{{ diyStore.name || '页面名字' }}</span>
- </div>
- <div class="flex-1"></div>
- <el-button @click="preview()">保存并预览</el-button>
- <el-button @click="save()">保存</el-button>
- <!-- :loading="loading" -->
- </el-header>
- <div class="full-container flex flex-row flex-1 bg-page">
- <!-- w-[192px] -->
- <div class="component-list">
- <!-- 组件列表区域 -->
- <el-collapse v-model="activeNames" @change="handleChange">
- <el-collapse-item v-for="(item, key) in collapse" :key="key" :title="item.name" :name="key">
- <ul class="flex flex-row flex-wrap">
- <li
- v-for="(compItem, compKey) in item.list"
- :key="compKey"
- class="w-2/4 text-center cursor-pointer h-[65px]"
- :title="compItem.name"
- @click="diyStore.addComponent(compItem, compKey)"
- >
- <icon v-if="compItem.icon" :name="compItem.icon" size="20px" class="inline-block mt-[3px]" />
- <icon v-else name="iconfont iconkaifazujian" size="20px" class="inline-block mt-[3px]" />
- <span class="block text-[12px] truncate">{{ compItem.name }}</span>
- </li>
- </ul>
- </el-collapse-item>
- </el-collapse>
- </div>
- <div class="preview-wrap">
- <div class="preview-box">
- <!-- 组件编辑区域 -->
- <div class="preview-pages shadow-lg" :style="{ backgroundColor: diyStore.backgroundColor }">
- <draggable v-model="diyStore.componentList" item-key="itemKey" class="drag-area" :move="onDragMove">
- <template #item="{ element, index }">
- <div @click="diyStore.onComponent(element, index)" class="component-bos">
- <div class="component-box" :style="{ borderWidth: diyStore.currentIndex == index ? '2px' : '0px' }"></div>
- <component :is="element.components" :key="element.itemKey" :index="index"></component>
- </div>
- </template>
- </draggable>
- </div>
- <div class="quick-action text-center w-[42px] rounded shadow-md">
- <el-tooltip effect="light" content="上移" placement="right">
- <icon name="iconfont iconjiantoushang" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
- </el-tooltip>
- <el-tooltip effect="light" content="下移" placement="right">
- <icon name="iconfont iconjiantouxia" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
- </el-tooltip>
- <!-- <el-tooltip effect="light" content="复制" placement="right">
- <icon name="iconfont iconcopy-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
- </el-tooltip> -->
- <el-tooltip effect="light" content="删除" placement="right">
- <icon name="iconfont icondelete-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent" />
- </el-tooltip>
- <el-tooltip effect="light" content="页面设置" placement="right">
- <icon name="iconfont iconloader-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
- </el-tooltip>
- </div>
- </div>
- </div>
- <!-- 编辑组件属性区域 -->
- <!-- w-[400px] -->
- <div class="edit-attribute-wrap">
- <!-- 编辑组件属性区域 -->
- <el-scrollbar>
- <el-card class="box-card" shadow="never">
- <template #header>
- <div class="card-header flex justify-between items-center">
- <span class="title flex-1">{{ diyStore.currentIndex == -99 ? '页面设置' : diyStore.editComponent.name }}</span>
- <div class="tab-wrap flex rounded-[50px] bg-gray-100 text-[14px]">
- <span
- class="cursor-pointer rounded-[50px] py-[5px] px-[15px]"
- :class="{ 'bg-primary text-white': diyStore.editTab == 'content' }"
- @click="diyStore.editTab = 'content'"
- >内容</span
- >
- <span
- class="cursor-pointer rounded-[50px] py-[5px] px-[15px]"
- :class="{ 'bg-primary text-white': diyStore.editTab == 'style' }"
- @click="diyStore.editTab = 'style'"
- >样式</span
- >
- </div>
- </div>
- </template>
- <div class="edit-component-wrap">
- <component
- v-if="diyStore.currentKey && diyStore.currentIndex != -99"
- :is="diyStore.editComponent.edit"
- :key="diyStore.currentIndex"
- :value="diyStore.componentList[diyStore.currentIndex]"
- >
- <template #style>
- <div class="edit-attr-item-wrap">
- <h3 class="mb-[10px]">组件样式</h3>
- <el-form label-width="90px" class="px-[10px]">
- <template v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
- <el-form-item label="底部背景">
- <el-color-picker v-model="diyStore.editComponent.pageStartBgColor" :predefine="diyStore.predefineColors" />
- <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
- <el-color-picker v-model="diyStore.editComponent.pageEndBgColor" :predefine="diyStore.predefineColors" />
- </el-form-item>
- <div class="text-sm text-gray-400 ml-[90px] mb-[10px]">底部背景包含边距和圆角</div>
- </template>
- <el-form-item label="渐变角度" v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
- <el-radio-group v-model="diyStore.editComponent.pageGradientAngle">
- <el-radio value="to bottom">从上到下</el-radio>
- <el-radio value="to right">从左到右</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="组件背景色" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
- <el-color-picker v-model="diyStore.editComponent.componentStartBgColor" :predefine="diyStore.predefineColors" />
- <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
- <el-color-picker v-model="diyStore.editComponent.componentEndBgColor" :predefine="diyStore.predefineColors" />
- </el-form-item>
- <el-form-item label="渐变角度" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
- <el-radio-group v-model="diyStore.editComponent.componentGradientAngle">
- <el-radio value="to bottom">从上到下</el-radio>
- <el-radio value="to right">从左到右</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="上边距" v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
- <el-slider v-model="diyStore.editComponent.padding.top" show-input size="small" :min="0" class="ml-[10px] diy-nav-slider" />
- </el-form-item>
- <el-form-item label="下边距" v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
- <el-slider
- v-model="diyStore.editComponent.padding.bottom"
- show-input
- size="small"
- class="ml-[10px] diy-nav-slider"
- :min="0"
- />
- </el-form-item>
- <el-form-item label="左右边距" v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
- <el-slider v-model="diyStore.editComponent.padding.both" show-input size="small" class="ml-[10px] diy-nav-slider" />
- </el-form-item>
- <el-form-item label="上圆角" v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
- <el-slider v-model="diyStore.editComponent.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
- </el-form-item>
- <el-form-item label="下圆角" v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
- <el-slider
- v-model="diyStore.editComponent.bottomRounded"
- show-input
- size="small"
- class="ml-[10px] diy-nav-slider"
- :max="100"
- />
- </el-form-item>
- <el-form-item label="上间距">
- <el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="0" class="ml-[10px] diy-nav-slider" />
- </el-form-item>
- <el-form-item label="下间距">
- <el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] diy-nav-slider" :min="0" />
- </el-form-item>
- </el-form>
- </div>
- </template>
- </component>
- <pagesEdit v-if="diyStore.currentIndex == -99"></pagesEdit>
- </div>
- </el-card>
- </el-scrollbar>
- <!-- <div v-for="(item, index) in diyStore.componentList" :key="index">
- <component v-if="item.itemKey == diyStore.currentKey" :is="item.edit" :value="item"> </component>
- </div> -->
- </div>
- </div>
- </div>
- </template>
- <script setup name="Index" lang="ts">
- import { pcAddDiy, pcEditDiy, pcLookDiy } from '@/api/diy/index';
- import icon from '@/components/icon/index.vue';
- import draggable from 'vuedraggable';
- import { getComponentGroups } from '@/views/diy/pccomponents/index';
- import usePcdiyStore from '@/store/modules/pcdiy';
- import pagesEdit from '@/views/diy/pccomponents/edit/pages-edit.vue';
- // const pagesEditRef = shallowRef(pagesEdit);
- const diyStore = usePcdiyStore();
- const route = useRoute();
- const query = route.query;
- const loading = ref<any>(false);
- const id = ref<any>(null);
- const activeNames = ref<any>([0]);
- const collapse = ref<any>([]);
- const siteId = ref<any>(null);
- const clientId = ref<any>(null);
- onMounted(() => {
- if (query.id) {
- id.value = query.id;
- } else {
- id.value = null;
- diyStore.type = query.type;
- diyStore.name = query.title;
- diyStore.backgroundColor = '#f2f2f2';
- diyStore.hoverColor = '#E7000B';
- if (query.siteId) siteId.value = query.siteId;
- if (query.clientId) {
- clientId.value = query.clientId;
- diyStore.clientId = query.clientId;
- }
- }
- loadComponents();
- });
- // 加载组件
- const loadComponents = async () => {
- collapse.value = getComponentGroups();
- if (id.value) {
- pcLookDiy(id.value).then((res) => {
- if (res.code == 200) {
- diyStore.name = res.data.name;
- diyStore.type = res.data.type;
- diyStore.backgroundColor = res.data.backgroundColor ? res.data.backgroundColor : '#f2f2f2';
- diyStore.hoverColor = res.data.hoverColor ? res.data.hoverColor : '#E7000B';
- diyStore.currentIndex = -99;
- if (res.data.clientId) diyStore.clientId = res.data.clientId;
- const datas = JSON.parse(res.data.property);
- collapse.value.forEach((item1: any) => {
- datas.forEach((item2: any) => {
- if (item1.id == item2.fid) {
- item1.list.forEach((item3: any) => {
- if (item2.id == item3.id) {
- item2.components = item3.components;
- item2.edit = item3.edit;
- }
- });
- }
- });
- });
- diyStore.componentList = datas;
- }
- });
- }
- };
- const onDragMove = (evt: any) => {
- const { willInsertAfter } = evt;
- // 获取被拖动元素的数据 (注意:不同版本 vuedraggable 获取数据的方式可能略有不同,通常是 dragged.context.element)
- const draggedElement = evt.draggedContext.element;
- // console.log(draggedElement, '456465');
- // 获取目标位置元素的数据
- const relatedElement = evt.relatedContext.element;
- // 规则 1: 如果正在拖动的是 ID 为 1 的头部组件 -> 禁止拖动
- if (draggedElement.id === 1) {
- return false;
- }
- // 规则 2: 如果试图将组件移动到 ID 为 1 的头部组件 之前 (即插队到第 0 位)
- // willInsertAfter: true 表示要插在 related 后面,false 表示插在前面
- if (relatedElement.id === 1 && !willInsertAfter) {
- return false; // 阻止插队到头部前面
- }
- // 允许其他所有移动
- return true;
- };
- const handleChange = (val: string[]) => {};
- // 返回上一页
- const goBack = () => {
- let url = 'platformDiyIndex'; //默认到平台微页面 防止404
- if (diyStore.type == '1') {
- //平台微页面
- url = 'platformDiyIndex';
- } else if (diyStore.type == '2') {
- //工业品微页面
- url = 'industryDiyIndex';
- } else if (diyStore.type == '3') {
- //福礼微页面
- url = 'fuliDiyIndex';
- } else if (diyStore.type == '5') {
- //pc微页面
- url = 'pcDiyIndex';
- }
- location.href = `${location.origin}/diy/` + url;
- };
- // 预览
- const preview = () => {
- save(1);
- };
- // 保存
- const save = (type?: number) => {
- const datas: any = {
- name: diyStore.name,
- siteId: siteId.value,
- clientId: query.clientId,
- type: diyStore.type,
- remark: '',
- previewPicUrls: '',
- hoverColor: diyStore.hoverColor,
- backgroundColor: diyStore.backgroundColor,
- property: JSON.stringify(diyStore.componentList),
- isHome: 1
- };
- loading.value = true;
- const api = id.value ? pcEditDiy : pcAddDiy;
- if (id.value) {
- datas.id = id.value;
- }
- api(datas)
- .then((res: any) => {
- loading.value = false;
- if (res.code == 200) {
- ElMessage({
- message: '保存成功~',
- type: 'success'
- });
- if (type == 1) {
- window.open('/diy/pcdiy?id=' + res.data.id);
- }
- }
- })
- .catch(() => {});
- };
- </script>
- <style lang="scss" scoped>
- .pcEdit-pages {
- // min-height: calc(100vh - 84px);
- min-width: 2000px;
- height: calc(100vh);
- .full-container {
- height: calc(100vh - 50px);
- background-color: #f2f2f2;
- .component-list {
- height: 100%;
- background-color: #ffffff;
- padding: 0 10px;
- min-width: 190px;
- width: 190px;
- }
- .component-list ul li {
- &:not(.disabled):hover {
- color: var(--el-color-primary);
- background: var(--el-color-primary-light-9);
- }
- }
- .preview-wrap {
- flex: 1;
- display: flex;
- justify-content: center;
- .preview-box {
- width: 1350px;
- position: relative;
- }
- .preview-pages {
- // margin: 30px auto;
- width: 1300px;
- background: var(--el-bg-color-page);
- overflow-y: auto;
- // height: calc(130vh - 194px);
- // zoom: 0.7;
- // height: calc(100vh - 194px);
- height: 100%;
- padding-top: 15px;
- /* 为了兼容某些情况,可能还需要配合 display */
- display: inline-block;
- padding-bottom: 30px;
- .component-bos {
- position: relative;
- .component-box {
- position: absolute;
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- border: 2px solid var(--el-color-primary);
- z-index: 2;
- cursor: move;
- }
- }
- }
- .quick-action {
- background: var(--el-bg-color);
- position: absolute;
- top: 20px;
- right: 0px;
- }
- }
- //编辑组件属性区域
- .edit-attribute-wrap {
- width: 400px;
- min-width: 400px;
- background: var(--el-bg-color);
- }
- .edit-attribute-wrap .box-card {
- border: none;
- }
- .edit-attr-item-wrap {
- border-top: 2px solid var(--el-color-info-light-8);
- padding-top: 20px;
- &:first-of-type {
- border-top: none;
- padding-top: 0;
- }
- }
- }
- :deep(.el-header) {
- height: 50px;
- }
- }
- </style>
|