Merge remote-tracking branch 'origin/dev' into dev
commit
c1534bf168
@ -0,0 +1,56 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
export interface CustomerVO {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
industryId: number
|
||||||
|
level: number
|
||||||
|
source: number
|
||||||
|
followUpStatus: boolean
|
||||||
|
lockStatus: boolean
|
||||||
|
mobile: string
|
||||||
|
telephone: string
|
||||||
|
website: string
|
||||||
|
qq: string
|
||||||
|
wechat: string
|
||||||
|
email: string
|
||||||
|
description: string
|
||||||
|
remark: string
|
||||||
|
ownerUserId: number
|
||||||
|
roUserIds: string
|
||||||
|
rwUserIds: string
|
||||||
|
areaId: number
|
||||||
|
detailAddress: string
|
||||||
|
contactLastTime: Date
|
||||||
|
contactNextTime: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询客户列表
|
||||||
|
export const getCustomerPage = async (params) => {
|
||||||
|
return await request.get({ url: `/crm/customer/page`, params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询客户详情
|
||||||
|
export const getCustomer = async (id: number) => {
|
||||||
|
return await request.get({ url: `/crm/customer/get?id=` + id })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增客户
|
||||||
|
export const createCustomer = async (data: CustomerVO) => {
|
||||||
|
return await request.post({ url: `/crm/customer/create`, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改客户
|
||||||
|
export const updateCustomer = async (data: CustomerVO) => {
|
||||||
|
return await request.put({ url: `/crm/customer/update`, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除客户
|
||||||
|
export const deleteCustomer = async (id: number) => {
|
||||||
|
return await request.delete({ url: `/crm/customer/delete?id=` + id })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出客户 Excel
|
||||||
|
export const exportCustomer = async (params) => {
|
||||||
|
return await request.download({ url: `/crm/customer/export-excel`, params })
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
export interface DiyPageVO {
|
||||||
|
id?: number
|
||||||
|
templateId?: number
|
||||||
|
name: string
|
||||||
|
remark: string
|
||||||
|
previewImageUrls: string[]
|
||||||
|
property: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询装修页面列表
|
||||||
|
export const getDiyPagePage = async (params: any) => {
|
||||||
|
return await request.get({ url: `/promotion/diy-page/page`, params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询装修页面详情
|
||||||
|
export const getDiyPage = async (id: number) => {
|
||||||
|
return await request.get({ url: `/promotion/diy-page/get?id=` + id })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增装修页面
|
||||||
|
export const createDiyPage = async (data: DiyPageVO) => {
|
||||||
|
return await request.post({ url: `/promotion/diy-page/create`, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改装修页面
|
||||||
|
export const updateDiyPage = async (data: DiyPageVO) => {
|
||||||
|
return await request.put({ url: `/promotion/diy-page/update`, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除装修页面
|
||||||
|
export const deleteDiyPage = async (id: number) => {
|
||||||
|
return await request.delete({ url: `/promotion/diy-page/delete?id=` + id })
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
export interface DiyTemplateVO {
|
||||||
|
id?: number
|
||||||
|
name: string
|
||||||
|
used: boolean
|
||||||
|
usedTime?: Date
|
||||||
|
remark: string
|
||||||
|
previewImageUrls: string[]
|
||||||
|
property: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询装修模板列表
|
||||||
|
export const getDiyTemplatePage = async (params: any) => {
|
||||||
|
return await request.get({ url: `/promotion/diy-template/page`, params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询装修模板详情
|
||||||
|
export const getDiyTemplate = async (id: number) => {
|
||||||
|
return await request.get({ url: `/promotion/diy-template/get?id=` + id })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增装修模板
|
||||||
|
export const createDiyTemplate = async (data: DiyTemplateVO) => {
|
||||||
|
return await request.post({ url: `/promotion/diy-template/create`, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改装修模板
|
||||||
|
export const updateDiyTemplate = async (data: DiyTemplateVO) => {
|
||||||
|
return await request.put({ url: `/promotion/diy-template/update`, data })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除装修模板
|
||||||
|
export const deleteDiyTemplate = async (id: number) => {
|
||||||
|
return await request.delete({ url: `/promotion/diy-template/delete?id=` + id })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用装修模板
|
||||||
|
export const useDiyTemplate = async (id: number) => {
|
||||||
|
return await request.put({ url: `/promotion/diy-template/use?id=` + id })
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<el-input v-model="color">
|
||||||
|
<template #prepend>
|
||||||
|
<el-color-picker v-model="color" :predefine="COLORS" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
// 颜色输入框
|
||||||
|
defineOptions({ name: 'ColorInput' })
|
||||||
|
|
||||||
|
// 预设颜色
|
||||||
|
const COLORS = [
|
||||||
|
'#ff4500',
|
||||||
|
'#ff8c00',
|
||||||
|
'#ffd700',
|
||||||
|
'#90ee90',
|
||||||
|
'#00ced1',
|
||||||
|
'#1e90ff',
|
||||||
|
'#c71585',
|
||||||
|
'#409EFF',
|
||||||
|
'#909399',
|
||||||
|
'#C0C4CC',
|
||||||
|
'#b7390b',
|
||||||
|
'#ff7800',
|
||||||
|
'#fad400',
|
||||||
|
'#5b8c5f',
|
||||||
|
'#00babd',
|
||||||
|
'#1f73c3',
|
||||||
|
'#711f57'
|
||||||
|
]
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: propTypes.string.def('')
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const color = computed({
|
||||||
|
get: () => {
|
||||||
|
return props.modelValue
|
||||||
|
},
|
||||||
|
set: (val: string) => {
|
||||||
|
emit('update:modelValue', val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
:deep(.el-input-group__prepend) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,196 @@
|
|||||||
|
<template>
|
||||||
|
<el-aside class="editor-left" width="260px">
|
||||||
|
<el-scrollbar>
|
||||||
|
<el-collapse v-model="extendGroups">
|
||||||
|
<el-collapse-item
|
||||||
|
v-for="group in groups"
|
||||||
|
:key="group.name"
|
||||||
|
:name="group.name"
|
||||||
|
:title="group.name"
|
||||||
|
>
|
||||||
|
<draggable
|
||||||
|
class="component-container"
|
||||||
|
ghost-class="draggable-ghost"
|
||||||
|
:list="group.components"
|
||||||
|
:sort="false"
|
||||||
|
:group="{ name: 'component', pull: 'clone', put: false }"
|
||||||
|
:clone="handleCloneComponent"
|
||||||
|
:animation="200"
|
||||||
|
:force-fallback="true"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<div>
|
||||||
|
<div class="drag-placement">组件放置区域</div>
|
||||||
|
<div class="component">
|
||||||
|
<Icon :icon="element.icon" :size="32" />
|
||||||
|
<span class="mt-4px text-12px">{{ element.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</el-scrollbar>
|
||||||
|
</el-aside>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
import { componentConfigs } from '../components/mobile/index'
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
import { DiyComponent, DiyComponentLibrary } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 组件库 */
|
||||||
|
defineOptions({ name: 'ComponentLibrary' })
|
||||||
|
|
||||||
|
// 组件列表
|
||||||
|
const props = defineProps<{
|
||||||
|
list: DiyComponentLibrary[]
|
||||||
|
}>()
|
||||||
|
const groups = reactive<any[]>([])
|
||||||
|
// 展开的折叠面板
|
||||||
|
const extendGroups = reactive<string[]>([])
|
||||||
|
watch(
|
||||||
|
() => props.list,
|
||||||
|
() => {
|
||||||
|
// 清除旧数据
|
||||||
|
extendGroups.length = 0
|
||||||
|
groups.length = 0
|
||||||
|
// 重新生成数据
|
||||||
|
props.list.forEach((group) => {
|
||||||
|
// 是否展开分组
|
||||||
|
if (group.extended) {
|
||||||
|
extendGroups.push(group.name)
|
||||||
|
}
|
||||||
|
// 查找组件
|
||||||
|
const components = group.components
|
||||||
|
.map((name) => componentConfigs[name] as DiyComponent<any>)
|
||||||
|
.filter((component) => component)
|
||||||
|
if (components.length > 0) {
|
||||||
|
groups.push({
|
||||||
|
name: group.name,
|
||||||
|
components
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 克隆组件
|
||||||
|
const handleCloneComponent = (component: DiyComponent<any>) => {
|
||||||
|
return cloneDeep(component)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.editor-left {
|
||||||
|
z-index: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-shadow: 8px 0 8px -8px rgba(0, 0, 0, 0.12);
|
||||||
|
|
||||||
|
:deep(.el-collapse) {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
:deep(.el-collapse-item__wrap) {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
:deep(.el-collapse-item__content) {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
:deep(.el-collapse-item__header) {
|
||||||
|
border-bottom: none;
|
||||||
|
background-color: var(--el-bg-color-page);
|
||||||
|
padding: 0 24px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.component {
|
||||||
|
width: 86px;
|
||||||
|
height: 86px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-right: 1px solid var(--el-border-color-lighter);
|
||||||
|
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||||
|
cursor: move;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.component.active,
|
||||||
|
.component:hover {
|
||||||
|
background: var(--el-color-primary);
|
||||||
|
color: var(--el-color-white);
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
color: var(--el-color-white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.component:nth-of-type(3n) {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 拖拽占位提示,默认不显示 */
|
||||||
|
.drag-placement {
|
||||||
|
display: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-area {
|
||||||
|
/* 拖拽到手机区域时的样式 */
|
||||||
|
.draggable-ghost {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
/* 条纹背景 */
|
||||||
|
background: linear-gradient(
|
||||||
|
45deg,
|
||||||
|
#91a8d5 0,
|
||||||
|
#91a8d5 10%,
|
||||||
|
#94b4eb 10%,
|
||||||
|
#94b4eb 50%,
|
||||||
|
#91a8d5 50%,
|
||||||
|
#91a8d5 60%,
|
||||||
|
#94b4eb 60%,
|
||||||
|
#94b4eb
|
||||||
|
);
|
||||||
|
background-size: 1rem 1rem;
|
||||||
|
transition: all 0.5s;
|
||||||
|
span {
|
||||||
|
color: #fff;
|
||||||
|
display: inline-block;
|
||||||
|
width: 140px;
|
||||||
|
height: 25px;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 25px;
|
||||||
|
background: #5487df;
|
||||||
|
}
|
||||||
|
/* 拖拽时隐藏组件 */
|
||||||
|
.component {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* 拖拽时显示占位提示 */
|
||||||
|
.drag-placement {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 轮播图属性 */
|
||||||
|
export interface CarouselProperty {
|
||||||
|
// 选择模板
|
||||||
|
swiperType: number
|
||||||
|
// 图片圆角
|
||||||
|
borderRadius: number
|
||||||
|
// 页面边距
|
||||||
|
pageMargin: number
|
||||||
|
// 图片边距
|
||||||
|
imageMargin: number
|
||||||
|
// 分页类型
|
||||||
|
pagingType: 'bullets' | 'fraction' | 'progressbar'
|
||||||
|
// 一行个数
|
||||||
|
rowIndividual: number
|
||||||
|
// 添加图片
|
||||||
|
items: CarouselItemProperty[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CarouselItemProperty {
|
||||||
|
title: string
|
||||||
|
imgUrl: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'Carousel',
|
||||||
|
name: '轮播图',
|
||||||
|
icon: 'system-uicons:carousel',
|
||||||
|
property: {
|
||||||
|
swiperType: 0, // 选择模板
|
||||||
|
borderRadius: 0, // 图片圆角
|
||||||
|
pageMargin: 0, // 页面边距
|
||||||
|
imageMargin: 0, // 图片边距
|
||||||
|
pagingType: 'bullets', // 分页类型
|
||||||
|
rowIndividual: 2, // 一行个数
|
||||||
|
items: [
|
||||||
|
{ imgUrl: 'https://static.iocoder.cn/mall/banner-01.jpg' },
|
||||||
|
{ imgUrl: 'https://static.iocoder.cn/mall/banner-02.jpg' }
|
||||||
|
] as CarouselItemProperty[]
|
||||||
|
}
|
||||||
|
} as DiyComponent<CarouselProperty>
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 无图片 -->
|
||||||
|
<div
|
||||||
|
class="h-250px flex items-center justify-center bg-gray-3"
|
||||||
|
v-if="property.items.length === 0"
|
||||||
|
>
|
||||||
|
<Icon icon="tdesign:image" class="text-gray-8 text-120px!" />
|
||||||
|
</div>
|
||||||
|
<!-- 一行一个 -->
|
||||||
|
<div
|
||||||
|
v-if="property.swiperType === 0"
|
||||||
|
class="flex flex-col"
|
||||||
|
:style="{
|
||||||
|
paddingLeft: property.pageMargin + 'px',
|
||||||
|
paddingRight: property.pageMargin + 'px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div v-for="(item, index) in property.items" :key="index">
|
||||||
|
<div
|
||||||
|
class="img-item"
|
||||||
|
:style="{
|
||||||
|
marginBottom: property.imageMargin + 'px',
|
||||||
|
borderRadius: property.borderRadius + 'px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<img alt="" :src="item.imgUrl" />
|
||||||
|
<div v-if="item.title" class="title">{{ item.title }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-carousel height="174px" v-else :type="property.swiperType === 3 ? 'card' : ''">
|
||||||
|
<el-carousel-item v-for="(item, index) in property.items" :key="index">
|
||||||
|
<div class="img-item" :style="{ borderRadius: property.borderRadius + 'px' }">
|
||||||
|
<img alt="" :src="item.imgUrl" />
|
||||||
|
<div v-if="item.title" class="title">{{ item.title }}</div>
|
||||||
|
</div>
|
||||||
|
</el-carousel-item>
|
||||||
|
</el-carousel>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { CarouselProperty } from './config'
|
||||||
|
|
||||||
|
/** 页面顶部导航栏 */
|
||||||
|
defineOptions({ name: 'NavigationBar' })
|
||||||
|
|
||||||
|
const props = defineProps<{ property: CarouselProperty }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.img-item {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
&:last-child {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
/* 图片 */
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
height: 36px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgba(51, 51, 51, 0.8);
|
||||||
|
text-align: center;
|
||||||
|
line-height: 36px;
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<el-form label-width="80px" :model="formData">
|
||||||
|
<el-form-item label="选择模板" prop="swiperType">
|
||||||
|
<el-radio-group v-model="formData.swiperType">
|
||||||
|
<el-tooltip class="item" content="一行一个" placement="bottom">
|
||||||
|
<el-radio-button :label="0">
|
||||||
|
<Icon icon="icon-park-twotone:multi-picture-carousel" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip class="item" content="轮播海报" placement="bottom">
|
||||||
|
<el-radio-button :label="1">
|
||||||
|
<Icon icon="system-uicons:carousel" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip class="item" content="多图单行" placement="bottom">
|
||||||
|
<el-radio-button :label="2">
|
||||||
|
<Icon icon="icon-park-twotone:carousel" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip class="item" content="立体轮播" placement="bottom">
|
||||||
|
<el-radio-button :label="3">
|
||||||
|
<Icon icon="ic:round-view-carousel" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-text tag="p">添加图片</el-text>
|
||||||
|
<el-text type="info" size="small"> 拖动左上角的小圆点可对其排序 </el-text>
|
||||||
|
|
||||||
|
<!-- 图片广告 -->
|
||||||
|
<div v-if="formData.items[0]">
|
||||||
|
<draggable
|
||||||
|
:list="formData.items"
|
||||||
|
:force-fallback="true"
|
||||||
|
:animation="200"
|
||||||
|
handle=".drag-icon"
|
||||||
|
class="m-t-8px"
|
||||||
|
>
|
||||||
|
<template #item="{ element, index }">
|
||||||
|
<div class="mb-4px flex flex-row gap-4px rounded bg-gray-100 p-8px">
|
||||||
|
<div class="flex flex-col items-start justify-between">
|
||||||
|
<Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" />
|
||||||
|
<Icon
|
||||||
|
icon="ep:delete"
|
||||||
|
class="cursor-pointer text-red-5"
|
||||||
|
@click="handleDeleteImage(index)"
|
||||||
|
v-if="formData.items.length > 1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-1 flex-col items-center justify-between gap-8px">
|
||||||
|
<UploadImg
|
||||||
|
v-model="element.imgUrl"
|
||||||
|
draggable="false"
|
||||||
|
height="80px"
|
||||||
|
width="100%"
|
||||||
|
class="min-w-80px"
|
||||||
|
/>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<el-input v-model="element.title" placeholder="标题,选填" />
|
||||||
|
<!-- 输入链接 -->
|
||||||
|
<el-input placeholder="链接,选填" v-model="element.link" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
<el-button @click="handleAddImage" type="primary" plain class="w-full"> 添加图片 </el-button>
|
||||||
|
<el-form-item label="一行个数" prop="rowIndividual" v-show="formData.swiperType === 2">
|
||||||
|
<!-- 单选框 -->
|
||||||
|
<el-radio-group v-model="formData.rowIndividual">
|
||||||
|
<el-radio :label="2">2个</el-radio>
|
||||||
|
<el-radio :label="3">3个</el-radio>
|
||||||
|
<el-radio :label="4">4个</el-radio>
|
||||||
|
<el-radio :label="5">5个</el-radio>
|
||||||
|
<el-radio :label="6">6个</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="分页类型" prop="pagingType">
|
||||||
|
<el-radio-group v-model="formData.pagingType">
|
||||||
|
<el-radio :label="0">不显示</el-radio>
|
||||||
|
<el-radio label="bullets">样式一</el-radio>
|
||||||
|
<el-radio label="fraction">样式二</el-radio>
|
||||||
|
<el-radio label="progressbar">样式三</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="图片圆角" prop="borderRadius">
|
||||||
|
<el-slider v-model="formData.borderRadius" :max="30" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="页面边距" prop="pageMargin" v-show="formData.swiperType === 0">
|
||||||
|
<el-slider v-model="formData.pageMargin" :max="20" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="图片边距"
|
||||||
|
prop="imageMargin"
|
||||||
|
v-show="formData.swiperType === 0 || formData.swiperType === 2"
|
||||||
|
>
|
||||||
|
<el-slider v-model="formData.imageMargin" :max="20" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import draggable from 'vuedraggable' //拖拽组件
|
||||||
|
import { CarouselItemProperty, CarouselProperty } from './config'
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
// 轮播图属性面板
|
||||||
|
defineOptions({ name: 'CarouselProperty' })
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: CarouselProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
|
||||||
|
// 添加图片
|
||||||
|
const handleAddImage = () => {
|
||||||
|
formData.value.items.push({} as CarouselItemProperty)
|
||||||
|
}
|
||||||
|
// 删除图片
|
||||||
|
const handleDeleteImage = (index) => {
|
||||||
|
formData.value.items.splice(index, 1)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 分割线属性 */
|
||||||
|
export interface DividerProperty {
|
||||||
|
// 高度
|
||||||
|
height: number
|
||||||
|
// 线宽
|
||||||
|
lineWidth: number
|
||||||
|
// 边距类型
|
||||||
|
paddingType: 'none' | 'horizontal'
|
||||||
|
// 颜色
|
||||||
|
lineColor: string
|
||||||
|
// 类型
|
||||||
|
borderType: 'solid' | 'dashed' | 'dotted' | 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'Divider',
|
||||||
|
name: '分割线',
|
||||||
|
icon: 'tdesign:component-divider-vertical',
|
||||||
|
property: {
|
||||||
|
height: 30,
|
||||||
|
lineWidth: 1,
|
||||||
|
paddingType: 'none',
|
||||||
|
lineColor: '#dcdfe6',
|
||||||
|
borderType: 'solid'
|
||||||
|
}
|
||||||
|
} as DiyComponent<DividerProperty>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="flex items-center"
|
||||||
|
:style="{
|
||||||
|
height: property.height + 'px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-full"
|
||||||
|
:style="{
|
||||||
|
borderTopStyle: property.borderType,
|
||||||
|
borderTopColor: property.lineColor,
|
||||||
|
borderTopWidth: `${property.lineWidth}px`,
|
||||||
|
margin: property.paddingType === 'none' ? '0' : '0px 16px'
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { DividerProperty } from './config'
|
||||||
|
|
||||||
|
/** 页面顶部导航栏 */
|
||||||
|
defineOptions({ name: 'Divider' })
|
||||||
|
|
||||||
|
defineProps<{ property: DividerProperty }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<el-form label-width="80px" :model="formData">
|
||||||
|
<el-form-item label="高度" prop="height">
|
||||||
|
<el-slider v-model="formData.height" :min="1" :max="100" show-input input-size="small" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="选择样式" prop="borderType">
|
||||||
|
<el-radio-group v-model="formData!.borderType">
|
||||||
|
<el-tooltip
|
||||||
|
placement="top"
|
||||||
|
v-for="(item, index) in BORDER_TYPES"
|
||||||
|
:key="index"
|
||||||
|
:content="item.text"
|
||||||
|
>
|
||||||
|
<el-radio-button :label="item.type">
|
||||||
|
<Icon :icon="item.icon" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<template v-if="formData.borderType !== 'none'">
|
||||||
|
<el-form-item label="线宽" prop="lineWidth">
|
||||||
|
<el-slider v-model="formData.lineWidth" :min="1" :max="30" show-input input-size="small" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="左右边距" prop="paddingType">
|
||||||
|
<el-radio-group v-model="formData!.paddingType">
|
||||||
|
<el-tooltip content="无边距" placement="top">
|
||||||
|
<el-radio-button label="none">
|
||||||
|
<Icon icon="tabler:box-padding" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="左右留边" placement="top">
|
||||||
|
<el-radio-button label="horizontal">
|
||||||
|
<Icon icon="vaadin:padding" />
|
||||||
|
</el-radio-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="颜色">
|
||||||
|
<!-- 分割线颜色 -->
|
||||||
|
<ColorInput v-model="formData.lineColor" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { DividerProperty } from './config'
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
// 导航栏属性面板
|
||||||
|
defineOptions({ name: 'DividerProperty' })
|
||||||
|
const props = defineProps<{ modelValue: DividerProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
|
||||||
|
//线类型
|
||||||
|
const BORDER_TYPES = [
|
||||||
|
{
|
||||||
|
icon: 'vaadin:line-h',
|
||||||
|
text: '实线',
|
||||||
|
type: 'solid'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler:line-dashed',
|
||||||
|
text: '虚线',
|
||||||
|
type: 'dashed'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler:line-dotted',
|
||||||
|
text: '点线',
|
||||||
|
type: 'dotted'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'entypo:progress-empty',
|
||||||
|
text: '无',
|
||||||
|
type: 'none'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 顶部导航栏属性 */
|
||||||
|
export interface NavigationBarProperty {
|
||||||
|
// 页面标题
|
||||||
|
title: string
|
||||||
|
// 页面描述
|
||||||
|
description: string
|
||||||
|
// 顶部导航高度
|
||||||
|
navBarHeight: number
|
||||||
|
// 页面背景颜色
|
||||||
|
backgroundColor: string
|
||||||
|
// 页面背景图片
|
||||||
|
backgroundImage: string
|
||||||
|
// 样式类型:默认 | 沉浸式
|
||||||
|
styleType: 'default' | 'immersion'
|
||||||
|
// 常驻显示
|
||||||
|
alwaysShow: boolean
|
||||||
|
// 是否显示返回按钮
|
||||||
|
showGoBack: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'NavigationBar',
|
||||||
|
name: '顶部导航栏',
|
||||||
|
icon: 'tabler:layout-navbar',
|
||||||
|
property: {
|
||||||
|
title: '页面标题',
|
||||||
|
description: '',
|
||||||
|
navBarHeight: 35,
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
backgroundImage: '',
|
||||||
|
styleType: 'default',
|
||||||
|
alwaysShow: true,
|
||||||
|
showGoBack: true
|
||||||
|
}
|
||||||
|
} as DiyComponent<NavigationBarProperty>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="navigation-bar"
|
||||||
|
:style="{
|
||||||
|
height: `${property.navBarHeight}px`,
|
||||||
|
backgroundColor: property.backgroundColor,
|
||||||
|
backgroundImage: `url(${property.backgroundImage})`
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<!-- 左侧 -->
|
||||||
|
<div class="left">
|
||||||
|
<Icon icon="ep:arrow-left" v-show="property.showGoBack" />
|
||||||
|
</div>
|
||||||
|
<!-- 中间 -->
|
||||||
|
<div
|
||||||
|
class="center"
|
||||||
|
:style="{
|
||||||
|
height: `${property.navBarHeight}px`,
|
||||||
|
lineHeight: `${property.navBarHeight}px`
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ property.title }}
|
||||||
|
</div>
|
||||||
|
<!-- 右侧 -->
|
||||||
|
<div class="right"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NavigationBarProperty } from './config'
|
||||||
|
|
||||||
|
/** 页面顶部导航栏 */
|
||||||
|
defineOptions({ name: 'NavigationBar' })
|
||||||
|
|
||||||
|
defineProps<{ property: NavigationBarProperty }>()
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.navigation-bar {
|
||||||
|
height: 35px;
|
||||||
|
background: #fff;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
/* 左边 */
|
||||||
|
.left {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
.center {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 35px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
/* 右边 */
|
||||||
|
.right {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<el-form label-width="80px" :model="formData" :rules="rules">
|
||||||
|
<el-form-item label="页面标题" prop="title">
|
||||||
|
<el-input v-model="formData!.title" placeholder="页面标题" maxlength="25" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="页面描述" prop="description">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="formData!.description"
|
||||||
|
placeholder="用户通过微信分享给朋友时,会自动显示页面描述"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="样式" prop="styleType">
|
||||||
|
<el-radio-group v-model="formData!.styleType">
|
||||||
|
<el-radio label="default">默认</el-radio>
|
||||||
|
<el-radio label="immersion">沉浸式</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="常驻显示" prop="alwaysShow" v-if="formData.styleType === 'immersion'">
|
||||||
|
<el-radio-group v-model="formData!.alwaysShow">
|
||||||
|
<el-radio :label="false">关闭</el-radio>
|
||||||
|
<el-radio :label="true">开启</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="高度" prop="navBarHeight">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData!.navBarHeight"
|
||||||
|
:max="100"
|
||||||
|
:min="35"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="返回按钮" prop="showGoBack">
|
||||||
|
<el-switch v-model="formData!.showGoBack" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="背景颜色" prop="backgroundColor">
|
||||||
|
<ColorInput v-model="formData!.backgroundColor" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="背景图片" prop="backgroundImage">
|
||||||
|
<UploadImg v-model="formData!.backgroundImage" :limit="1">
|
||||||
|
<template #tip>建议宽度 750px</template>
|
||||||
|
</UploadImg>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NavigationBarProperty } from './config'
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
// 导航栏属性面板
|
||||||
|
defineOptions({ name: 'NavigationBarProperty' })
|
||||||
|
// 表单校验
|
||||||
|
const rules = {
|
||||||
|
name: [{ required: true, message: '请输入页面名称', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: NavigationBarProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 公告栏属性 */
|
||||||
|
export interface NoticeBarProperty {
|
||||||
|
// 图标地址
|
||||||
|
iconUrl: string
|
||||||
|
// 公告内容列表
|
||||||
|
contents: NoticeContentProperty[]
|
||||||
|
// 背景颜色
|
||||||
|
backgroundColor: string
|
||||||
|
// 文字颜色
|
||||||
|
textColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 内容属性 */
|
||||||
|
export interface NoticeContentProperty {
|
||||||
|
// 内容文字
|
||||||
|
text: string
|
||||||
|
// 链接地址
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'NoticeBar',
|
||||||
|
name: '公告栏',
|
||||||
|
icon: 'ep:bell',
|
||||||
|
property: {
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/xinjian.png',
|
||||||
|
contents: [
|
||||||
|
{
|
||||||
|
text: '',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
],
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
textColor: '#333'
|
||||||
|
}
|
||||||
|
} as DiyComponent<NoticeBarProperty>
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="flex items-center text-12px"
|
||||||
|
:style="{ backgroundColor: property.backgroundColor, color: property.textColor }"
|
||||||
|
>
|
||||||
|
<el-image :src="property.iconUrl" class="h-18px" />
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-carousel height="24px" direction="vertical" :autoplay="true" class="flex-1 p-r-8px">
|
||||||
|
<el-carousel-item v-for="(item, index) in property.contents" :key="index">
|
||||||
|
<div class="h-24px truncate leading-24px">{{ item.text }}</div>
|
||||||
|
</el-carousel-item>
|
||||||
|
</el-carousel>
|
||||||
|
<Icon icon="ep:arrow-right" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NoticeBarProperty } from './config'
|
||||||
|
|
||||||
|
/** 公告栏 */
|
||||||
|
defineOptions({ name: 'NoticeBar' })
|
||||||
|
|
||||||
|
defineProps<{ property: NoticeBarProperty }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 页面设置属性 */
|
||||||
|
export interface PageConfigProperty {
|
||||||
|
// 页面描述
|
||||||
|
description: string
|
||||||
|
// 页面背景颜色
|
||||||
|
backgroundColor: string
|
||||||
|
// 页面背景图片
|
||||||
|
backgroundImage: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义页面组件
|
||||||
|
export const component = {
|
||||||
|
id: 'PageConfig',
|
||||||
|
name: '页面设置',
|
||||||
|
icon: 'ep:document',
|
||||||
|
property: {
|
||||||
|
description: '',
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
backgroundImage: ''
|
||||||
|
}
|
||||||
|
} as DiyComponent<PageConfigProperty>
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<el-form label-width="80px" :model="formData" :rules="rules">
|
||||||
|
<el-form-item label="页面描述" prop="description">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="formData!.description"
|
||||||
|
placeholder="用户通过微信分享给朋友时,会自动显示页面描述"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="背景颜色" prop="backgroundColor">
|
||||||
|
<ColorInput v-model="formData!.backgroundColor" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="背景图片" prop="backgroundImage">
|
||||||
|
<UploadImg v-model="formData!.backgroundImage" :limit="1">
|
||||||
|
<template #tip>建议宽度 750px</template>
|
||||||
|
</UploadImg>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { PageConfigProperty } from './config'
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
// 导航栏属性面板
|
||||||
|
defineOptions({ name: 'PageConfigProperty' })
|
||||||
|
// 表单校验
|
||||||
|
const rules = {}
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: PageConfigProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 搜索框属性 */
|
||||||
|
export interface SearchProperty {
|
||||||
|
height: number // 搜索栏高度
|
||||||
|
showScan: boolean // 显示扫一扫
|
||||||
|
borderRadius: number // 框体样式
|
||||||
|
placeholder: string // 占位文字
|
||||||
|
placeholderPosition: PlaceholderPosition // 占位文字位置
|
||||||
|
backgroundColor: string // 背景颜色
|
||||||
|
borderColor: string // 框体颜色
|
||||||
|
textColor: string // 字体颜色
|
||||||
|
hotKeywords: string[] // 热词
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文字位置
|
||||||
|
export type PlaceholderPosition = 'left' | 'center'
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'SearchBar',
|
||||||
|
name: '搜索框',
|
||||||
|
icon: 'ep:search',
|
||||||
|
property: {
|
||||||
|
height: 28,
|
||||||
|
showScan: false,
|
||||||
|
borderRadius: 0,
|
||||||
|
placeholder: '搜索商品',
|
||||||
|
placeholderPosition: 'left',
|
||||||
|
backgroundColor: 'rgb(249, 249, 249)',
|
||||||
|
borderColor: 'rgb(255, 255, 255)',
|
||||||
|
textColor: 'rgb(150, 151, 153)',
|
||||||
|
hotKeywords: []
|
||||||
|
}
|
||||||
|
} as DiyComponent<SearchProperty>
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="search-bar"
|
||||||
|
:style="{
|
||||||
|
background: property.backgroundColor,
|
||||||
|
border: `1px solid ${property.backgroundColor}`,
|
||||||
|
color: property.textColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<div
|
||||||
|
class="inner"
|
||||||
|
:style="{
|
||||||
|
height: `${property.height}px`,
|
||||||
|
background: property.borderColor,
|
||||||
|
borderRadius: `${property.borderRadius}px`
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="placeholder"
|
||||||
|
:style="{
|
||||||
|
justifyContent: property.placeholderPosition
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:search" />
|
||||||
|
<span>{{ property.placeholder || '搜索商品' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<!-- 搜索热词 -->
|
||||||
|
<span v-for="(keyword, index) in property.hotKeywords" :key="index">{{ keyword }}</span>
|
||||||
|
<!-- 扫一扫 -->
|
||||||
|
<Icon icon="ant-design:scan-outlined" v-show="property.showScan" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { SearchProperty } from './config'
|
||||||
|
/** 搜索框 */
|
||||||
|
defineOptions({ name: 'SearchBar' })
|
||||||
|
defineProps<{ property: SearchProperty }>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.search-bar {
|
||||||
|
position: relative;
|
||||||
|
/* 搜索框 */
|
||||||
|
.inner {
|
||||||
|
position: relative;
|
||||||
|
width: calc(100% - 16px);
|
||||||
|
min-height: 28px;
|
||||||
|
margin: 5px auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 8px;
|
||||||
|
gap: 2px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<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>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import VueDraggable from 'vuedraggable'
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
import { SearchProperty } from '@/components/DiyEditor/components/mobile/SearchBar/config'
|
||||||
|
|
||||||
|
/** 搜索框属性面板 */
|
||||||
|
defineOptions({ name: 'SearchProperty' })
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: SearchProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
|
||||||
|
/* 添加热词 */
|
||||||
|
const handleAddHotWord = () => {
|
||||||
|
formData.value.hotKeywords.push('')
|
||||||
|
}
|
||||||
|
/* 删除热词 */
|
||||||
|
const deleteHotWord = (index: number) => {
|
||||||
|
formData.value.hotKeywords.splice(index, 1)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 底部导航菜单属性 */
|
||||||
|
export interface TabBarProperty {
|
||||||
|
// 选项列表
|
||||||
|
items: TabBarItemProperty[]
|
||||||
|
// 主题
|
||||||
|
theme: string
|
||||||
|
// 样式
|
||||||
|
style: TabBarStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选项属性
|
||||||
|
export interface TabBarItemProperty {
|
||||||
|
name: string // 标签名称
|
||||||
|
link: string // 链接
|
||||||
|
iconUrl: string // 默认图标链接
|
||||||
|
activeIconUrl: string // 选中的图标链接
|
||||||
|
}
|
||||||
|
|
||||||
|
// 样式
|
||||||
|
export interface TabBarStyle {
|
||||||
|
// 背景类型
|
||||||
|
backgroundType: 'color' | 'img'
|
||||||
|
// 背景颜色 或 图片链接
|
||||||
|
background: string
|
||||||
|
// 默认颜色
|
||||||
|
color: string
|
||||||
|
// 选中的颜色
|
||||||
|
activeColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'TabBar',
|
||||||
|
name: '底部导航',
|
||||||
|
icon: 'fluent:table-bottom-row-16-filled',
|
||||||
|
property: {
|
||||||
|
theme: 'red',
|
||||||
|
style: {
|
||||||
|
backgroundType: 'color',
|
||||||
|
background: '#fff',
|
||||||
|
color: '#282828',
|
||||||
|
activeColor: '#fc4141'
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: '首页',
|
||||||
|
link: '/',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-001.png',
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-002.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '分类',
|
||||||
|
link: '/pages/goods_cate/goods_cate',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-001.png',
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-002.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '购物车',
|
||||||
|
link: '/pages/order_addcart/order_addcart',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-001.png',
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-002.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '我的',
|
||||||
|
link: '/pages/user/index',
|
||||||
|
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-001.png',
|
||||||
|
activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-002.png'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} as DiyComponent<TabBarProperty>
|
||||||
|
|
||||||
|
export const THEME_LIST = [
|
||||||
|
{ id: 'red', name: '中国红', icon: 'icon-park-twotone:theme', color: '#d10019' },
|
||||||
|
{ id: 'orange', name: '桔橙', icon: 'icon-park-twotone:theme', color: '#f37b1d' },
|
||||||
|
{ id: 'gold', name: '明黄', icon: 'icon-park-twotone:theme', color: '#fbbd08' },
|
||||||
|
{ id: 'green', name: '橄榄绿', icon: 'icon-park-twotone:theme', color: '#8dc63f' },
|
||||||
|
{ id: 'cyan', name: '天青', icon: 'icon-park-twotone:theme', color: '#1cbbb4' },
|
||||||
|
{ id: 'blue', name: '海蓝', icon: 'icon-park-twotone:theme', color: '#0081ff' },
|
||||||
|
{ id: 'purple', name: '姹紫', icon: 'icon-park-twotone:theme', color: '#6739b6' },
|
||||||
|
{ id: 'brightRed', name: '嫣红', icon: 'icon-park-twotone:theme', color: '#e54d42' },
|
||||||
|
{ id: 'forestGreen', name: '森绿', icon: 'icon-park-twotone:theme', color: '#39b54a' },
|
||||||
|
{ id: 'mauve', name: '木槿', icon: 'icon-park-twotone:theme', color: '#9c26b0' },
|
||||||
|
{ id: 'pink', name: '桃粉', icon: 'icon-park-twotone:theme', color: '#e03997' },
|
||||||
|
{ id: 'brown', name: '棕褐', icon: 'icon-park-twotone:theme', color: '#a5673f' },
|
||||||
|
{ id: 'grey', name: '玄灰', icon: 'icon-park-twotone:theme', color: '#8799a3' },
|
||||||
|
{ id: 'gray', name: '草灰', icon: 'icon-park-twotone:theme', color: '#aaaaaa' },
|
||||||
|
{ id: 'black', name: '墨黑', icon: 'icon-park-twotone:theme', color: '#333333' }
|
||||||
|
]
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tab-bar">
|
||||||
|
<div
|
||||||
|
class="tab-bar-bg"
|
||||||
|
:style="{
|
||||||
|
background:
|
||||||
|
property.style.backgroundType === 'color'
|
||||||
|
? property.style.background
|
||||||
|
: `url(${property.style.background})`,
|
||||||
|
backgroundSize: '100% 100%',
|
||||||
|
backgroundRepeat: 'no-repeat'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div v-for="(item, index) in property.items" :key="index" class="tab-bar-item">
|
||||||
|
<img :src="index === 0 ? item.activeIconUrl : item.iconUrl" alt="" />
|
||||||
|
<span :style="{ color: index === 0 ? property.style.activeColor : property.style.color }">
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { TabBarProperty } from './config'
|
||||||
|
|
||||||
|
/** 页面底部导航栏 */
|
||||||
|
defineOptions({ name: 'TabBar' })
|
||||||
|
|
||||||
|
defineProps<{ property: TabBarProperty }>()
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tab-bar {
|
||||||
|
width: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
.tab-bar-bg {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding: 8px 0;
|
||||||
|
|
||||||
|
.tab-bar-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||||
|
|
||||||
|
/** 标题栏属性 */
|
||||||
|
export interface TitleBarProperty {
|
||||||
|
// 主标题
|
||||||
|
title: string
|
||||||
|
// 副标题
|
||||||
|
description: string
|
||||||
|
// 标题大小
|
||||||
|
titleSize: number
|
||||||
|
// 描述大小
|
||||||
|
descriptionSize: number
|
||||||
|
// 标题粗细
|
||||||
|
titleWeight: number
|
||||||
|
// 显示位置
|
||||||
|
position: 'left' | 'center'
|
||||||
|
// 描述粗细
|
||||||
|
descriptionWeight: number
|
||||||
|
// 标题颜色
|
||||||
|
titleColor: string
|
||||||
|
// 描述颜色
|
||||||
|
descriptionColor: string
|
||||||
|
// 背景颜色
|
||||||
|
backgroundColor: string
|
||||||
|
// 底部分割线
|
||||||
|
showBottomBorder: false
|
||||||
|
// 查看更多
|
||||||
|
more: {
|
||||||
|
// 是否显示查看更多
|
||||||
|
show: false
|
||||||
|
// 样式选择
|
||||||
|
type: 'text' | 'icon' | 'all'
|
||||||
|
// 自定义文字
|
||||||
|
text: string
|
||||||
|
// 链接
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
export const component = {
|
||||||
|
id: 'TitleBar',
|
||||||
|
name: '标题栏',
|
||||||
|
icon: 'material-symbols:line-start',
|
||||||
|
property: {
|
||||||
|
title: '主标题',
|
||||||
|
description: '副标题',
|
||||||
|
titleSize: 16,
|
||||||
|
descriptionSize: 12,
|
||||||
|
titleWeight: 400,
|
||||||
|
position: 'left',
|
||||||
|
descriptionWeight: 200,
|
||||||
|
titleColor: 'rgba(50, 50, 51, 10)',
|
||||||
|
descriptionColor: 'rgba(150, 151, 153, 10)',
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 10)',
|
||||||
|
showBottomBorder: false,
|
||||||
|
more: {
|
||||||
|
//查看更多
|
||||||
|
show: false,
|
||||||
|
type: 'icon',
|
||||||
|
text: '查看更多',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as DiyComponent<TitleBarProperty>
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="title-bar"
|
||||||
|
:style="{
|
||||||
|
background: property.backgroundColor,
|
||||||
|
borderBottom: property.showBottomBorder ? '1px solid #F9F9F9' : '1px solid #fff'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
fontSize: `${property.titleSize}px`,
|
||||||
|
fontWeight: property.titleWeight,
|
||||||
|
color: property.titleColor,
|
||||||
|
textAlign: property.position
|
||||||
|
}"
|
||||||
|
v-if="property.title"
|
||||||
|
>
|
||||||
|
{{ property.title }}
|
||||||
|
</div>
|
||||||
|
<!-- 副标题 -->
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
fontSize: `${property.descriptionSize}px`,
|
||||||
|
fontWeight: property.descriptionWeight,
|
||||||
|
color: property.descriptionColor,
|
||||||
|
textAlign: property.position
|
||||||
|
}"
|
||||||
|
class="m-t-8px"
|
||||||
|
v-if="property.description"
|
||||||
|
>
|
||||||
|
{{ property.description }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 更多 -->
|
||||||
|
<div
|
||||||
|
class="more"
|
||||||
|
v-show="property.more.show"
|
||||||
|
:style="{
|
||||||
|
color: property.more.type === 'text' ? '#38f' : ''
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ property.more.type === 'icon' ? '' : property.more.text }}
|
||||||
|
<Icon icon="ep:arrow-right" v-if="property.more.type !== 'text'" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { TitleBarProperty } from './config'
|
||||||
|
|
||||||
|
/** 标题栏 */
|
||||||
|
defineOptions({ name: 'TitleBar' })
|
||||||
|
|
||||||
|
defineProps<{ property: TitleBarProperty }>()
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.title-bar {
|
||||||
|
border: 2px solid #fff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 16px;
|
||||||
|
min-height: 20px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
/* 更多 */
|
||||||
|
.more {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #969799;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<section class="title-bar">
|
||||||
|
<el-form label-width="85px" :model="formData" :rules="rules">
|
||||||
|
<el-form-item label="主标题" prop="title">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.title"
|
||||||
|
placeholder="请输入主标题"
|
||||||
|
show-word-limit
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="副标题" prop="description">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="formData.description"
|
||||||
|
placeholder="请输入副标题"
|
||||||
|
maxlength="50"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="显示位置" prop="position">
|
||||||
|
<el-radio-group v-model="formData!.position">
|
||||||
|
<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="titleSize">
|
||||||
|
<el-slider v-model="formData.titleSize" :max="60" :min="10" show-input input-size="small" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="副标题大小" prop="descriptionSize">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData.descriptionSize"
|
||||||
|
:max="60"
|
||||||
|
:min="10"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="标题粗细" prop="titleWeight">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData.titleWeight"
|
||||||
|
:min="100"
|
||||||
|
:max="900"
|
||||||
|
:step="100"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="副标题粗细" prop="descriptionWeight">
|
||||||
|
<el-slider
|
||||||
|
v-model="formData.descriptionWeight"
|
||||||
|
:min="100"
|
||||||
|
:max="900"
|
||||||
|
:step="100"
|
||||||
|
show-input
|
||||||
|
input-size="small"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="标题颜色" prop="titleColor">
|
||||||
|
<ColorInput v-model="formData.titleColor" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="副标题颜色" prop="descriptionColor">
|
||||||
|
<ColorInput v-model="formData.descriptionColor" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="背景颜色" prop="backgroundColor">
|
||||||
|
<ColorInput v-model="formData.backgroundColor" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="底部分割线" prop="showBottomBorder">
|
||||||
|
<el-switch v-model="formData!.showBottomBorder" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="查看更多" prop="more.show">
|
||||||
|
<el-checkbox v-model="formData.more.show" />
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 更多样式选择 -->
|
||||||
|
<template v-if="formData.more.show">
|
||||||
|
<el-form-item label="样式" prop="more.type">
|
||||||
|
<el-radio-group v-model="formData.more.type">
|
||||||
|
<el-radio label="text">文字</el-radio>
|
||||||
|
<el-radio label="icon">图标</el-radio>
|
||||||
|
<el-radio label="all">文字+图标</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="更多文字" prop="more.text" v-show="formData.more.type !== 'icon'">
|
||||||
|
<el-input v-model="formData.more.text" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="跳转链接" prop="more.url">
|
||||||
|
<el-input v-model="formData.more.url" placeholder="请输入跳转链接" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { TitleBarProperty } from './config'
|
||||||
|
import { usePropertyForm } from '@/components/DiyEditor/util'
|
||||||
|
// 导航栏属性面板
|
||||||
|
defineOptions({ name: 'TitleBarProperty' })
|
||||||
|
|
||||||
|
const props = defineProps<{ modelValue: TitleBarProperty }>()
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||||
|
|
||||||
|
// 表单校验
|
||||||
|
const rules = {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
Loading…
Reference in New Issue