!301 营销:完善商城装修

Merge pull request !301 from 疯狂的世界/dev
This commit is contained in:
芋道源码 2023-11-01 00:48:16 +00:00 committed by Gitee
commit 20c59b8122
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
7 changed files with 282 additions and 178 deletions

View File

@ -33,3 +33,13 @@ export const updateDiyPage = async (data: DiyPageVO) => {
export const deleteDiyPage = async (id: number) => { export const deleteDiyPage = async (id: number) => {
return await request.delete({ url: `/promotion/diy-page/delete?id=` + id }) return await request.delete({ url: `/promotion/diy-page/delete?id=` + id })
} }
// 获得装修页面属性
export const getDiyPageProperty = async (id: number) => {
return await request.get({ url: `/promotion/diy-page/get-property?id=` + id })
}
// 更新装修页面属性
export const updateDiyPageProperty = async (data: DiyPageVO) => {
return await request.put({ url: `/promotion/diy-page/update-property`, data })
}

View File

@ -1,4 +1,5 @@
import request from '@/config/axios' import request from '@/config/axios'
import { DiyPageVO } from '@/api/mall/promotion/diy/page'
export interface DiyTemplateVO { export interface DiyTemplateVO {
id?: number id?: number
@ -10,6 +11,10 @@ export interface DiyTemplateVO {
property: string property: string
} }
export interface DiyTemplatePropertyVO extends DiyTemplateVO {
pages: DiyPageVO[]
}
// 查询装修模板列表 // 查询装修模板列表
export const getDiyTemplatePage = async (params: any) => { export const getDiyTemplatePage = async (params: any) => {
return await request.get({ url: `/promotion/diy-template/page`, params }) return await request.get({ url: `/promotion/diy-template/page`, params })
@ -39,3 +44,15 @@ export const deleteDiyTemplate = async (id: number) => {
export const useDiyTemplate = async (id: number) => { export const useDiyTemplate = async (id: number) => {
return await request.put({ url: `/promotion/diy-template/use?id=` + id }) return await request.put({ url: `/promotion/diy-template/use?id=` + id })
} }
// 获得装修模板属性
export const getDiyTemplateProperty = async (id: number) => {
return await request.get<DiyTemplatePropertyVO>({
url: `/promotion/diy-template/get-property?id=` + id
})
}
// 更新装修模板属性
export const updateDiyTemplateProperty = async (data: DiyTemplateVO) => {
return await request.put({ url: `/promotion/diy-template/update-property`, data })
}

View File

@ -40,7 +40,6 @@ defineProps<{ property: NavigationBarProperty }>()
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
cursor: pointer;
/* 左边 */ /* 左边 */
.left { .left {
margin-left: 8px; margin-left: 8px;

View File

@ -1,6 +1,6 @@
<template> <template>
<div <div
class="flex items-center text-12px" class="flex items-center p-y-4px text-12px"
:style="{ backgroundColor: property.backgroundColor, color: property.textColor }" :style="{ backgroundColor: property.backgroundColor, color: property.textColor }"
> >
<el-image :src="property.iconUrl" class="h-18px" /> <el-image :src="property.iconUrl" class="h-18px" />

View File

@ -45,6 +45,7 @@
@click="handleNavigationBarSelected" @click="handleNavigationBarSelected"
:class="[ :class="[
'component', 'component',
'cursor-pointer!',
{ active: selectedComponent?.id === navigationBarComponent.id } { active: selectedComponent?.id === navigationBarComponent.id }
]" ]"
/> />
@ -59,7 +60,7 @@
}" }"
> >
<draggable <draggable
class="drag-area page-prop-area" class="page-prop-area drag-area"
v-model="pageComponents" v-model="pageComponents"
item-key="index" item-key="index"
:animation="200" :animation="200"
@ -70,7 +71,7 @@
@change="handleComponentChange" @change="handleComponentChange"
> >
<template #item="{ element, index }"> <template #item="{ element, index }">
<div class="component-box" @click="handleComponentSelected(element, index)"> <div class="component-container" @click="handleComponentSelected(element, index)">
<!-- 左侧组件名 --> <!-- 左侧组件名 -->
<div <div
:class="['component-name', { active: selectedComponentIndex === index }]" :class="['component-name', { active: selectedComponentIndex === index }]"
@ -79,12 +80,13 @@
{{ element.name }} {{ element.name }}
</div> </div>
<!-- 组件内容区 --> <!-- 组件内容区 -->
<div :class="['component', { active: selectedComponentIndex === index }]">
<component <component
:is="element.id" :is="element.id"
:property="element.property" :property="element.property"
:class="['component', { active: selectedComponentIndex === index }]"
:data-type="element.id" :data-type="element.id"
/> />
</div>
<!-- 左侧组件操作工具栏 --> <!-- 左侧组件操作工具栏 -->
<div <div
class="component-toolbar" class="component-toolbar"
@ -130,6 +132,7 @@
:class="[ :class="[
'editor-design-bottom', 'editor-design-bottom',
'component', 'component',
'cursor-pointer!',
{ active: selectedComponent?.id === tabBarComponent.id } { active: selectedComponent?.id === tabBarComponent.id }
]" ]"
> >
@ -200,18 +203,25 @@ const navigationBarComponent = ref<DiyComponent<any>>(cloneDeep(NAVIGATION_BAR_C
const tabBarComponent = ref<DiyComponent<any>>(cloneDeep(TAB_BAR_COMPONENT)) const tabBarComponent = ref<DiyComponent<any>>(cloneDeep(TAB_BAR_COMPONENT))
// //
const selectedComponent = ref<DiyComponent<any>>(unref(pageConfigComponent)) const selectedComponent = ref<DiyComponent<any>>()
// //
const selectedComponentIndex = ref<number>(-1) const selectedComponentIndex = ref<number>(-1)
// //
const pageComponents = ref<DiyComponent<any>[]>([]) const pageComponents = ref<DiyComponent<any>[]>([])
// //
const props = defineProps<{ const props = defineProps<{
// Json
modelValue: string | PageConfig modelValue: string | PageConfig
//
title: string title: string
libs: DiyComponentLibrary[] // //
libs: DiyComponentLibrary[]
//
showNavigationBar: boolean showNavigationBar: boolean
//
showTabBar: boolean showTabBar: boolean
//
showPageConfig: boolean
}>() }>()
// //
@ -255,6 +265,8 @@ const handleSave = () => {
// //
const handlePageSelected = (event: any) => { const handlePageSelected = (event: any) => {
if (!props.showPageConfig) return
// page-prop-area // page-prop-area
if (includes(event?.target?.classList, 'page-prop-area')) { if (includes(event?.target?.classList, 'page-prop-area')) {
handleComponentSelected(unref(pageConfigComponent)) handleComponentSelected(unref(pageConfigComponent))
@ -351,14 +363,33 @@ const handlePreview = () => {
message.warning('开发中~') message.warning('开发中~')
emits('preview') emits('preview')
} }
//
const setDefaultSelectedComponent = () => {
if (props.showPageConfig) {
selectedComponent.value = unref(pageConfigComponent)
} else if (props.showNavigationBar) {
selectedComponent.value = unref(navigationBarComponent)
} else if (props.showTabBar) {
selectedComponent.value = unref(tabBarComponent)
}
}
watch(
() => [props.showPageConfig, props.showNavigationBar, props.showTabBar],
() => setDefaultSelectedComponent()
)
onMounted(() => setDefaultSelectedComponent())
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 手机宽度 */
$phone-width: 375px;
/* 根节点样式 */
.editor { .editor {
height: 100%; height: 100%;
margin: calc(0px - var(--app-content-padding)); margin: calc(0px - var(--app-content-padding));
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} /* 顶部:工具栏 */
.editor-header { .editor-header {
display: flex; display: flex;
align-items: center; align-items: center;
@ -367,14 +398,14 @@ const handlePreview = () => {
padding: 0; padding: 0;
border-bottom: solid 1px var(--el-border-color); border-bottom: solid 1px var(--el-border-color);
background-color: var(--el-bg-color); background-color: var(--el-bg-color);
/* 工具栏:右侧按钮 */
.header-right { .header-right {
height: 100%; height: 100%;
.el-button { .el-button {
height: 100%; height: 100%;
} }
} }
/* 隐藏工具栏按钮的边框 */
:deep(.el-radio-button__inner), :deep(.el-radio-button__inner),
:deep(.el-button) { :deep(.el-button) {
border-top: none !important; border-top: none !important;
@ -382,6 +413,7 @@ const handlePreview = () => {
border-radius: 0 !important; border-radius: 0 !important;
} }
} }
/* 中心操作区 */
.editor-container { .editor-container {
height: calc( height: calc(
100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 42px 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 42px
@ -390,11 +422,11 @@ const handlePreview = () => {
.editor-right { .editor-right {
flex-shrink: 0; flex-shrink: 0;
box-shadow: -8px 0 8px -8px rgba(0, 0, 0, 0.12); box-shadow: -8px 0 8px -8px rgba(0, 0, 0, 0.12);
/* 属性面板顶部:减少内边距 */
:deep(.el-card__header) { :deep(.el-card__header) {
padding: 8px 16px; padding: 8px 16px;
} }
/* 属性面板分组 */
.property-group { .property-group {
/* 属性分组 */ /* 属性分组 */
:deep(.el-card__header) { :deep(.el-card__header) {
@ -404,14 +436,14 @@ const handlePreview = () => {
} }
} }
/* 中心 */ /* 中心区域 */
.editor-center { .editor-center {
flex: 1 1 0; flex: 1 1 0;
padding: 16px 0; padding: 16px 0;
background-color: var(--app-content-bg-color); background-color: var(--app-content-bg-color);
display: flex; display: flex;
justify-content: center; justify-content: center;
/* 中心设计区域 */
.editor-design { .editor-design {
position: relative; position: relative;
height: 100%; height: 100%;
@ -424,34 +456,32 @@ const handlePreview = () => {
/* 组件 */ /* 组件 */
.component { .component {
border: 1px solid #fff; border: 1px solid #fff;
width: 375px !important; width: $phone-width;
cursor: move;
/* 鼠标放到组件上时 */
&:hover { &:hover {
border: 1px dashed #155bd4; border: 1px dashed var(--el-color-primary);
} }
} }
/* 组件选中 */
.component.active { .component.active {
border: 2px solid #155bd4 !important; border: 2px solid var(--el-color-primary);
} }
/* 手机顶部 */
.editor-design-top { .editor-design-top {
width: 379px; width: $phone-width;
/* 手机顶部状态栏 */
.status-bar { .status-bar {
height: 20px; height: 20px;
width: 100%; width: $phone-width;
background-color: #fff; background-color: #fff;
} }
.navigation-bar {
width: 100%;
} }
} /* 手机底部导航 */
.editor-design-bottom { .editor-design-bottom {
width: 379px; width: $phone-width;
} }
/* 手机页面编辑区域 */
.editor-design-center { .editor-design-center {
width: 100%; width: 100%;
flex: 1 1 0; flex: 1 1 0;
@ -464,22 +494,20 @@ const handlePreview = () => {
.phone-container { .phone-container {
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
cursor: move;
position: relative; position: relative;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
width: 379px; width: $phone-width;
margin: 0 auto; margin: 0 auto;
.drag-area { .drag-area {
height: 100%; height: 100%;
} }
/* 组件容器 */ /* 组件容器(左侧:组件名称,中间:组件,右侧:操作工具栏) */
.component-box { .component-container {
width: 100%; width: 100%;
position: relative; position: relative;
/* 组件名称 */ /* 左侧:组件名称 */
.component-name { .component-name {
position: absolute; position: absolute;
width: 80px; width: 80px;
@ -488,23 +516,50 @@ const handlePreview = () => {
height: 25px; height: 25px;
background: #fff; background: #fff;
font-size: 12px; font-size: 12px;
left: -80px; left: -85px;
top: 0; top: 0;
box-shadow: box-shadow:
0 0 4px #00000014, 0 0 4px #00000014,
0 2px 6px #0000000f, 0 2px 6px #0000000f,
0 4px 8px 2px #0000000a; 0 4px 8px 2px #0000000a;
/* 右侧小三角 */
&:after {
position: absolute;
top: 7.5px;
right: -10px;
content: ' ';
height: 0;
width: 0;
border: 5px solid transparent;
border-left-color: #fff;
} }
}
/* 组件选中按钮 */
.component-name.active { .component-name.active {
background: #2d8cf0; background: var(--el-color-primary);
color: #fff; color: #fff;
&:after {
border-left-color: var(--el-color-primary);
} }
/* 组件操作按钮 */ }
/* 右侧:组件操作工具栏 */
.component-toolbar { .component-toolbar {
position: absolute; position: absolute;
top: 0; top: 0;
right: -50px; right: -57px;
/* 左侧小三角 */
&:before {
position: absolute;
top: 10px;
left: -10px;
content: ' ';
height: 0;
width: 0;
border: 5px solid transparent;
border-right-color: #2d8cf0;
}
/* 重写 Element 按钮组的样式(官方只支持水平显示,增加垂直显示的样式) */
.el-button-group { .el-button-group {
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
@ -536,4 +591,5 @@ const handlePreview = () => {
} }
} }
} }
}
</style> </style>

View File

@ -4,6 +4,7 @@
v-model="formData.property" v-model="formData.property"
:title="formData.name" :title="formData.name"
:libs="componentLibs" :libs="componentLibs"
:show-page-config="true"
:show-navigation-bar="true" :show-navigation-bar="true"
:show-tab-bar="false" :show-tab-bar="false"
@save="submitForm" @save="submitForm"
@ -51,7 +52,7 @@ const formRef = ref() // 表单 Ref
const getPageDetail = async (id: any) => { const getPageDetail = async (id: any) => {
formLoading.value = true formLoading.value = true
try { try {
formData.value = await DiyPageApi.getDiyPage(id) formData.value = await DiyPageApi.getDiyPageProperty(id)
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -63,7 +64,7 @@ const submitForm = async () => {
// //
formLoading.value = true formLoading.value = true
try { try {
await DiyPageApi.updateDiyPage(unref(formData)!) await DiyPageApi.updateDiyPageProperty(unref(formData)!)
message.success('保存成功') message.success('保存成功')
} finally { } finally {
formLoading.value = false formLoading.value = false

View File

@ -1,11 +1,12 @@
<template> <template>
<DiyEditor <DiyEditor
v-if="formData && !formLoading" v-if="formData && !formLoading"
v-model="formData.property" v-model="currentFormData!.property"
:title="templateItems[selectedTemplateItem].name" :title="templateItems[selectedTemplateItem].name"
:libs="libs" :libs="libs"
:show-page-config="selectedTemplateItem !== 0"
:show-tab-bar="selectedTemplateItem === 0" :show-tab-bar="selectedTemplateItem === 0"
:show-navigation-bar="selectedTemplateItem > 0" :show-navigation-bar="selectedTemplateItem !== 0"
@save="submitForm" @save="submitForm"
> >
<template #toolBarLeft> <template #toolBarLeft>
@ -25,6 +26,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import * as DiyTemplateApi from '@/api/mall/promotion/diy/template' import * as DiyTemplateApi from '@/api/mall/promotion/diy/template'
import * as DiyPageApi from '@/api/mall/promotion/diy/page'
import { useTagsViewStore } from '@/store/modules/tagsView' import { useTagsViewStore } from '@/store/modules/tagsView'
import { DiyComponentLibrary } from '@/components/DiyEditor/util' import { DiyComponentLibrary } from '@/components/DiyEditor/util'
@ -42,14 +44,17 @@ const templateItems = reactive([
const message = useMessage() // const message = useMessage() //
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formData = ref<DiyTemplateApi.DiyTemplateVO>() const formData = ref<DiyTemplateApi.DiyTemplatePropertyVO>()
const formRef = ref() // Ref const formRef = ref() // Ref
//
const currentFormData = ref<DiyTemplateApi.DiyTemplatePropertyVO | DiyPageApi.DiyPageVO>()
// //
const getPageDetail = async (id: any) => { const getPageDetail = async (id: any) => {
formLoading.value = true formLoading.value = true
try { try {
formData.value = await DiyTemplateApi.getDiyTemplate(id) formData.value = await DiyTemplateApi.getDiyTemplateProperty(id)
currentFormData.value = formData.value
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -82,12 +87,21 @@ const pageLibs = [
] as DiyComponentLibrary[] ] as DiyComponentLibrary[]
// //
const libs = ref<DiyComponentLibrary[]>(templateLibs) const libs = ref<DiyComponentLibrary[]>(templateLibs)
//
const handleTemplateItemChange = () => { const handleTemplateItemChange = () => {
//
if (selectedTemplateItem.value === 0) { if (selectedTemplateItem.value === 0) {
libs.value = templateLibs libs.value = templateLibs
} else { currentFormData.value = formData.value
libs.value = pageLibs return
} }
//
libs.value = pageLibs
currentFormData.value = formData.value!.pages.find(
(page: DiyPageApi.DiyPageVO) => page.name === templateItems[selectedTemplateItem.value].name
)
console.log(currentFormData.value)
} }
// //
@ -97,7 +111,13 @@ const submitForm = async () => {
// //
formLoading.value = true formLoading.value = true
try { try {
await DiyTemplateApi.updateDiyTemplate(unref(formData)!) if (selectedTemplateItem.value === 0) {
//
await DiyTemplateApi.updateDiyTemplateProperty(unref(formData)!)
} else {
//
await DiyPageApi.updateDiyPageProperty(unref(currentFormData)!)
}
message.success('保存成功') message.success('保存成功')
} finally { } finally {
formLoading.value = false formLoading.value = false
@ -113,8 +133,9 @@ const resetForm = () => {
usedTime: undefined, usedTime: undefined,
remark: '', remark: '',
previewImageUrls: [], previewImageUrls: [],
property: '' property: '',
} as DiyTemplateApi.DiyTemplateVO pages: []
} as DiyTemplateApi.DiyTemplatePropertyVO
formRef.value?.resetFields() formRef.value?.resetFields()
} }