refactor: (ele,diy-editor)重构组件库结构和功能

- 新增 ComponentContainer、ComponentContainerProperty、ComponentLibrary 组件
- 优化导航栏单元格属性组件,更名为 CellProperty
- 更新优惠券相关组件导出方式
- 删除旧版 ComponentContainer 组件
pull/194/head
吃货 2025-08-10 21:17:03 +08:00
parent d7397f28a0
commit b8c66b23f9
97 changed files with 838 additions and 701 deletions

View File

@ -166,7 +166,7 @@ const handleSliderChange = (prop: string) => {
:label="data.label"
:prop="data.prop"
:label-width="node.level === 1 ? '80px' : '62px'"
class="m-b-0! w-full"
class="mb-0 w-full"
>
<ElSlider
v-model="

View File

@ -11,6 +11,8 @@ import { ElButton, ElTooltip } from 'element-plus';
import { components } from '#/components/diy-editor/components/mobile';
import VerticalButtonGroup from '#/components/vertical-button-group/index.vue';
import { IconifyIcon } from '@vben/icons';
/**
* 组件容器目前在中间部分
* 用于包裹组件为组件提供 背景外边距内边距边框等样式
@ -36,7 +38,7 @@ const props = defineProps({
},
showToolbar: {
type: Boolean,
default: false,
default: true,
},
});
@ -125,7 +127,7 @@ const handleDeleteComponent = () => {
:disabled="!canMoveUp"
@click.stop="handleMoveComponent(-1)"
>
<Icon icon="ep:arrow-up" />
<IconifyIcon icon="ep:arrow-up" />
</ElButton>
</ElTooltip>
<ElTooltip content="下移" placement="right">
@ -133,17 +135,17 @@ const handleDeleteComponent = () => {
:disabled="!canMoveDown"
@click.stop="handleMoveComponent(1)"
>
<Icon icon="ep:arrow-down" />
<IconifyIcon icon="ep:arrow-down" />
</ElButton>
</ElTooltip>
<ElTooltip content="复制" placement="right">
<ElButton @click.stop="handleCopyComponent()">
<Icon icon="ep:copy-document" />
<IconifyIcon icon="ep:copy-document" />
</ElButton>
</ElTooltip>
<ElTooltip content="删除" placement="right">
<ElButton @click.stop="handleDeleteComponent()">
<Icon icon="ep:delete" />
<IconifyIcon icon="ep:delete" />
</ElButton>
</ElTooltip>
</VerticalButtonGroup>

View File

@ -12,7 +12,7 @@ import { cloneDeep } from '@vben/utils';
import { ElAside, ElCollapse, ElCollapseItem, ElScrollbar } from 'element-plus';
import draggable from 'vuedraggable';
import { componentConfigs } from '../components/mobile/index';
import { componentConfigs } from './mobile/index';
/** 组件库:目前左侧的【基础组件】、【图文组件】部分 */
defineOptions({ name: 'ComponentLibrary' });
@ -90,7 +90,7 @@ const handleCloneComponent = (component: DiyComponent<any>) => {
<div class="drag-placement">组件放置区域</div>
<div class="component">
<IconifyIcon :icon="element.icon" :size="32" />
<span class="mt-4px text-12px">{{ element.name }}</span>
<span class="mt-1 text-xs">{{ element.name }}</span>
</div>
</div>
</template>

View File

@ -17,7 +17,7 @@ import {
} from 'element-plus';
import AppLinkInput from '#/components/app-link-input/index.vue';
import ComponentContainerProperty from '#/components/diy-editor/components/ComponentContainerProperty.vue';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import Draggable from '#/components/draggable/index.vue';
import UploadFile from '#/components/upload/file-upload.vue';
import UploadImg from '#/components/upload/image-upload.vue';
@ -76,7 +76,7 @@ const formData = useVModel(props, 'modelValue', emit);
<ElFormItem
label="类型"
prop="type"
class="m-b-8px!"
class="mb-2"
label-width="40px"
>
<ElRadioGroup v-model="element.type">
@ -86,7 +86,7 @@ const formData = useVModel(props, 'modelValue', emit);
</ElFormItem>
<ElFormItem
label="图片"
class="m-b-8px!"
class="mb-2"
label-width="40px"
v-if="element.type === 'img'"
>
@ -95,32 +95,32 @@ const formData = useVModel(props, 'modelValue', emit);
draggable="false"
height="80px"
width="100%"
class="min-w-80px"
class="min-w-[80px]"
:show-description="false"
/>
</ElFormItem>
<template v-else>
<ElFormItem label="封面" class="m-b-8px!" label-width="40px">
<ElFormItem label="封面" class="mb-2" label-width="40px">
<UploadImg
v-model="element.imgUrl"
draggable="false"
:show-description="false"
height="80px"
width="100%"
class="min-w-80px"
class="min-w-[80px]"
/>
</ElFormItem>
<ElFormItem label="视频" class="m-b-8px!" label-width="40px">
<ElFormItem label="视频" class="mb-2" label-width="40px">
<UploadFile
v-model="element.videoUrl"
:file-type="['mp4']"
:limit="1"
:file-size="100"
class="min-w-80px"
class="min-w-[80px]"
/>
</ElFormItem>
</template>
<ElFormItem label="链接" class="m-b-8px!" label-width="40px">
<ElFormItem label="链接" class="mb-2" label-width="40px">
<AppLinkInput v-model="element.url" />
</ElFormItem>
</template>

View File

@ -1,4 +0,0 @@
// 导出所有优惠券相关组件
export { CouponDiscount } from './CouponDiscount';
export { CouponDiscountDesc } from './CouponDiscountDesc';
export { CouponValidTerm } from './CouponValidTerm';

View File

@ -2,6 +2,18 @@
import type { DividerProperty } from './config';
import { useVModel } from '@vueuse/core';
import {
ElForm,
ElFormItem,
ElRadioButton,
ElRadioGroup,
ElSlider,
ElTooltip,
} from 'element-plus';
import { IconifyIcon } from '@vben/icons';
import ColorInput from '#/components/input-with-color/index.vue';
//
defineOptions({ name: 'DividerProperty' });
const props = defineProps<{ modelValue: DividerProperty }>();
@ -34,60 +46,60 @@ const BORDER_TYPES = [
</script>
<template>
<el-form label-width="80px" :model="formData">
<el-form-item label="高度" prop="height">
<el-slider
<ElForm label-width="80px" :model="formData">
<ElFormItem label="高度" prop="height">
<ElSlider
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
</ElFormItem>
<ElFormItem label="选择样式" prop="borderType">
<ElRadioGroup v-model="formData!.borderType">
<ElTooltip
placement="top"
v-for="(item, index) in BORDER_TYPES"
:key="index"
:content="item.text"
>
<el-radio-button :value="item.type">
<Icon :icon="item.icon" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<ElRadioButton :value="item.type">
<IconifyIcon :icon="item.icon" />
</ElRadioButton>
</ElTooltip>
</ElRadioGroup>
</ElFormItem>
<template v-if="formData.borderType !== 'none'">
<el-form-item label="线宽" prop="lineWidth">
<el-slider
<ElFormItem label="线宽" prop="lineWidth">
<ElSlider
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 value="none">
<Icon icon="tabler:box-padding" />
</el-radio-button>
</el-tooltip>
<el-tooltip content="左右留边" placement="top">
<el-radio-button value="horizontal">
<Icon icon="vaadin:padding" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item label="颜色">
</ElFormItem>
<ElFormItem label="左右边距" prop="paddingType">
<ElRadioGroup v-model="formData!.paddingType">
<ElTooltip content="无边距" placement="top">
<ElRadioButton value="none">
<IconifyIcon icon="tabler:box-padding" />
</ElRadioButton>
</ElTooltip>
<ElTooltip content="左右留边" placement="top">
<ElRadioButton value="horizontal">
<IconifyIcon icon="vaadin:padding" />
</ElRadioButton>
</ElTooltip>
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="颜色">
<!-- 分割线颜色 -->
<ColorInput v-model="formData.lineColor" />
</el-form-item>
</ElFormItem>
</template>
</el-form>
</ElForm>
</template>
<style scoped lang="scss"></style>

View File

@ -1,40 +0,0 @@
<script setup lang="ts">
import type { MenuListProperty } from './config';
/** 列表导航 */
defineOptions({ name: 'MenuList' });
defineProps<{ property: MenuListProperty }>();
</script>
<template>
<div class="min-h-42px flex flex-col">
<div
v-for="(item, index) in property.list"
:key="index"
class="item h-42px gap-4px p-x-12px flex flex-row items-center justify-between"
>
<div class="gap-8px flex flex-1 flex-row items-center">
<el-image
v-if="item.iconUrl"
class="h-16px w-16px"
:src="item.iconUrl"
/>
<span class="text-16px" :style="{ color: item.titleColor }">{{
item.title
}}</span>
</div>
<div class="item-center gap-4px flex flex-row justify-center">
<span class="text-12px" :style="{ color: item.subtitleColor }">{{
item.subtitle
}}</span>
<Icon icon="ep-arrow-right" color="#000" :size="16" />
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.item + .item {
border-top: 1px solid #eee;
}
</style>

View File

@ -1,88 +0,0 @@
<script setup lang="ts">
import type { MenuSwiperProperty } from './config';
import { cloneDeep } from '@vben/utils';
import { useVModel } from '@vueuse/core';
import { EMPTY_MENU_SWIPER_ITEM_PROPERTY } from './config';
/** 菜单导航属性面板 */
defineOptions({ name: 'MenuSwiperProperty' });
const props = defineProps<{ modelValue: MenuSwiperProperty }>();
const emit = defineEmits(['update:modelValue']);
const formData = useVModel(props, 'modelValue', emit);
</script>
<template>
<ComponentContainerProperty v-model="formData.style">
<!-- 表单 -->
<el-form label-width="80px" :model="formData" class="m-t-8px">
<el-form-item label="布局" prop="layout">
<el-radio-group v-model="formData.layout">
<el-radio value="iconText">图标+文字</el-radio>
<el-radio value="icon">仅图标</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="行数" prop="row">
<el-radio-group v-model="formData.row">
<el-radio :value="1">1</el-radio>
<el-radio :value="2">2</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="列数" prop="column">
<el-radio-group v-model="formData.column">
<el-radio :value="3">3</el-radio>
<el-radio :value="4">4</el-radio>
<el-radio :value="5">5</el-radio>
</el-radio-group>
</el-form-item>
<el-card header="菜单设置" class="property-group" shadow="never">
<Draggable
v-model="formData.list"
:empty-item="cloneDeep(EMPTY_MENU_SWIPER_ITEM_PROPERTY)"
>
<template #default="{ element }">
<el-form-item label="图标" prop="iconUrl">
<UploadImg
v-model="element.iconUrl"
height="80px"
width="80px"
:show-description="false"
>
<template #tip> 建议尺寸98 * 98 </template>
</UploadImg>
</el-form-item>
<el-form-item label="标题" prop="title">
<InputWithColor
v-model="element.title"
v-model:color="element.titleColor"
/>
</el-form-item>
<el-form-item label="链接" prop="url">
<AppLinkInput v-model="element.url" />
</el-form-item>
<el-form-item label="显示角标" prop="badge.show">
<el-switch v-model="element.badge.show" />
</el-form-item>
<template v-if="element.badge.show">
<el-form-item label="角标内容" prop="badge.text">
<InputWithColor
v-model="element.badge.text"
v-model:color="element.badge.textColor"
/>
</el-form-item>
<el-form-item label="背景颜色" prop="badge.bgColor">
<ColorInput v-model="element.badge.bgColor" />
</el-form-item>
</template>
</template>
</Draggable>
</el-card>
</el-form>
</ComponentContainerProperty>
</template>
<style scoped lang="scss"></style>

View File

@ -1,34 +0,0 @@
<script setup lang="ts">
import type { NoticeBarProperty } from './config';
/** 公告栏 */
defineOptions({ name: 'NoticeBar' });
defineProps<{ property: NoticeBarProperty }>();
</script>
<template>
<div
class="p-y-4px text-12px flex items-center"
: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="p-r-8px flex-1"
>
<el-carousel-item v-for="(item, index) in property.contents" :key="index">
<div class="h-24px leading-24px truncate">{{ item.text }}</div>
</el-carousel-item>
</el-carousel>
<Icon icon="ep:arrow-right" />
</div>
</template>
<style scoped lang="scss"></style>

View File

@ -1,6 +1,10 @@
<script setup lang="ts">
import type { PopoverProperty } from './config';
import { ElImage } from 'element-plus';
import { IconifyIcon } from '@vben/icons';
import { ref } from 'vue';
/** 弹窗广告 */
@ -18,7 +22,7 @@ const handleActive = (index: number) => {
<div
v-for="(item, index) in property.list"
:key="index"
class="bottom-50% right-50% h-454px w-292px border-1px border-gray border-rounded-4px p-1px absolute border-solid bg-white"
class="absolute bottom-1/2 right-1/2 h-[454px] w-[292px] rounded border border-gray-300 bg-white p-0.5"
:style="{
zIndex: 100 + index + (activeIndex === index ? 100 : 0),
marginRight: `${-146 - index * 20}px`,
@ -26,14 +30,14 @@ const handleActive = (index: number) => {
}"
@click="handleActive(index)"
>
<el-image :src="item.imgUrl" fit="contain" class="h-full w-full">
<ElImage :src="item.imgUrl" fit="contain" class="h-full w-full">
<template #error>
<div class="flex h-full w-full items-center justify-center">
<Icon icon="ep:picture" />
<IconifyIcon icon="ep:picture" />
</div>
</template>
</el-image>
<div class="text-12px absolute right-1 top-1">{{ index + 1 }}</div>
</ElImage>
<div class="absolute right-1 top-1 text-xs">{{ index + 1 }}</div>
</div>
</template>

View File

@ -2,6 +2,16 @@
import type { PopoverProperty } from './config';
import { useVModel } from '@vueuse/core';
import {
ElForm,
ElFormItem,
ElRadio,
ElRadioGroup,
ElTooltip,
} from 'element-plus';
import Draggable from '#/components/draggable/index.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import AppLinkInput from '#/components/app-link-input/index.vue';
// 广
defineOptions({ name: 'PopoverProperty' });
@ -12,36 +22,36 @@ const formData = useVModel(props, 'modelValue', emit);
</script>
<template>
<el-form label-width="80px" :model="formData">
<ElForm label-width="80px" :model="formData">
<Draggable v-model="formData.list" :empty-item="{ showType: 'once' }">
<template #default="{ element, index }">
<el-form-item label="图片" :prop="`list[${index}].imgUrl`">
<ElFormItem label="图片" :prop="`list[${index}].imgUrl`">
<UploadImg
v-model="element.imgUrl"
height="56px"
width="56px"
:show-description="false"
/>
</el-form-item>
<el-form-item label="跳转链接" :prop="`list[${index}].url`">
</ElFormItem>
<ElFormItem label="跳转链接" :prop="`list[${index}].url`">
<AppLinkInput v-model="element.url" />
</el-form-item>
<el-form-item label="显示次数" :prop="`list[${index}].showType`">
<el-radio-group v-model="element.showType">
<el-tooltip
</ElFormItem>
<ElFormItem label="显示次数" :prop="`list[${index}].showType`">
<ElRadioGroup v-model="element.showType">
<ElTooltip
content="只显示一次,下次打开时不显示"
placement="bottom"
>
<el-radio value="once">一次</el-radio>
</el-tooltip>
<el-tooltip content="每次打开时都会显示" placement="bottom">
<el-radio value="always">不限</el-radio>
</el-tooltip>
</el-radio-group>
</el-form-item>
<ElRadio value="once">一次</ElRadio>
</ElTooltip>
<ElTooltip content="每次打开时都会显示" placement="bottom">
<ElRadio value="always">不限</ElRadio>
</ElTooltip>
</ElRadioGroup>
</ElFormItem>
</template>
</Draggable>
</el-form>
</ElForm>
</template>
<style scoped lang="scss"></style>

View File

@ -1,110 +0,0 @@
<script setup lang="ts">
import type { ProductListProperty } from './config';
import { useVModel } from '@vueuse/core';
import SpuShowcase from '#/views/mall/product/spu/components/spu-showcase.vue';
//
defineOptions({ name: 'ProductListProperty' });
const props = defineProps<{ modelValue: ProductListProperty }>();
const emit = defineEmits(['update:modelValue']);
const formData = useVModel(props, 'modelValue', emit);
</script>
<template>
<ComponentContainerProperty v-model="formData.style">
<el-form label-width="80px" :model="formData">
<el-card header="商品列表" class="property-group" shadow="never">
<SpuShowcase v-model="formData.spuIds" />
</el-card>
<el-card header="商品样式" class="property-group" shadow="never">
<el-form-item label="布局" prop="type">
<el-radio-group v-model="formData.layoutType">
<el-tooltip class="item" content="双列" placement="bottom">
<el-radio-button value="twoCol">
<Icon icon="fluent:text-column-two-24-filled" />
</el-radio-button>
</el-tooltip>
<el-tooltip class="item" content="三列" placement="bottom">
<el-radio-button value="threeCol">
<Icon icon="fluent:text-column-three-24-filled" />
</el-radio-button>
</el-tooltip>
<el-tooltip class="item" content="水平滑动" placement="bottom">
<el-radio-button value="horizSwiper">
<Icon icon="system-uicons:carousel" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item label="商品名称" prop="fields.name.show">
<div class="gap-8px flex">
<ColorInput v-model="formData.fields.name.color" />
<el-checkbox v-model="formData.fields.name.show" />
</div>
</el-form-item>
<el-form-item label="商品价格" prop="fields.price.show">
<div class="gap-8px flex">
<ColorInput v-model="formData.fields.price.color" />
<el-checkbox v-model="formData.fields.price.show" />
</div>
</el-form-item>
</el-card>
<el-card header="角标" class="property-group" shadow="never">
<el-form-item label="角标" prop="badge.show">
<el-switch v-model="formData.badge.show" />
</el-form-item>
<el-form-item
label="角标"
prop="badge.imgUrl"
v-if="formData.badge.show"
>
<UploadImg
v-model="formData.badge.imgUrl"
height="44px"
width="72px"
:show-description="false"
>
<template #tip> 建议尺寸36 * 22 </template>
</UploadImg>
</el-form-item>
</el-card>
<el-card header="商品样式" class="property-group" shadow="never">
<el-form-item label="上圆角" prop="borderRadiusTop">
<el-slider
v-model="formData.borderRadiusTop"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
<el-form-item label="下圆角" prop="borderRadiusBottom">
<el-slider
v-model="formData.borderRadiusBottom"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
<el-form-item label="间隔" prop="space">
<el-slider
v-model="formData.space"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
</el-card>
</el-form>
</ComponentContainerProperty>
</template>
<style scoped lang="scss"></style>

View File

@ -1,150 +0,0 @@
<script setup lang="ts">
import type { TitleBarProperty } from './config';
import { useVModel } from '@vueuse/core';
//
defineOptions({ name: 'TitleBarProperty' });
const props = defineProps<{ modelValue: TitleBarProperty }>();
const emit = defineEmits(['update:modelValue']);
const formData = useVModel(props, 'modelValue', emit);
//
const rules = {};
</script>
<template>
<ComponentContainerProperty v-model="formData.style">
<el-form label-width="85px" :model="formData" :rules="rules">
<el-card header="风格" class="property-group" shadow="never">
<el-form-item label="背景图片" prop="bgImgUrl">
<UploadImg
v-model="formData.bgImgUrl"
width="100%"
height="40px"
:show-description="false"
>
<template #tip>建议尺寸 750*80</template>
</UploadImg>
</el-form-item>
<el-form-item label="标题位置" prop="textAlign">
<el-radio-group v-model="formData!.textAlign">
<el-tooltip content="居左" placement="top">
<el-radio-button value="left">
<Icon icon="ant-design:align-left-outlined" />
</el-radio-button>
</el-tooltip>
<el-tooltip content="居中" placement="top">
<el-radio-button value="center">
<Icon icon="ant-design:align-center-outlined" />
</el-radio-button>
</el-tooltip>
</el-radio-group>
</el-form-item>
<el-form-item label="偏移量" prop="marginLeft" label-width="70px">
<el-slider
v-model="formData.marginLeft"
:max="100"
:min="0"
show-input
input-size="small"
/>
</el-form-item>
<el-form-item label="高度" prop="height" label-width="70px">
<el-slider
v-model="formData.height"
:max="200"
:min="20"
show-input
input-size="small"
/>
</el-form-item>
</el-card>
<el-card header="主标题" class="property-group" shadow="never">
<el-form-item label="文字" prop="title" label-width="40px">
<InputWithColor
v-model="formData.title"
v-model:color="formData.titleColor"
show-word-limit
maxlength="20"
/>
</el-form-item>
<el-form-item label="大小" prop="titleSize" label-width="40px">
<el-slider
v-model="formData.titleSize"
:max="60"
:min="10"
show-input
input-size="small"
/>
</el-form-item>
<el-form-item label="粗细" prop="titleWeight" label-width="40px">
<el-slider
v-model="formData.titleWeight"
:min="100"
:max="900"
:step="100"
show-input
input-size="small"
/>
</el-form-item>
</el-card>
<el-card header="副标题" class="property-group" shadow="never">
<el-form-item label="文字" prop="description" label-width="40px">
<InputWithColor
v-model="formData.description"
v-model:color="formData.descriptionColor"
show-word-limit
maxlength="50"
/>
</el-form-item>
<el-form-item label="大小" prop="descriptionSize" label-width="40px">
<el-slider
v-model="formData.descriptionSize"
:max="60"
:min="10"
show-input
input-size="small"
/>
</el-form-item>
<el-form-item label="粗细" prop="descriptionWeight" label-width="40px">
<el-slider
v-model="formData.descriptionWeight"
:min="100"
:max="900"
:step="100"
show-input
input-size="small"
/>
</el-form-item>
</el-card>
<el-card header="查看更多" class="property-group" shadow="never">
<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 value="text">文字</el-radio>
<el-radio value="icon">图标</el-radio>
<el-radio value="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">
<AppLinkInput v-model="formData.more.url" />
</el-form-item>
</template>
</el-card>
</el-form>
</ComponentContainerProperty>
</template>
<style scoped lang="scss"></style>

View File

@ -1,31 +0,0 @@
<script setup lang="ts">
import type { UserCardProperty } from './config';
/** 用户卡片 */
defineOptions({ name: 'UserCard' });
//
defineProps<{ property: UserCardProperty }>();
</script>
<template>
<div class="flex flex-col">
<div class="p-x-18px p-y-24px flex items-center justify-between">
<div class="gap-16px flex flex-1 items-center">
<el-avatar :size="60">
<Icon icon="ep:avatar" :size="60" />
</el-avatar>
<span class="text-18px font-bold">芋道源码</span>
</div>
<Icon icon="tdesign:qrcode" :size="20" />
</div>
<div
class="p-x-20px p-y-8px text-12px flex items-center justify-between bg-white"
>
<span class="color-#ff690d">点击绑定手机号</span>
<span class="rounded-26px bg-#ff6100 p-x-8px p-y-5px color-white">
去绑定
</span>
</div>
</div>
</template>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,4 @@
// 导出所有优惠券相关组件
export { CouponDiscount } from './coupon-discount';
export { CouponDiscountDesc } from './coupon-discount-desc';
export { CouponValidTerm } from './coupon-validTerm';

View File

@ -22,6 +22,7 @@ import {
import * as CouponTemplateApi from '#/api/mall/promotion/coupon/couponTemplate';
import ColorInput from '#/components/color-input/index.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import {
CouponTemplateTakeTypeEnum,
PromotionDiscountTypeEnum,
@ -91,9 +92,9 @@ watch(
@click="handleAddCoupon"
type="primary"
plain
class="m-t-8px w-full"
class="mt-2 w-full"
>
<IconifyIcon icon="ep:plus" class="mr-5px" /> 添加
<IconifyIcon icon="ep:plus" class="mr-1" /> 添加
</ElButton>
</ElFormItem>
</ElCard>
@ -122,7 +123,7 @@ watch(
v-model="formData.bgImg"
height="80px"
width="100%"
class="min-w-160px"
class="min-w-[160px]"
:show-description="false"
/>
</ElFormItem>

View File

@ -1,6 +1,8 @@
<script setup lang="ts">
import type { HotZoneProperty } from './config';
import { ElImage } from 'element-plus';
/** 热区 */
defineOptions({ name: 'HotZone' });
const props = defineProps<{ property: HotZoneProperty }>();
@ -8,7 +10,7 @@ const props = defineProps<{ property: HotZoneProperty }>();
<template>
<div class="min-h-30px relative h-full w-full">
<el-image
<ElImage
:src="props.property.imgUrl"
class="pointer-events-none h-full w-full select-none"
/>

View File

@ -4,8 +4,11 @@ import type { HotZoneProperty } from './config';
import { ref } from 'vue';
import { useVModel } from '@vueuse/core';
import { ElForm, ElFormItem, ElText, ElButton } from 'element-plus';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import HotZoneEditDialog from './components/HotZoneEditDialog/index.vue';
import HotZoneEditDialog from './components/hot-zone-edit-dialog/index.vue';
/** 热区属性面板 */
defineOptions({ name: 'HotZoneProperty' });
@ -25,30 +28,25 @@ const handleOpenEditDialog = () => {
<template>
<ComponentContainerProperty v-model="formData.style">
<!-- 表单 -->
<el-form label-width="80px" :model="formData" class="m-t-8px">
<el-form-item label="上传图片" prop="imgUrl">
<ElForm label-width="80px" :model="formData" class="mt-2">
<ElFormItem label="上传图片" prop="imgUrl">
<UploadImg
v-model="formData.imgUrl"
height="50px"
width="auto"
class="min-w-80px"
class="min-w-[80px]"
:show-description="false"
>
<template #tip>
<el-text type="info" size="small"> 推荐宽度 750</el-text>
<ElText type="info" size="small"> 推荐宽度 750</ElText>
</template>
</UploadImg>
</el-form-item>
</el-form>
</ElFormItem>
</ElForm>
<el-button
type="primary"
plain
class="w-full"
@click="handleOpenEditDialog"
>
<ElButton type="primary" plain class="w-full" @click="handleOpenEditDialog">
设置热区
</el-button>
</ElButton>
</ComponentContainerProperty>
<!-- 热区编辑对话框 -->
<HotZoneEditDialog

View File

@ -1,6 +1,9 @@
<script setup lang="ts">
import type { ImageBarProperty } from './config';
import { IconifyIcon } from '@vben/icons';
import { ElImage } from 'element-plus';
/** 图片展示 */
defineOptions({ name: 'ImageBar' });
@ -9,12 +12,12 @@ defineProps<{ property: ImageBarProperty }>();
<template>
<!-- 无图片 -->
<div
class="h-50px bg-gray-3 flex items-center justify-center"
class="flex h-12 items-center justify-center bg-gray-300"
v-if="!property.imgUrl"
>
<Icon icon="ep:picture" class="text-gray-8 text-30px!" />
<IconifyIcon icon="ep:picture" class="text-3xl text-gray-600" />
</div>
<el-image class="min-h-30px" v-else :src="property.imgUrl" />
<ElImage class="min-h-8" v-else :src="property.imgUrl" />
</template>
<style scoped lang="scss">

View File

@ -2,6 +2,10 @@
import type { ImageBarProperty } from './config';
import { useVModel } from '@vueuse/core';
import { ElForm, ElFormItem } from 'element-plus';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import AppLinkInput from '#/components/app-link-input/index.vue';
//
defineOptions({ name: 'ImageBarProperty' });
@ -13,23 +17,23 @@ const formData = useVModel(props, 'modelValue', emit);
<template>
<ComponentContainerProperty v-model="formData.style">
<el-form label-width="80px" :model="formData">
<el-form-item label="上传图片" prop="imgUrl">
<ElForm label-width="80px" :model="formData">
<ElFormItem label="上传图片" prop="imgUrl">
<UploadImg
v-model="formData.imgUrl"
draggable="false"
height="80px"
width="100%"
class="min-w-80px"
class="min-w-[80px]"
:show-description="false"
>
<template #tip> 建议宽度750 </template>
</UploadImg>
</el-form-item>
<el-form-item label="链接" prop="url">
</ElFormItem>
<ElFormItem label="链接" prop="url">
<AppLinkInput v-model="formData.url" />
</el-form-item>
</el-form>
</ElFormItem>
</ElForm>
</ComponentContainerProperty>
</template>

View File

@ -31,6 +31,10 @@ export interface MagicCubeItemProperty {
top: number;
// 左
left: number;
// 右
right: number;
// 下
bottom: number;
}
// 定义组件

View File

@ -1,6 +1,9 @@
<script setup lang="ts">
import type { MagicCubeProperty } from './config';
import { ElImage } from 'element-plus';
import { IconifyIcon } from '@vben/icons';
import { computed } from 'vue';
/** 广告魔方 */
@ -48,7 +51,7 @@ const rowCount = computed(() => {
left: `${item.left * CUBE_SIZE}px`,
}"
>
<el-image
<ElImage
class="h-full w-full"
fit="cover"
:src="item.imgUrl"
@ -68,11 +71,11 @@ const rowCount = computed(() => {
height: `${item.height * CUBE_SIZE}px`,
}"
>
<Icon icon="ep-picture" color="gray" :size="CUBE_SIZE" />
<IconifyIcon icon="ep-picture" color="gray" :size="CUBE_SIZE" />
</div>
</div>
</template>
</el-image>
</ElImage>
</div>
</div>
</template>

View File

@ -4,6 +4,11 @@ import type { MagicCubeProperty } from './config';
import { ref } from 'vue';
import { useVModel } from '@vueuse/core';
import { ElForm, ElFormItem, ElSlider, ElText } from 'element-plus';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import AppLinkInput from '#/components/app-link-input/index.vue';
import MagicCubeEditor from '#/components/magic-cube-editor/index.vue';
/** 广告魔方属性面板 */
defineOptions({ name: 'MagicCubeProperty' });
@ -22,11 +27,11 @@ const handleHotAreaSelected = (_: any, index: number) => {
<template>
<ComponentContainerProperty v-model="formData.style">
<!-- 表单 -->
<el-form label-width="80px" :model="formData" class="m-t-8px">
<el-text tag="p"> 魔方设置 </el-text>
<el-text type="info" size="small"> 每格尺寸187 * 187 </el-text>
<ElForm label-width="80px" :model="formData" class="mt-2">
<ElText tag="p"> 魔方设置 </ElText>
<ElText type="info" size="small"> 每格尺寸187 * 187 </ElText>
<MagicCubeEditor
class="m-y-16px"
class="my-4"
v-model="formData.list"
:rows="4"
:cols="4"
@ -34,21 +39,21 @@ const handleHotAreaSelected = (_: any, index: number) => {
/>
<template v-for="(hotArea, index) in formData.list" :key="index">
<template v-if="selectedHotAreaIndex === index">
<el-form-item label="上传图片" :prop="`list[${index}].imgUrl`">
<ElFormItem label="上传图片" :prop="`list[${index}].imgUrl`">
<UploadImg
v-model="hotArea.imgUrl"
height="80px"
width="80px"
:show-description="false"
/>
</el-form-item>
<el-form-item label="链接" :prop="`list[${index}].url`">
</ElFormItem>
<ElFormItem label="链接" :prop="`list[${index}].url`">
<AppLinkInput v-model="hotArea.url" />
</el-form-item>
</ElFormItem>
</template>
</template>
<el-form-item label="上圆角" prop="borderRadiusTop">
<el-slider
<ElFormItem label="上圆角" prop="borderRadiusTop">
<ElSlider
v-model="formData.borderRadiusTop"
:max="100"
:min="0"
@ -56,9 +61,9 @@ const handleHotAreaSelected = (_: any, index: number) => {
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
<el-form-item label="下圆角" prop="borderRadiusBottom">
<el-slider
</ElFormItem>
<ElFormItem label="下圆角" prop="borderRadiusBottom">
<ElSlider
v-model="formData.borderRadiusBottom"
:max="100"
:min="0"
@ -66,9 +71,9 @@ const handleHotAreaSelected = (_: any, index: number) => {
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
<el-form-item label="间隔" prop="space">
<el-slider
</ElFormItem>
<ElFormItem label="间隔" prop="space">
<ElSlider
v-model="formData.space"
:max="100"
:min="0"
@ -76,8 +81,8 @@ const handleHotAreaSelected = (_: any, index: number) => {
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
</el-form>
</ElFormItem>
</ElForm>
</ComponentContainerProperty>
</template>

View File

@ -12,7 +12,7 @@ import {
} from 'element-plus';
import AppLinkInput from '#/components/app-link-input/index.vue';
import ComponentContainerProperty from '#/components/diy-editor/components/ComponentContainerProperty.vue';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import Draggable from '#/components/draggable/index.vue';
import UploadImg from '#/components/upload/image-upload.vue';
@ -29,7 +29,7 @@ const formData = useVModel(props, 'modelValue', emit);
<template>
<ComponentContainerProperty v-model="formData.style">
<!-- 表单 -->
<ElForm label-width="80px" :model="formData" class="m-t-8px">
<ElForm label-width="80px" :model="formData" class="mt-2">
<ElFormItem label="每行数量" prop="column">
<ElRadioGroup v-model="formData.column">
<ElRadio :value="3">3</ElRadio>

View File

@ -0,0 +1,44 @@
<script setup lang="ts">
import type { MenuListProperty } from './config';
import { IconifyIcon } from '@vben/icons';
import { ElImage } from 'element-plus';
/** 列表导航 */
defineOptions({ name: 'MenuList' });
defineProps<{ property: MenuListProperty }>();
</script>
<template>
<div class="min-h-[42px] flex flex-col">
<div
v-for="(item, index) in property.list"
:key="index"
class="item h-[42px] gap-1 px-3 flex flex-row items-center justify-between"
>
<div class="gap-2 flex flex-1 flex-row items-center">
<ElImage
v-if="item.iconUrl"
class="h-4 w-4"
:src="item.iconUrl"
/>
<span class="text-base" :style="{ color: item.titleColor }">{{
item.title
}}</span>
</div>
<div class="item-center gap-1 flex flex-row justify-center">
<span class="text-xs" :style="{ color: item.subtitleColor }">{{
item.subtitle
}}</span>
<IconifyIcon icon="ep:arrow-right" color="#000" :size="16" />
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.item + .item {
border-top: 1px solid #eee;
}
</style>

View File

@ -2,8 +2,14 @@
import type { MenuListProperty } from './config';
import { useVModel } from '@vueuse/core';
import { ElForm, ElFormItem, ElText } from 'element-plus';
import { EMPTY_MENU_LIST_ITEM_PROPERTY } from './config';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import Draggable from '#/components/draggable/index.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import InputWithColor from '#/components/input-with-color/index.vue';
import AppLinkInput from '#/components/app-link-input/index.vue';
/** 列表导航属性面板 */
defineOptions({ name: 'MenuListProperty' });
@ -15,17 +21,17 @@ const formData = useVModel(props, 'modelValue', emit);
<template>
<ComponentContainerProperty v-model="formData.style">
<el-text tag="p"> 菜单设置 </el-text>
<el-text type="info" size="small"> 拖动左侧的小圆点可以调整顺序 </el-text>
<ElText tag="p"> 菜单设置 </ElText>
<ElText type="info" size="small"> 拖动左侧的小圆点可以调整顺序 </ElText>
<!-- 表单 -->
<el-form label-width="60px" :model="formData" class="m-t-8px">
<ElForm label-width="60px" :model="formData" class="mt-2">
<Draggable
v-model="formData.list"
:empty-item="EMPTY_MENU_LIST_ITEM_PROPERTY"
>
<template #default="{ element }">
<el-form-item label="图标" prop="iconUrl">
<ElFormItem label="图标" prop="iconUrl">
<UploadImg
v-model="element.iconUrl"
height="80px"
@ -34,25 +40,25 @@ const formData = useVModel(props, 'modelValue', emit);
>
<template #tip> 建议尺寸44 * 44 </template>
</UploadImg>
</el-form-item>
<el-form-item label="标题" prop="title">
</ElFormItem>
<ElFormItem label="标题" prop="title">
<InputWithColor
v-model="element.title"
v-model:color="element.titleColor"
/>
</el-form-item>
<el-form-item label="副标题" prop="subtitle">
</ElFormItem>
<ElFormItem label="副标题" prop="subtitle">
<InputWithColor
v-model="element.subtitle"
v-model:color="element.subtitleColor"
/>
</el-form-item>
<el-form-item label="链接" prop="url">
</ElFormItem>
<ElFormItem label="链接" prop="url">
<AppLinkInput v-model="element.url" />
</el-form-item>
</ElFormItem>
</template>
</Draggable>
</el-form>
</ElForm>
</ComponentContainerProperty>
</template>

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import type { MenuSwiperItemProperty, MenuSwiperProperty } from './config';
import { ElCarousel, ElCarouselItem, ElImage } from 'element-plus';
import { ref, watch } from 'vue';
/** 菜单导航 */
@ -59,13 +60,13 @@ watch(
</script>
<template>
<el-carousel
<ElCarousel
:height="`${carouselHeight}px`"
:autoplay="false"
arrow="hover"
indicator-position="outside"
>
<el-carousel-item v-for="(page, pageIndex) in pages" :key="pageIndex">
<ElCarouselItem v-for="(page, pageIndex) in pages" :key="pageIndex">
<div class="flex flex-row flex-wrap">
<div
v-for="(item, index) in page"
@ -78,7 +79,7 @@ watch(
<!-- 右上角角标 -->
<span
v-if="item.badge?.show"
class="right--10px top--10px z-1 h-20px rounded-10px p-x-6px text-12px leading-20px absolute text-center"
class="absolute -right-2.5 -top-2.5 z-10 h-5 rounded-[10px] px-1.5 text-center text-xs leading-5"
:style="{
color: item.badge.textColor,
backgroundColor: item.badge.bgColor,
@ -86,7 +87,7 @@ watch(
>
{{ item.badge.text }}
</span>
<el-image
<ElImage
v-if="item.iconUrl"
:src="item.iconUrl"
class="h-full w-full"
@ -95,7 +96,7 @@ watch(
<!-- 标题 -->
<span
v-if="property.layout === 'iconText'"
class="text-12px"
class="text-xs"
:style="{
color: item.titleColor,
height: `${TITLE_HEIGHT}px`,
@ -106,8 +107,8 @@ watch(
</span>
</div>
</div>
</el-carousel-item>
</el-carousel>
</ElCarouselItem>
</ElCarousel>
</template>
<style lang="scss">

View File

@ -0,0 +1,103 @@
<script setup lang="ts">
import type { MenuSwiperProperty } from './config';
import { cloneDeep } from '@vben/utils';
import {
ElCard,
ElForm,
ElFormItem,
ElRadio,
ElRadioGroup,
ElSwitch,
} from 'element-plus';
import { useVModel } from '@vueuse/core';
import { EMPTY_MENU_SWIPER_ITEM_PROPERTY } from './config';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import Draggable from '#/components/draggable/index.vue';
import InputWithColor from '#/components/input-with-color/index.vue';
import AppLinkInput from '#/components/app-link-input/index.vue';
import ColorInput from '#/components/color-input/index.vue';
/** 菜单导航属性面板 */
defineOptions({ name: 'MenuSwiperProperty' });
const props = defineProps<{ modelValue: MenuSwiperProperty }>();
const emit = defineEmits(['update:modelValue']);
const formData = useVModel(props, 'modelValue', emit);
</script>
<template>
<ComponentContainerProperty v-model="formData.style">
<!-- 表单 -->
<ElForm label-width="80px" :model="formData" class="mt-2">
<ElFormItem label="布局" prop="layout">
<ElRadioGroup v-model="formData.layout">
<ElRadio value="iconText">图标+文字</ElRadio>
<ElRadio value="icon">仅图标</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="行数" prop="row">
<ElRadioGroup v-model="formData.row">
<ElRadio :value="1">1</ElRadio>
<ElRadio :value="2">2</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="列数" prop="column">
<ElRadioGroup v-model="formData.column">
<ElRadio :value="3">3</ElRadio>
<ElRadio :value="4">4</ElRadio>
<ElRadio :value="5">5</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElCard header="菜单设置" class="property-group" shadow="never">
<Draggable
v-model="formData.list"
:empty-item="cloneDeep(EMPTY_MENU_SWIPER_ITEM_PROPERTY)"
>
<template #default="{ element }">
<ElFormItem label="图标" prop="iconUrl">
<UploadImg
v-model="element.iconUrl"
height="80px"
width="80px"
:show-description="false"
>
<template #tip> 建议尺寸98 * 98 </template>
</UploadImg>
</ElFormItem>
<ElFormItem label="标题" prop="title">
<InputWithColor
v-model="element.title"
v-model:color="element.titleColor"
/>
</ElFormItem>
<ElFormItem label="链接" prop="url">
<AppLinkInput v-model="element.url" />
</ElFormItem>
<ElFormItem label="显示角标" prop="badge.show">
<ElSwitch v-model="element.badge.show" />
</ElFormItem>
<template v-if="element.badge.show">
<ElFormItem label="角标内容" prop="badge.text">
<InputWithColor
v-model="element.badge.text"
v-model:color="element.badge.textColor"
/>
</ElFormItem>
<ElFormItem label="背景颜色" prop="badge.bgColor">
<ColorInput v-model="element.badge.bgColor" />
</ElFormItem>
</template>
</template>
</Draggable>
</ElCard>
</ElForm>
</ComponentContainerProperty>
</template>
<style scoped lang="scss"></style>

View File

@ -6,12 +6,12 @@ import type {
NavigationBarProperty,
} from './config';
import type { SearchProperty } from '#/components/diy-editor/components/mobile/SearchBar/config';
import type { SearchProperty } from '#/components/diy-editor/components/mobile/search-bar/config';
import { computed } from 'vue';
import appNavbarMp from '#/assets/imgs/diy/app-nav-bar-mp.png';
import SearchBar from '#/components/diy-editor/components/mobile/SearchBar/index.vue';
import SearchBar from '#/components/diy-editor/components/mobile/search-bar/index.vue';
/** 页面顶部导航栏 */
defineOptions({ name: 'NavigationBar' });

View File

@ -3,7 +3,7 @@ import type { NavigationBarProperty } from './config';
import { useVModel } from '@vueuse/core';
import NavigationBarCellProperty from './components/CellProperty.vue';
import NavigationBarCellProperty from './components/cell-property.vue';
//
defineOptions({ name: 'NavigationBarProperty' });
@ -79,7 +79,7 @@ if (!formData.value._local) {
<template #header>
<div class="flex items-center justify-between">
<span>内容小程序</span>
<el-form-item prop="_local.previewMp" class="m-b-0!">
<el-form-item prop="_local.previewMp" class="mb-0">
<el-checkbox
v-model="formData._local.previewMp"
@change="
@ -97,7 +97,7 @@ if (!formData.value._local) {
<template #header>
<div class="flex items-center justify-between">
<span>内容非小程序</span>
<el-form-item prop="_local.previewOther" class="m-b-0!">
<el-form-item prop="_local.previewOther" class="mb-0">
<el-checkbox
v-model="formData._local.previewOther"
@change="

View File

@ -0,0 +1,37 @@
<script setup lang="ts">
import type { NoticeBarProperty } from './config';
import { ElCarousel, ElCarouselItem, ElImage, ElDivider } from 'element-plus';
import { IconifyIcon } from '@vben/icons';
/** 公告栏 */
defineOptions({ name: 'NoticeBar' });
defineProps<{ property: NoticeBarProperty }>();
</script>
<template>
<div
class="py-1 text-xs flex items-center"
:style="{
backgroundColor: property.backgroundColor,
color: property.textColor,
}"
>
<ElImage :src="property.iconUrl" class="h-[18px]" />
<ElDivider direction="vertical" />
<ElCarousel
height="24px"
direction="vertical"
:autoplay="true"
class="pr-2 flex-1"
>
<ElCarouselItem v-for="(item, index) in property.contents" :key="index">
<div class="h-6 leading-6 truncate">{{ item.text }}</div>
</ElCarouselItem>
</ElCarousel>
<IconifyIcon icon="ep:arrow-right" />
</div>
</template>
<style scoped lang="scss"></style>

View File

@ -1,8 +1,16 @@
<script setup lang="ts">
import type { NoticeBarProperty } from './config';
import { ElCard, ElForm, ElFormItem, ElInput } from 'element-plus';
import { useVModel } from '@vueuse/core';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import Draggable from '#/components/draggable/index.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import AppLinkInput from '#/components/app-link-input/index.vue';
import ColorInput from '#/components/color-input/index.vue';
//
defineOptions({ name: 'NoticeBarProperty' });
const props = defineProps<{ modelValue: NoticeBarProperty }>();
@ -19,8 +27,8 @@ const formData = useVModel(props, 'modelValue', emit);
<template>
<ComponentContainerProperty v-model="formData.style">
<el-form label-width="80px" :model="formData" :rules="rules">
<el-form-item label="公告图标" prop="iconUrl">
<ElForm label-width="80px" :model="formData" :rules="rules">
<ElFormItem label="公告图标" prop="iconUrl">
<UploadImg
v-model="formData.iconUrl"
height="48px"
@ -28,26 +36,26 @@ const formData = useVModel(props, 'modelValue', emit);
>
<template #tip>建议尺寸24 * 24</template>
</UploadImg>
</el-form-item>
<el-form-item label="背景颜色" prop="backgroundColor">
</ElFormItem>
<ElFormItem label="背景颜色" prop="backgroundColor">
<ColorInput v-model="formData.backgroundColor" />
</el-form-item>
<el-form-item label="文字颜色" prop="文字颜色">
</ElFormItem>
<ElFormItem label="文字颜色" prop="文字颜色">
<ColorInput v-model="formData.textColor" />
</el-form-item>
<el-card header="公告内容" class="property-group" shadow="never">
</ElFormItem>
<ElCard header="公告内容" class="property-group" shadow="never">
<Draggable v-model="formData.contents">
<template #default="{ element }">
<el-form-item label="公告" prop="text" label-width="40px">
<el-input v-model="element.text" placeholder="请输入公告" />
</el-form-item>
<el-form-item label="链接" prop="url" label-width="40px">
<ElFormItem label="公告" prop="text" label-width="40px">
<ElInput v-model="element.text" placeholder="请输入公告" />
</ElFormItem>
<ElFormItem label="链接" prop="url" label-width="40px">
<AppLinkInput v-model="element.url" />
</el-form-item>
</ElFormItem>
</template>
</Draggable>
</el-card>
</el-form>
</ElCard>
</ElForm>
</ComponentContainerProperty>
</template>

View File

@ -2,6 +2,9 @@
import type { PageConfigProperty } from './config';
import { useVModel } from '@vueuse/core';
import { ElForm, ElFormItem, ElInput } from 'element-plus';
import ColorInput from '#/components/input-with-color/index.vue';
import UploadImg from '#/components/upload/image-upload.vue';
//
defineOptions({ name: 'PageConfigProperty' });
@ -16,18 +19,18 @@ const formData = useVModel(props, 'modelValue', emit);
</script>
<template>
<el-form label-width="80px" :model="formData" :rules="rules">
<el-form-item label="页面描述" prop="description">
<el-input
<ElForm label-width="80px" :model="formData" :rules="rules">
<ElFormItem label="页面描述" prop="description">
<ElInput
type="textarea"
v-model="formData!.description"
placeholder="用户通过微信分享给朋友时,会自动显示页面描述"
/>
</el-form-item>
<el-form-item label="背景颜色" prop="backgroundColor">
</ElFormItem>
<ElFormItem label="背景颜色" prop="backgroundColor">
<ColorInput v-model="formData!.backgroundColor" />
</el-form-item>
<el-form-item label="背景图片" prop="backgroundImage">
</ElFormItem>
<ElFormItem label="背景图片" prop="backgroundImage">
<UploadImg
v-model="formData!.backgroundImage"
:limit="1"
@ -35,8 +38,8 @@ const formData = useVModel(props, 'modelValue', emit);
>
<template #tip>建议宽度 750px</template>
</UploadImg>
</el-form-item>
</el-form>
</ElFormItem>
</ElForm>
</template>
<style scoped lang="scss"></style>

View File

@ -56,37 +56,37 @@ const formData = useVModel(props, 'modelValue', emit);
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="商品名称" prop="fields.name.show">
<div class="gap-8px flex">
<div class="gap-2 flex">
<ColorInput v-model="formData.fields.name.color" />
<ElCheckbox v-model="formData.fields.name.show" />
</div>
</ElFormItem>
<ElFormItem label="商品简介" prop="fields.introduction.show">
<div class="gap-8px flex">
<div class="gap-2 flex">
<ColorInput v-model="formData.fields.introduction.color" />
<ElCheckbox v-model="formData.fields.introduction.show" />
</div>
</ElFormItem>
<ElFormItem label="商品价格" prop="fields.price.show">
<div class="gap-8px flex">
<div class="gap-2 flex">
<ColorInput v-model="formData.fields.price.color" />
<ElCheckbox v-model="formData.fields.price.show" />
</div>
</ElFormItem>
<ElFormItem label="市场价" prop="fields.marketPrice.show">
<div class="gap-8px flex">
<div class="gap-2 flex">
<ColorInput v-model="formData.fields.marketPrice.color" />
<ElCheckbox v-model="formData.fields.marketPrice.show" />
</div>
</ElFormItem>
<ElFormItem label="商品销量" prop="fields.salesCount.show">
<div class="gap-8px flex">
<div class="gap-2 flex">
<ColorInput v-model="formData.fields.salesCount.color" />
<ElCheckbox v-model="formData.fields.salesCount.show" />
</div>
</ElFormItem>
<ElFormItem label="商品库存" prop="fields.stock.show">
<div class="gap-8px flex">
<div class="gap-2 flex">
<ColorInput v-model="formData.fields.stock.color" />
<ElCheckbox v-model="formData.fields.stock.show" />
</div>

View File

@ -6,6 +6,7 @@ import type { MallSpuApi } from '#/api/mall/product/spu';
import { onMounted, ref, watch } from 'vue';
import { fenToYuan } from '@vben/utils';
import { ElImage, ElScrollbar } from 'element-plus';
import * as ProductSpuApi from '#/api/mall/product/spu';
@ -73,7 +74,7 @@ onMounted(() => {
});
</script>
<template>
<el-scrollbar class="z-1 min-h-30px" wrap-class="w-full" ref="containerRef">
<ElScrollbar class="z-10 min-h-[30px]" wrap-class="w-full" ref="containerRef">
<!-- 商品网格 -->
<div
class="grid overflow-x-auto"
@ -98,22 +99,22 @@ onMounted(() => {
<!-- 角标 -->
<div
v-if="property.badge.show"
class="z-1 absolute left-0 top-0 items-center justify-center"
class="absolute left-0 top-0 z-10 items-center justify-center"
>
<el-image
<ElImage
fit="cover"
:src="property.badge.imgUrl"
class="h-26px w-38px"
class="h-[26px] w-[38px]"
/>
</div>
<!-- 商品封面图 -->
<el-image
<ElImage
fit="cover"
:src="spu.picUrl"
:style="{ width: imageSize, height: imageSize }"
/>
<div
class="gap-8px p-8px box-border flex flex-col"
class="box-border flex flex-col gap-2 p-2"
:class="[
{
'w-[calc(100%-64px)]': columns === 2,
@ -124,7 +125,7 @@ onMounted(() => {
<!-- 商品名称 -->
<div
v-if="property.fields.name.show"
class="text-12px truncate"
class="truncate text-xs"
:style="{ color: property.fields.name.color }"
>
{{ spu.name }}
@ -133,7 +134,7 @@ onMounted(() => {
<!-- 商品价格 -->
<span
v-if="property.fields.price.show"
class="text-12px"
class="text-xs"
:style="{ color: property.fields.price.color }"
>
{{ fenToYuan(spu.price || 0) }}
@ -142,7 +143,7 @@ onMounted(() => {
</div>
</div>
</div>
</el-scrollbar>
</ElScrollbar>
</template>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,119 @@
<script setup lang="ts">
import type { ProductListProperty } from './config';
import { useVModel } from '@vueuse/core';
import {
ElForm,
ElFormItem,
ElCard,
ElRadioGroup,
ElRadioButton,
ElSlider,
ElSwitch,
ElTooltip,
} from 'element-plus';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import ColorInput from '#/components/input-with-color/index.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import SpuShowcase from '#/views/mall/product/spu/components/spu-showcase.vue';
//
defineOptions({ name: 'ProductListProperty' });
const props = defineProps<{ modelValue: ProductListProperty }>();
const emit = defineEmits(['update:modelValue']);
const formData = useVModel(props, 'modelValue', emit);
</script>
<template>
<ComponentContainerProperty v-model="formData.style">
<ElForm label-width="80px" :model="formData">
<ElCard header="商品列表" class="property-group" shadow="never">
<SpuShowcase v-model="formData.spuIds" />
</ElCard>
<ElCard header="商品样式" class="property-group" shadow="never">
<ElFormItem label="布局" prop="type">
<ElRadioGroup v-model="formData.layoutType">
<ElTooltip class="item" content="双列" placement="bottom">
<ElRadioButton value="twoCol">
<IconifyIcon icon="fluent:text-column-two-24-filled" />
</ElRadioButton>
</ElTooltip>
<ElTooltip class="item" content="三列" placement="bottom">
<ElRadioButton value="threeCol">
<IconifyIcon icon="fluent:text-column-three-24-filled" />
</ElRadioButton>
</ElTooltip>
<ElTooltip class="item" content="水平滑动" placement="bottom">
<ElRadioButton value="horizSwiper">
<IconifyIcon icon="system-uicons:carousel" />
</ElRadioButton>
</ElTooltip>
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="商品名称" prop="fields.name.show">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.name.color" />
<ElCheckbox v-model="formData.fields.name.show" />
</div>
</ElFormItem>
<ElFormItem label="商品价格" prop="fields.price.show">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.price.color" />
<ElCheckbox v-model="formData.fields.price.show" />
</div>
</ElFormItem>
</ElCard>
<ElCard header="角标" class="property-group" shadow="never">
<ElFormItem label="角标" prop="badge.show">
<el-switch v-model="formData.badge.show" />
</ElFormItem>
<ElFormItem label="角标" prop="badge.imgUrl" v-if="formData.badge.show">
<UploadImg
v-model="formData.badge.imgUrl"
height="44px"
width="72px"
:show-description="false"
>
<template #tip> 建议尺寸36 * 22 </template>
</UploadImg>
</ElFormItem>
</ElCard>
<ElCard header="商品样式" class="property-group" shadow="never">
<ElFormItem label="上圆角" prop="borderRadiusTop">
<ElSlider
v-model="formData.borderRadiusTop"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</ElFormItem>
<ElFormItem label="下圆角" prop="borderRadiusBottom">
<ElSlider
v-model="formData.borderRadiusBottom"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</ElFormItem>
<ElFormItem label="间隔" prop="space">
<ElSlider
v-model="formData.space"
:max="100"
:min="0"
show-input
input-size="small"
:show-input-controls="false"
/>
</ElFormItem>
</ElCard>
</ElForm>
</ComponentContainerProperty>
</template>
<style scoped lang="scss"></style>

View File

@ -27,7 +27,7 @@ watch(
);
</script>
<template>
<div class="min-h-30px" v-dompurify-html="article?.content"></div>
<div class="min-h-[30px]" v-dompurify-html="article?.content"></div>
</template>
<style scoped lang="scss"></style>

View File

@ -6,7 +6,8 @@ import type { MallArticleApi } from '#/api/mall/promotion/article';
import { onMounted, ref } from 'vue';
import { useVModel } from '@vueuse/core';
import { ElForm, ElFormItem, ElSelect, ElOption } from 'element-plus';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import * as ArticleApi from '#/api/mall/promotion/article/index';
//
@ -40,9 +41,9 @@ onMounted(() => {
<template>
<ComponentContainerProperty v-model="formData.style">
<el-form label-width="40px" :model="formData">
<el-form-item label="文章" prop="id">
<el-select
<ElForm label-width="40px" :model="formData">
<ElFormItem label="文章" prop="id">
<ElSelect
v-model="formData.id"
placeholder="请选择文章"
class="w-full"
@ -51,15 +52,15 @@ onMounted(() => {
:remote-method="queryArticleList"
:loading="loading"
>
<el-option
<ElOption
v-for="article in articles"
:key="article.id"
:label="article.title"
:value="article.id"
/>
</el-select>
</el-form-item>
</el-form>
</ElSelect>
</ElFormItem>
</ElForm>
</ComponentContainerProperty>
</template>

View File

@ -139,7 +139,7 @@ const calculateWidth = () => {
<ElImage fit="cover" class="h-full w-full" :src="spu.picUrl" />
</div>
<div
class="box-border flex flex-col gap-[8px] p-[8px]"
class="box-border flex flex-col gap-2 p-2"
:class="[
{
'w-full': property.layoutType !== 'oneColSmallImg',

View File

@ -74,37 +74,37 @@ onMounted(async () => {
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="商品名称" prop="fields.name.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.name.color" />
<ElCheckbox v-model="formData.fields.name.show" />
</div>
</ElFormItem>
<ElFormItem label="商品简介" prop="fields.introduction.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.introduction.color" />
<ElCheckbox v-model="formData.fields.introduction.show" />
</div>
</ElFormItem>
<ElFormItem label="商品价格" prop="fields.price.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.price.color" />
<ElCheckbox v-model="formData.fields.price.show" />
</div>
</ElFormItem>
<ElFormItem label="市场价" prop="fields.marketPrice.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.marketPrice.color" />
<ElCheckbox v-model="formData.fields.marketPrice.show" />
</div>
</ElFormItem>
<ElFormItem label="商品销量" prop="fields.salesCount.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.salesCount.color" />
<ElCheckbox v-model="formData.fields.salesCount.show" />
</div>
</ElFormItem>
<ElFormItem label="商品库存" prop="fields.stock.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.stock.color" />
<ElCheckbox v-model="formData.fields.stock.show" />
</div>

View File

@ -135,7 +135,7 @@ const calculateWidth = () => {
<ElImage :src="spu.picUrl" class="h-full w-full" fit="cover" />
</div>
<div
class="box-border flex flex-col gap-[8px] p-[8px]"
class="box-border flex flex-col gap-2 p-2"
:class="[
{
'w-full': property.layoutType !== 'oneColSmallImg',

View File

@ -59,37 +59,37 @@ const formData = useVModel(props, 'modelValue', emit);
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="商品名称" prop="fields.name.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.name.color" />
<ElCheckbox v-model="formData.fields.name.show" />
</div>
</ElFormItem>
<ElFormItem label="商品简介" prop="fields.introduction.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.introduction.color" />
<ElCheckbox v-model="formData.fields.introduction.show" />
</div>
</ElFormItem>
<ElFormItem label="商品价格" prop="fields.price.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.price.color" />
<ElCheckbox v-model="formData.fields.price.show" />
</div>
</ElFormItem>
<ElFormItem label="市场价" prop="fields.marketPrice.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.marketPrice.color" />
<ElCheckbox v-model="formData.fields.marketPrice.show" />
</div>
</ElFormItem>
<ElFormItem label="商品销量" prop="fields.salesCount.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.salesCount.color" />
<ElCheckbox v-model="formData.fields.salesCount.show" />
</div>
</ElFormItem>
<ElFormItem label="商品库存" prop="fields.stock.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.stock.color" />
<ElCheckbox v-model="formData.fields.stock.show" />
</div>

View File

@ -76,37 +76,37 @@ onMounted(async () => {
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="商品名称" prop="fields.name.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.name.color" />
<ElCheckbox v-model="formData.fields.name.show" />
</div>
</ElFormItem>
<ElFormItem label="商品简介" prop="fields.introduction.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.introduction.color" />
<ElCheckbox v-model="formData.fields.introduction.show" />
</div>
</ElFormItem>
<ElFormItem label="商品价格" prop="fields.price.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.price.color" />
<ElCheckbox v-model="formData.fields.price.show" />
</div>
</ElFormItem>
<ElFormItem label="市场价" prop="fields.marketPrice.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.marketPrice.color" />
<ElCheckbox v-model="formData.fields.marketPrice.show" />
</div>
</ElFormItem>
<ElFormItem label="商品销量" prop="fields.salesCount.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.salesCount.color" />
<ElCheckbox v-model="formData.fields.salesCount.show" />
</div>
</ElFormItem>
<ElFormItem label="商品库存" prop="fields.stock.show">
<div class="gap-8px flex">
<div class="flex gap-2">
<ColorInput v-model="formData.fields.stock.color" />
<ElCheckbox v-model="formData.fields.stock.show" />
</div>

View File

@ -18,7 +18,7 @@ import {
ElTooltip,
} from 'element-plus';
import ComponentContainerProperty from '#/components/diy-editor/components/ComponentContainerProperty.vue';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import Draggable from '#/components/draggable/index.vue';
/** 搜索框属性面板 */
@ -45,7 +45,7 @@ watch(
<template>
<ComponentContainerProperty v-model="formData.style">
<!-- 表单 -->
<ElForm label-width="80px" :model="formData" class="m-t-8px">
<ElForm label-width="80px" :model="formData" class="mt-2">
<ElCard header="搜索热词" class="property-group" shadow="never">
<Draggable
v-model="formData.hotKeywords"

View File

@ -1,6 +1,9 @@
<script setup lang="ts">
import type { TitleBarProperty } from './config';
import { ElImage } from 'element-plus';
import { IconifyIcon } from '@vben/icons';
/** 标题栏 */
defineOptions({ name: 'TitleBar' });
@ -8,7 +11,7 @@ defineProps<{ property: TitleBarProperty }>();
</script>
<template>
<div class="title-bar" :style="{ height: `${property.height}px` }">
<el-image
<ElImage
v-if="property.bgImgUrl"
:src="property.bgImgUrl"
fit="cover"
@ -56,7 +59,7 @@ defineProps<{ property: TitleBarProperty }>();
<span v-if="property.more.type !== 'icon'">
{{ property.more.text }}
</span>
<Icon icon="ep:arrow-right" v-if="property.more.type !== 'text'" />
<IconifyIcon icon="ep:arrow-right" v-if="property.more.type !== 'text'" />
</div>
</div>
</template>

View File

@ -0,0 +1,167 @@
<script setup lang="ts">
import type { TitleBarProperty } from './config';
import { useVModel } from '@vueuse/core';
import {
ElForm,
ElFormItem,
ElRadioButton,
ElRadioGroup,
ElSlider,
ElTooltip,
ElInput,
ElCheckbox,
ElCard,
} from 'element-plus';
import { IconifyIcon } from '@vben/icons';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import UploadImg from '#/components/upload/image-upload.vue';
import InputWithColor from '#/components/input-with-color/index.vue';
import AppLinkInput from '#/components/app-link-input/index.vue';
//
defineOptions({ name: 'TitleBarProperty' });
const props = defineProps<{ modelValue: TitleBarProperty }>();
const emit = defineEmits(['update:modelValue']);
const formData = useVModel(props, 'modelValue', emit);
//
const rules = {};
</script>
<template>
<ComponentContainerProperty v-model="formData.style">
<ElForm label-width="85px" :model="formData" :rules="rules">
<ElCard header="风格" class="property-group" shadow="never">
<ElFormItem label="背景图片" prop="bgImgUrl">
<UploadImg
v-model="formData.bgImgUrl"
width="100%"
height="40px"
:show-description="false"
>
<template #tip>建议尺寸 750*80</template>
</UploadImg>
</ElFormItem>
<ElFormItem label="标题位置" prop="textAlign">
<ElRadioGroup v-model="formData!.textAlign">
<ElTooltip content="居左" placement="top">
<ElRadioButton value="left">
<IconifyIcon icon="ant-design:align-left-outlined" />
</ElRadioButton>
</ElTooltip>
<ElTooltip content="居中" placement="top">
<ElRadioButton value="center">
<IconifyIcon icon="ant-design:align-center-outlined" />
</ElRadioButton>
</ElTooltip>
</ElRadioGroup>
</ElFormItem>
<ElFormItem label="偏移量" prop="marginLeft" label-width="70px">
<el-slider
v-model="formData.marginLeft"
:max="100"
:min="0"
show-input
input-size="small"
/>
</ElFormItem>
<ElFormItem label="高度" prop="height" label-width="70px">
<el-slider
v-model="formData.height"
:max="200"
:min="20"
show-input
input-size="small"
/>
</ElFormItem>
</ElCard>
<ElCard header="主标题" class="property-group" shadow="never">
<ElFormItem label="文字" prop="title" label-width="40px">
<InputWithColor
v-model="formData.title"
v-model:color="formData.titleColor"
show-word-limit
maxlength="20"
/>
</ElFormItem>
<ElFormItem label="大小" prop="titleSize" label-width="40px">
<ElSlider
v-model="formData.titleSize"
:max="60"
:min="10"
show-input
input-size="small"
/>
</ElFormItem>
<ElFormItem label="粗细" prop="titleWeight" label-width="40px">
<ElSlider
v-model="formData.titleWeight"
:min="100"
:max="900"
:step="100"
show-input
input-size="small"
/>
</ElFormItem>
</ElCard>
<ElCard header="副标题" class="property-group" shadow="never">
<ElFormItem label="文字" prop="description" label-width="40px">
<InputWithColor
v-model="formData.description"
v-model:color="formData.descriptionColor"
show-word-limit
maxlength="50"
/>
</ElFormItem>
<ElFormItem label="大小" prop="descriptionSize" label-width="40px">
<ElSlider
v-model="formData.descriptionSize"
:max="60"
:min="10"
show-input
input-size="small"
/>
</ElFormItem>
<ElFormItem label="粗细" prop="descriptionWeight" label-width="40px">
<ElSlider
v-model="formData.descriptionWeight"
:min="100"
:max="900"
:step="100"
show-input
input-size="small"
/>
</ElFormItem>
</ElCard>
<ElCard header="查看更多" class="property-group" shadow="never">
<ElFormItem label="是否显示" prop="more.show">
<ElCheckbox v-model="formData.more.show" />
</ElFormItem>
<!-- 更多按钮的 样式选择 -->
<template v-if="formData.more.show">
<ElFormItem label="样式" prop="more.type">
<ElRadioGroup v-model="formData.more.type">
<ElRadio value="text">文字</ElRadio>
<ElRadio value="icon">图标</ElRadio>
<ElRadio value="all">文字+图标</ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
label="更多文字"
prop="more.text"
v-show="formData.more.type !== 'icon'"
>
<ElInput v-model="formData.more.text" />
</ElFormItem>
<ElFormItem label="跳转链接" prop="more.url">
<AppLinkInput v-model="formData.more.url" />
</ElFormItem>
</template>
</ElCard>
</ElForm>
</ComponentContainerProperty>
</template>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,34 @@
<script setup lang="ts">
import type { UserCardProperty } from './config';
import { ElAvatar } from 'element-plus';
import { IconifyIcon } from '@vben/icons';
/** 用户卡片 */
defineOptions({ name: 'UserCard' });
//
defineProps<{ property: UserCardProperty }>();
</script>
<template>
<div class="flex flex-col">
<div class="flex items-center justify-between px-[18px] py-[24px]">
<div class="flex flex-1 items-center gap-[16px]">
<ElAvatar :size="60">
<IconifyIcon icon="ep:avatar" :size="60" />
</ElAvatar>
<span class="text-[18px] font-bold">芋道源码</span>
</div>
<IconifyIcon icon="tdesign:qrcode" :size="20" />
</div>
<div
class="flex items-center justify-between bg-white px-[20px] py-[8px] text-[12px]"
>
<span class="text-[#ff690d]">点击绑定手机号</span>
<span class="rounded-[26px] bg-[#ff6100] px-[8px] py-[5px] text-white">
去绑定
</span>
</div>
</div>
</template>
<style scoped lang="scss"></style>

View File

@ -2,6 +2,7 @@
import type { UserCardProperty } from './config';
import { useVModel } from '@vueuse/core';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
//
defineOptions({ name: 'UserCardProperty' });

View File

@ -1,13 +1,15 @@
<script setup lang="ts">
import type { UserCouponProperty } from './config';
import { ElImage } from 'element-plus';
/** 用户卡券 */
defineOptions({ name: 'UserCoupon' });
//
defineProps<{ property: UserCouponProperty }>();
</script>
<template>
<el-image
<ElImage
src="https://shopro.sheepjs.com/admin/static/images/shop/decorate/couponCardStyle.png"
/>
</template>

View File

@ -2,6 +2,7 @@
import type { UserCouponProperty } from './config';
import { useVModel } from '@vueuse/core';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
//
defineOptions({ name: 'UserCouponProperty' });

View File

@ -1,13 +1,15 @@
<script setup lang="ts">
import type { UserOrderProperty } from './config';
import { ElImage } from 'element-plus';
/** 用户订单 */
defineOptions({ name: 'UserOrder' });
//
defineProps<{ property: UserOrderProperty }>();
</script>
<template>
<el-image
<ElImage
src="https://shopro.sheepjs.com/admin/static/images/shop/decorate/orderCardStyle.png"
/>
</template>

View File

@ -2,6 +2,7 @@
import type { UserOrderProperty } from './config';
import { useVModel } from '@vueuse/core';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
//
defineOptions({ name: 'UserOrderProperty' });

View File

@ -1,13 +1,15 @@
<script setup lang="ts">
import type { UserWalletProperty } from './config';
import { ElImage } from 'element-plus';
/** 用户资产 */
defineOptions({ name: 'UserWallet' });
//
defineProps<{ property: UserWalletProperty }>();
</script>
<template>
<el-image
<ElImage
src="https://shopro.sheepjs.com/admin/static/images/shop/decorate/walletCardStyle.png"
/>
</template>

View File

@ -2,6 +2,7 @@
import type { UserWalletProperty } from './config';
import { useVModel } from '@vueuse/core';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
//
defineOptions({ name: 'UserWalletProperty' });

View File

@ -1,6 +1,8 @@
<script setup lang="ts">
import type { VideoPlayerProperty } from './config';
import { ElImage } from 'element-plus';
/** 视频播放 */
defineOptions({ name: 'VideoPlayer' });
@ -8,7 +10,7 @@ defineProps<{ property: VideoPlayerProperty }>();
</script>
<template>
<div class="w-full" :style="{ height: `${property.style.height}px` }">
<el-image
<ElImage
class="w-full"
:src="property.posterUrl"
v-if="property.posterUrl"

View File

@ -2,6 +2,10 @@
import type { VideoPlayerProperty } from './config';
import { useVModel } from '@vueuse/core';
import { ElForm, ElFormItem, ElSlider, ElSwitch } from 'element-plus';
import ComponentContainerProperty from '#/components/diy-editor/components/component-container-property.vue';
import UploadFile from '#/components/upload/file-upload.vue';
import UploadImg from '#/components/upload/image-upload.vue';
//
defineOptions({ name: 'VideoPlayerProperty' });
@ -14,8 +18,8 @@ const formData = useVModel(props, 'modelValue', emit);
<template>
<ComponentContainerProperty v-model="formData.style">
<template #style>
<el-form-item label="高度" prop="height">
<el-slider
<ElFormItem label="高度" prop="height">
<ElSlider
v-model="formData.style.height"
:max="500"
:min="100"
@ -23,34 +27,34 @@ const formData = useVModel(props, 'modelValue', emit);
input-size="small"
:show-input-controls="false"
/>
</el-form-item>
</ElFormItem>
</template>
<el-form label-width="80px" :model="formData">
<el-form-item label="上传视频" prop="videoUrl">
<ElForm label-width="80px" :model="formData">
<ElFormItem label="上传视频" prop="videoUrl">
<UploadFile
v-model="formData.videoUrl"
:file-type="['mp4']"
:limit="1"
:file-size="100"
class="min-w-80px"
class="min-w-[80px]"
/>
</el-form-item>
<el-form-item label="上传封面" prop="posterUrl">
</ElFormItem>
<ElFormItem label="上传封面" prop="posterUrl">
<UploadImg
v-model="formData.posterUrl"
draggable="false"
height="80px"
width="100%"
class="min-w-80px"
class="min-w-[80px]"
:show-description="false"
>
<template #tip> 建议宽度750 </template>
</UploadImg>
</el-form-item>
<el-form-item label="自动播放" prop="autoplay">
<el-switch v-model="formData.autoplay" />
</el-form-item>
</el-form>
</ElFormItem>
<ElFormItem label="自动播放" prop="autoplay">
<ElSwitch v-model="formData.autoplay" />
</ElFormItem>
</ElForm>
</ComponentContainerProperty>
</template>

View File

@ -25,12 +25,12 @@ import {
componentConfigs,
components,
} from '#/components/diy-editor/components/mobile';
import { component as PAGE_CONFIG_COMPONENT } from '#/components/diy-editor/components/mobile/PageConfig/config';
import { component as PAGE_CONFIG_COMPONENT } from '#/components/diy-editor/components/mobile/page-config/config';
import ComponentContainer from './components/ComponentContainer.vue';
import ComponentLibrary from './components/ComponentLibrary.vue';
import { component as NAVIGATION_BAR_COMPONENT } from './components/mobile/NavigationBar/config';
import { component as TAB_BAR_COMPONENT } from './components/mobile/TabBar/config';
import ComponentContainer from './components/component-container.vue';
import ComponentLibrary from './components/component-library.vue';
import { component as NAVIGATION_BAR_COMPONENT } from './components/mobile/navigation-bar/config';
import { component as TAB_BAR_COMPONENT } from './components/mobile/tab-bar/config';
/** 页面装修详情页 */
defineOptions({

View File

@ -13,7 +13,7 @@ import type { AxiosProgressEvent } from '#/api/infra/file';
import { nextTick, ref, toRefs, watch } from 'vue';
import { CloudUpload } from '@vben/icons';
import { Plus } from '@vben/icons';
import { $t } from '@vben/locales';
import { isFunction, isObject, isString } from '@vben/utils';
@ -313,8 +313,7 @@ const triggerEdit = () => {
}"
>
<div class="upload-content flex flex-col items-center justify-center">
<CloudUpload />
<div class="mt-2">{{ $t('ui.upload.imgUpload') }}</div>
<Plus />
</div>
</ElUpload>
</template>