营销:装修页面适配搜索框

(cherry picked from commit aedf014407)
This commit is contained in:
owen 2023-11-04 22:06:40 +08:00 committed by shizhong
parent b2e9e9273d
commit 8cb041b57a
9 changed files with 332 additions and 90 deletions

View File

@ -0,0 +1,45 @@
<template>
<div
:style="{
...style,
background: property.bgType === 'color' ? property.bgColor : `url(${property.bgImg})`
}"
>
<slot></slot>
</div>
</template>
<script setup lang="ts">
import { ComponentStyle } from '@/components/DiyEditor/util'
/**
* 组件容器
* 用于包裹组件为组件提供 背景外边距内边距边框等样式
*/
defineOptions({ name: 'ComponentContainer' })
const props = defineProps<{ property: ComponentStyle }>()
const style = computed(() => {
if (!props.property) {
return {}
}
return {
marginTop: `${props.property.marginTop || 0}px`,
marginBottom: `${props.property.marginBottom || 0}px`,
marginLeft: `${props.property.marginLeft || 0}px`,
marginRight: `${props.property.marginRight || 0}px`,
paddingTop: `${props.property.paddingTop || 0}px`,
paddingRight: `${props.property.paddingRight || 0}px`,
paddingBottom: `${props.property.paddingBottom || 0}px`,
paddingLeft: `${props.property.paddingLeft || 0}px`,
borderTopLeftRadius: `${props.property.borderTopLeftRadius || 0}px`,
borderTopRightRadius: `${props.property.borderTopRightRadius || 0}px`,
borderBottomRightRadius: `${props.property.borderBottomRightRadius || 0}px`,
borderBottomLeftRadius: `${props.property.borderBottomLeftRadius || 0}px`,
overflow: 'hidden'
}
})
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,164 @@
<template>
<el-tabs stretch>
<el-tab-pane label="内容">
<slot></slot>
</el-tab-pane>
<el-tab-pane label="样式" lazy>
<el-card header="组件样式" class="property-group">
<el-form :model="formData" label-width="80px">
<el-form-item label="组件背景" prop="bgType">
<el-radio-group v-model="formData.bgType">
<el-radio label="color">纯色</el-radio>
<el-radio label="img">图片</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="选择颜色" prop="bgColor" v-if="formData.bgType === 'color'">
<ColorInput v-model="formData.bgColor" />
</el-form-item>
<el-form-item label="上传图片" prop="bgImg" v-else>
<UploadImg v-model="formData.bgImg" :limit="1">
<template #tip>建议宽度 750px</template>
</UploadImg>
</el-form-item>
<el-tree :data="treeData" :expand-on-click-node="false">
<template #default="{ node, data }">
<el-form-item
:label="data.label"
:prop="data.prop"
:label-width="node.level === 1 ? '80px' : '62px'"
class="tree-form-item w-full m-b-0!"
>
<el-slider
v-model="formData[data.prop]"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
@input="handleSliderChange(data.prop)"
/>
</el-form-item>
</template>
</el-tree>
</el-form>
</el-card>
</el-tab-pane>
</el-tabs>
</template>
<script setup lang="ts">
import { ComponentStyle, usePropertyForm } from '@/components/DiyEditor/util'
/**
* 组件容器属性
* 用于包裹组件为组件提供 背景外边距内边距边框等样式
*/
defineOptions({ name: 'ComponentContainer' })
const props = defineProps<{ modelValue: ComponentStyle }>()
const emit = defineEmits(['update:modelValue'])
const { formData } = usePropertyForm(props.modelValue, emit)
const treeData = [
{
label: '外部边距',
prop: 'margin',
children: [
{
label: '上',
prop: 'marginTop'
},
{
label: '右',
prop: 'marginRight'
},
{
label: '下',
prop: 'marginBottom'
},
{
label: '左',
prop: 'marginLeft'
}
]
},
{
label: '内部边距',
prop: 'padding',
children: [
{
label: '上',
prop: 'paddingTop'
},
{
label: '右',
prop: 'paddingRight'
},
{
label: '下',
prop: 'paddingBottom'
},
{
label: '左',
prop: 'paddingLeft'
}
]
},
{
label: '边框圆角',
prop: 'borderRadius',
children: [
{
label: '上左',
prop: 'borderTopLeftRadius'
},
{
label: '上右',
prop: 'borderTopRightRadius'
},
{
label: '下右',
prop: 'borderBottomRightRadius'
},
{
label: '下左',
prop: 'borderBottomLeftRadius'
}
]
}
]
const handleSliderChange = (prop: string) => {
switch (prop) {
case 'margin':
formData.value.marginTop = formData.value.margin
formData.value.marginRight = formData.value.margin
formData.value.marginBottom = formData.value.margin
formData.value.marginLeft = formData.value.margin
break
case 'padding':
formData.value.paddingTop = formData.value.padding
formData.value.paddingRight = formData.value.padding
formData.value.paddingBottom = formData.value.padding
formData.value.paddingLeft = formData.value.padding
break
case 'borderRadius':
formData.value.borderTopLeftRadius = formData.value.borderRadius
formData.value.borderTopRightRadius = formData.value.borderRadius
formData.value.borderBottomRightRadius = formData.value.borderRadius
formData.value.borderBottomLeftRadius = formData.value.borderRadius
break
}
}
</script>
<style scoped lang="scss">
.tree-form-item {
:deep(.el-slider__runway) {
margin-right: 16px;
}
:deep(.el-input-number) {
width: 50px;
}
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<el-aside class="editor-left" width="260px">
<el-aside class="editor-left" width="261px">
<el-scrollbar>
<el-collapse v-model="extendGroups">
<el-collapse-item

View File

@ -29,7 +29,7 @@ export const component = {
title: '页面标题',
description: '',
navBarHeight: 35,
backgroundColor: '#f5f5f5',
backgroundColor: '#fff',
backgroundImage: '',
styleType: 'default',
alwaysShow: true,

View File

@ -1,4 +1,4 @@
import { DiyComponent } from '@/components/DiyEditor/util'
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
/** 搜索框属性 */
export interface SearchProperty {
@ -7,10 +7,10 @@ export interface SearchProperty {
borderRadius: number // 框体样式
placeholder: string // 占位文字
placeholderPosition: PlaceholderPosition // 占位文字位置
backgroundColor: string // 背景颜色
borderColor: string // 框体颜色
backgroundColor: string // 框体颜色
textColor: string // 字体颜色
hotKeywords: string[] // 热词
style: ComponentStyle
}
// 文字位置
@ -27,9 +27,17 @@ export const component = {
borderRadius: 0,
placeholder: '搜索商品',
placeholderPosition: 'left',
backgroundColor: 'rgb(249, 249, 249)',
borderColor: 'rgb(255, 255, 255)',
backgroundColor: 'rgb(238, 238, 238)',
textColor: 'rgb(150, 151, 153)',
hotKeywords: []
hotKeywords: [],
style: {
bgType: 'color',
bgColor: '#fff',
marginBottom: 8,
paddingTop: 8,
paddingRight: 8,
paddingBottom: 8,
paddingLeft: 8
} as ComponentStyle
}
} as DiyComponent<SearchProperty>

View File

@ -2,8 +2,6 @@
<div
class="search-bar"
:style="{
background: property.backgroundColor,
border: `1px solid ${property.backgroundColor}`,
color: property.textColor
}"
>
@ -12,7 +10,7 @@
class="inner"
:style="{
height: `${property.height}px`,
background: property.borderColor,
background: property.backgroundColor,
borderRadius: `${property.borderRadius}px`
}"
>
@ -44,13 +42,11 @@ defineProps<{ property: SearchProperty }>()
<style scoped lang="scss">
.search-bar {
position: relative;
width: 375px;
/* 搜索框 */
.inner {
position: relative;
width: calc(100% - 16px);
min-height: 28px;
margin: 5px auto;
display: flex;
align-items: center;
font-size: 14px;

View File

@ -1,78 +1,77 @@
<template>
<el-text tag="p"> 搜索热词 </el-text>
<el-text type="info" size="small"> 拖动左侧的小圆点可以调整热词顺序 </el-text>
<ComponentContainerProperty v-model="formData.style">
<el-text tag="p"> 搜索热词 </el-text>
<el-text type="info" size="small"> 拖动左侧的小圆点可以调整热词顺序 </el-text>
<!-- 表单 -->
<el-form label-width="80px" :model="formData" class="m-t-8px">
<div v-if="formData.hotKeywords.length">
<VueDraggable
:list="formData.hotKeywords"
item-key="index"
handle=".drag-icon"
:forceFallback="true"
:animation="200"
>
<template #item="{ index }">
<div class="mb-4px flex flex-row items-center gap-4px rounded bg-gray-100 p-8px">
<Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" />
<el-input v-model="formData.hotKeywords[index]" placeholder="请输入热词" />
<Icon icon="ep:delete" class="text-red-500" @click="deleteHotWord(index)" />
</div>
</template>
</VueDraggable>
</div>
<el-form-item label-width="0">
<el-button @click="handleAddHotWord" type="primary" plain class="m-t-8px w-full">
添加热词
</el-button>
</el-form-item>
<el-form-item label="框体样式">
<el-radio-group v-model="formData!.borderRadius">
<el-tooltip content="方形" placement="top">
<el-radio-button :label="0">
<Icon icon="tabler:input-search" />
</el-radio-button>
</el-tooltip>
<el-tooltip content="圆形" placement="top">
<el-radio-button :label="10">
<Icon icon="iconoir:input-search" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item label="提示文字" prop="placeholder">
<el-input v-model="formData.placeholder" />
</el-form-item>
<el-form-item label="文本位置" prop="placeholderPosition">
<el-radio-group v-model="formData!.placeholderPosition">
<el-tooltip content="居左" placement="top">
<el-radio-button label="left">
<Icon icon="ant-design:align-left-outlined" />
</el-radio-button>
</el-tooltip>
<el-tooltip content="居中" placement="top">
<el-radio-button label="center">
<Icon icon="ant-design:align-center-outlined" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item label="扫一扫" prop="showScan">
<el-switch v-model="formData!.showScan" />
</el-form-item>
<el-form-item label="框体高度" prop="height">
<el-slider v-model="formData!.height" :max="50" :min="28" show-input input-size="small" />
</el-form-item>
<el-form-item label="背景颜色" prop="backgroundColor">
<ColorInput v-model="formData.backgroundColor" />
</el-form-item>
<el-form-item label="框体颜色" prop="borderColor">
<ColorInput v-model="formData.borderColor" />
</el-form-item>
<el-form-item class="lef" label="文本颜色" prop="textColor">
<ColorInput v-model="formData.textColor" />
</el-form-item>
</el-form>
<!-- 表单 -->
<el-form label-width="80px" :model="formData" class="m-t-8px">
<div v-if="formData.hotKeywords.length">
<VueDraggable
:list="formData.hotKeywords"
item-key="index"
handle=".drag-icon"
:forceFallback="true"
:animation="200"
>
<template #item="{ index }">
<div class="mb-4px flex flex-row items-center gap-4px rounded bg-gray-100 p-8px">
<Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" />
<el-input v-model="formData.hotKeywords[index]" placeholder="请输入热词" />
<Icon icon="ep:delete" class="text-red-500" @click="deleteHotWord(index)" />
</div>
</template>
</VueDraggable>
</div>
<el-form-item label-width="0">
<el-button @click="handleAddHotWord" type="primary" plain class="m-t-8px w-full">
添加热词
</el-button>
</el-form-item>
<el-form-item label="框体样式">
<el-radio-group v-model="formData!.borderRadius">
<el-tooltip content="方形" placement="top">
<el-radio-button :label="0">
<Icon icon="tabler:input-search" />
</el-radio-button>
</el-tooltip>
<el-tooltip content="圆形" placement="top">
<el-radio-button :label="10">
<Icon icon="iconoir:input-search" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item label="提示文字" prop="placeholder">
<el-input v-model="formData.placeholder" />
</el-form-item>
<el-form-item label="文本位置" prop="placeholderPosition">
<el-radio-group v-model="formData!.placeholderPosition">
<el-tooltip content="居左" placement="top">
<el-radio-button label="left">
<Icon icon="ant-design:align-left-outlined" />
</el-radio-button>
</el-tooltip>
<el-tooltip content="居中" placement="top">
<el-radio-button label="center">
<Icon icon="ant-design:align-center-outlined" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item label="扫一扫" prop="showScan">
<el-switch v-model="formData!.showScan" />
</el-form-item>
<el-form-item label="框体高度" prop="height">
<el-slider v-model="formData!.height" :max="50" :min="28" show-input input-size="small" />
</el-form-item>
<el-form-item label="框体颜色" prop="backgroundColor">
<ColorInput v-model="formData.backgroundColor" />
</el-form-item>
<el-form-item class="lef" label="文本颜色" prop="textColor">
<ColorInput v-model="formData.textColor" />
</el-form-item>
</el-form>
</ComponentContainerProperty>
</template>
<script setup lang="ts">

View File

@ -427,11 +427,13 @@ $phone-width: 375px;
padding: 8px 16px;
}
/* 属性面板分组 */
.property-group {
/* 属性分组 */
:deep(.el-card__header) {
:deep(.property-group) {
margin: 0 -20px;
/* 属性分组名称 */
.el-card__header {
border: none;
background: var(--el-bg-color-page);
padding: 8px 32px;
}
}
}

View File

@ -16,6 +16,34 @@ export interface DiyComponentLibrary {
components: string[]
}
// 组件样式
export interface ComponentStyle {
// 背景类型
bgType: 'color' | 'img'
// 背景颜色
bgColor: string
// 背景图片
bgImg: string
// 外边距
margin: number
marginTop: number
marginRight: number
marginBottom: number
marginLeft: number
// 内边距
padding: number
paddingTop: number
paddingRight: number
paddingBottom: number
paddingLeft: number
// 边框圆角
borderRadius: number
borderTopLeftRadius: number
borderTopRightRadius: number
borderBottomRightRadius: number
borderBottomLeftRadius: number
}
// 页面配置
export interface PageConfig {
// 页面属性