diff --git a/.vscode/extensions.json b/.vscode/extensions.json index e8dc9ed9..c67d983e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -21,7 +21,8 @@ // CSS 变量提示 "vunguyentuan.vscode-css-variables", // 在 package.json 中显示 PNPM catalog 的版本 - "antfu.pnpm-catalog-lens" + "antfu.pnpm-catalog-lens", + "augment.vscode-augment" ], "unwantedRecommendations": [ // 和 volar 冲突 diff --git a/apps/web-ele/.env.development b/apps/web-ele/.env.development index 02edf8dd..77c13d39 100644 --- a/apps/web-ele/.env.development +++ b/apps/web-ele/.env.development @@ -19,3 +19,5 @@ VITE_INJECT_APP_LOADING=true VITE_APP_DEFAULT_USERNAME=admin # 默认登录密码 VITE_APP_DEFAULT_PASSWORD=admin123 + +VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn' diff --git a/apps/web-ele/.env.production b/apps/web-ele/.env.production index 910fd64c..ac0408ec 100644 --- a/apps/web-ele/.env.production +++ b/apps/web-ele/.env.production @@ -21,3 +21,5 @@ VITE_INJECT_APP_LOADING=true # 打包后是否生成dist.zip VITE_ARCHIVER=true + +VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn' diff --git a/apps/web-ele/package.json b/apps/web-ele/package.json index 43a43dac..45689f33 100644 --- a/apps/web-ele/package.json +++ b/apps/web-ele/package.json @@ -51,7 +51,9 @@ "highlight.js": "catalog:", "pinia": "catalog:", "vue": "catalog:", - "vue-router": "catalog:" + "vue-dompurify-html": "catalog:", + "vue-router": "catalog:", + "vuedraggable": "catalog:" }, "devDependencies": { "unplugin-element-plus": "catalog:" diff --git a/apps/web-ele/src/api/mall/promotion/combination/combinationActivity.ts b/apps/web-ele/src/api/mall/promotion/combination/combinationActivity.ts index c0d53d6b..486f05aa 100644 --- a/apps/web-ele/src/api/mall/promotion/combination/combinationActivity.ts +++ b/apps/web-ele/src/api/mall/promotion/combination/combinationActivity.ts @@ -48,6 +48,8 @@ export namespace MallCombinationActivityApi { combinationPrice?: number; /** 商品列表 */ products: CombinationProduct[]; + /** 图片 */ + picUrl?: string; } /** 扩展 SKU 配置 */ diff --git a/apps/web-ele/src/api/mall/promotion/diy/page.ts b/apps/web-ele/src/api/mall/promotion/diy/page.ts index daa5e4b0..afdface5 100644 --- a/apps/web-ele/src/api/mall/promotion/diy/page.ts +++ b/apps/web-ele/src/api/mall/promotion/diy/page.ts @@ -52,7 +52,7 @@ export function deleteDiyPage(id: number) { /** 获得装修页面属性 */ export function getDiyPageProperty(id: number) { - return requestClient.get(`/promotion/diy-page/get-property?id=${id}`); + return requestClient.get(`/promotion/diy-page/get-property?id=${id}`); } /** 更新装修页面属性 */ diff --git a/apps/web-ele/src/api/mall/promotion/seckill/seckillActivity.ts b/apps/web-ele/src/api/mall/promotion/seckill/seckillActivity.ts index e11e8828..9a7e121d 100644 --- a/apps/web-ele/src/api/mall/promotion/seckill/seckillActivity.ts +++ b/apps/web-ele/src/api/mall/promotion/seckill/seckillActivity.ts @@ -55,6 +55,8 @@ export namespace MallSeckillActivityApi { seckillPrice?: number; /** 秒杀商品列表 */ products?: SeckillProduct[]; + /** 图片 */ + picUrl?: string; } /** 扩展 SKU 配置 */ diff --git a/apps/web-ele/src/assets/imgs/diy/app-nav-bar-mp.png b/apps/web-ele/src/assets/imgs/diy/app-nav-bar-mp.png new file mode 100644 index 00000000..c982804c Binary files /dev/null and b/apps/web-ele/src/assets/imgs/diy/app-nav-bar-mp.png differ diff --git a/apps/web-ele/src/assets/imgs/diy/statusBar.png b/apps/web-ele/src/assets/imgs/diy/statusBar.png new file mode 100644 index 00000000..b85562e4 Binary files /dev/null and b/apps/web-ele/src/assets/imgs/diy/statusBar.png differ diff --git a/apps/web-ele/src/bootstrap.ts b/apps/web-ele/src/bootstrap.ts index c366b278..9b31950f 100644 --- a/apps/web-ele/src/bootstrap.ts +++ b/apps/web-ele/src/bootstrap.ts @@ -1,4 +1,5 @@ import { createApp, watchEffect } from 'vue'; +import VueDOMPurifyHTML from 'vue-dompurify-html'; import { registerAccessDirective } from '@vben/access'; import { registerLoadingDirective } from '@vben/common-ui'; @@ -34,7 +35,7 @@ async function bootstrap(namespace: string) { // zIndex: 2000, // }); const app = createApp(App); - + app.use(VueDOMPurifyHTML); // 注册Element Plus提供的v-loading指令 app.directive('loading', ElLoading.directive); diff --git a/apps/web-ele/src/components/app-link-input/app-link-select-dialog.vue b/apps/web-ele/src/components/app-link-input/app-link-select-dialog.vue new file mode 100644 index 00000000..06d71be7 --- /dev/null +++ b/apps/web-ele/src/components/app-link-input/app-link-select-dialog.vue @@ -0,0 +1,241 @@ + + + diff --git a/apps/web-ele/src/components/app-link-input/data.ts b/apps/web-ele/src/components/app-link-input/data.ts new file mode 100644 index 00000000..550b88d7 --- /dev/null +++ b/apps/web-ele/src/components/app-link-input/data.ts @@ -0,0 +1,236 @@ +// APP 链接分组 +export interface AppLinkGroup { + // 分组名称 + name: string; + // 链接列表 + links: AppLink[]; +} + +// APP 链接 +export interface AppLink { + // 链接名称 + name: string; + // 链接地址 + path: string; + // 链接的类型 + type?: APP_LINK_TYPE_ENUM; +} + +// APP 链接类型(需要特殊处理,例如商品详情) +export enum APP_LINK_TYPE_ENUM { + // 拼团活动 + ACTIVITY_COMBINATION, + // 积分商城活动 + ACTIVITY_POINT, + // 秒杀活动 + ACTIVITY_SECKILL, + // 文章详情 + ARTICLE_DETAIL, + // 优惠券详情 + COUPON_DETAIL, + // 自定义页面详情 + DIY_PAGE_DETAIL, + // 品类列表 + PRODUCT_CATEGORY_LIST, + // 拼团商品详情 + PRODUCT_DETAIL_COMBINATION, + // 商品详情 + PRODUCT_DETAIL_NORMAL, + // 秒杀商品详情 + PRODUCT_DETAIL_SECKILL, + // 商品列表 + PRODUCT_LIST, +} + +// APP 链接列表(做一下持久化?) +export const APP_LINK_GROUP_LIST = [ + { + name: '商城', + links: [ + { + name: '首页', + path: '/pages/index/index', + }, + { + name: '商品分类', + path: '/pages/index/category', + type: APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST, + }, + { + name: '购物车', + path: '/pages/index/cart', + }, + { + name: '个人中心', + path: '/pages/index/user', + }, + { + name: '商品搜索', + path: '/pages/index/search', + }, + { + name: '自定义页面', + path: '/pages/index/page', + type: APP_LINK_TYPE_ENUM.DIY_PAGE_DETAIL, + }, + { + name: '客服', + path: '/pages/chat/index', + }, + { + name: '系统设置', + path: '/pages/public/setting', + }, + { + name: '常见问题', + path: '/pages/public/faq', + }, + ], + }, + { + name: '商品', + links: [ + { + name: '商品列表', + path: '/pages/goods/list', + type: APP_LINK_TYPE_ENUM.PRODUCT_LIST, + }, + { + name: '商品详情', + path: '/pages/goods/index', + type: APP_LINK_TYPE_ENUM.PRODUCT_DETAIL_NORMAL, + }, + { + name: '拼团商品详情', + path: '/pages/goods/groupon', + type: APP_LINK_TYPE_ENUM.PRODUCT_DETAIL_COMBINATION, + }, + { + name: '秒杀商品详情', + path: '/pages/goods/seckill', + type: APP_LINK_TYPE_ENUM.PRODUCT_DETAIL_SECKILL, + }, + ], + }, + { + name: '营销活动', + links: [ + { + name: '拼团订单', + path: '/pages/activity/groupon/order', + }, + { + name: '营销商品', + path: '/pages/activity/index', + }, + { + name: '拼团活动', + path: '/pages/activity/groupon/list', + type: APP_LINK_TYPE_ENUM.ACTIVITY_COMBINATION, + }, + { + name: '秒杀活动', + path: '/pages/activity/seckill/list', + type: APP_LINK_TYPE_ENUM.ACTIVITY_SECKILL, + }, + { + name: '积分商城活动', + path: '/pages/activity/point/list', + type: APP_LINK_TYPE_ENUM.ACTIVITY_POINT, + }, + { + name: '签到中心', + path: '/pages/app/sign', + }, + { + name: '优惠券中心', + path: '/pages/coupon/list', + }, + { + name: '优惠券详情', + path: '/pages/coupon/detail', + type: APP_LINK_TYPE_ENUM.COUPON_DETAIL, + }, + { + name: '文章详情', + path: '/pages/public/richtext', + type: APP_LINK_TYPE_ENUM.ARTICLE_DETAIL, + }, + ], + }, + { + name: '分销商城', + links: [ + { + name: '分销中心', + path: '/pages/commission/index', + }, + { + name: '推广商品', + path: '/pages/commission/goods', + }, + { + name: '分销订单', + path: '/pages/commission/order', + }, + { + name: '我的团队', + path: '/pages/commission/team', + }, + ], + }, + { + name: '支付', + links: [ + { + name: '充值余额', + path: '/pages/pay/recharge', + }, + { + name: '充值记录', + path: '/pages/pay/recharge-log', + }, + ], + }, + { + name: '用户中心', + links: [ + { + name: '用户信息', + path: '/pages/user/info', + }, + { + name: '用户订单', + path: '/pages/order/list', + }, + { + name: '售后订单', + path: '/pages/order/aftersale/list', + }, + { + name: '商品收藏', + path: '/pages/user/goods-collect', + }, + { + name: '浏览记录', + path: '/pages/user/goods-log', + }, + { + name: '地址管理', + path: '/pages/user/address/list', + }, + { + name: '用户佣金', + path: '/pages/user/wallet/commission', + }, + { + name: '用户余额', + path: '/pages/user/wallet/money', + }, + { + name: '用户积分', + path: '/pages/user/wallet/score', + }, + ], + }, +] as AppLinkGroup[]; diff --git a/apps/web-ele/src/components/app-link-input/index.vue b/apps/web-ele/src/components/app-link-input/index.vue new file mode 100644 index 00000000..5b608c4e --- /dev/null +++ b/apps/web-ele/src/components/app-link-input/index.vue @@ -0,0 +1,48 @@ + + diff --git a/apps/web-ele/src/components/color-input/index.vue b/apps/web-ele/src/components/color-input/index.vue new file mode 100644 index 00000000..16170c23 --- /dev/null +++ b/apps/web-ele/src/components/color-input/index.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/component-container-property.vue b/apps/web-ele/src/components/diy-editor/components/component-container-property.vue new file mode 100644 index 00000000..24062a19 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/component-container-property.vue @@ -0,0 +1,200 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/component-container.vue b/apps/web-ele/src/components/diy-editor/components/component-container.vue new file mode 100644 index 00000000..5a9b803d --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/component-container.vue @@ -0,0 +1,269 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/component-library.vue b/apps/web-ele/src/components/diy-editor/components/component-library.vue new file mode 100644 index 00000000..628c1c55 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/component-library.vue @@ -0,0 +1,221 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/config.ts new file mode 100644 index 00000000..749d36a3 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/config.ts @@ -0,0 +1,61 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 轮播图属性 */ +export interface CarouselProperty { + // 类型:默认 | 卡片 + type: 'card' | 'default'; + // 指示器样式:点 | 数字 + indicator: 'dot' | 'number'; + // 是否自动播放 + autoplay: boolean; + // 播放间隔 + interval: number; + // 轮播内容 + items: CarouselItemProperty[]; + // 组件样式 + style: ComponentStyle; +} +// 轮播内容属性 +export interface CarouselItemProperty { + // 类型:图片 | 视频 + type: 'img' | 'video'; + // 图片链接 + imgUrl: string; + // 视频链接 + videoUrl: string; + // 跳转链接 + url: string; +} + +// 定义组件 +export const component = { + id: 'Carousel', + name: '轮播图', + icon: 'system-uicons:carousel', + property: { + type: 'default', + indicator: 'dot', + autoplay: false, + interval: 3, + items: [ + { + type: 'img', + imgUrl: 'https://static.iocoder.cn/mall/banner-01.jpg', + videoUrl: '', + }, + { + type: 'img', + imgUrl: 'https://static.iocoder.cn/mall/banner-02.jpg', + videoUrl: '', + }, + ] as CarouselItemProperty[], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/index.vue new file mode 100644 index 00000000..df256770 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/index.vue @@ -0,0 +1,50 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/property.vue new file mode 100644 index 00000000..21da4043 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Carousel/property.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Divider/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/Divider/config.ts new file mode 100644 index 00000000..7147ef9b --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Divider/config.ts @@ -0,0 +1,29 @@ +import type { DiyComponent } from '#/components/diy-editor/util'; + +/** 分割线属性 */ +export interface DividerProperty { + // 高度 + height: number; + // 线宽 + lineWidth: number; + // 边距类型 + paddingType: 'horizontal' | 'none'; + // 颜色 + lineColor: string; + // 类型 + borderType: 'dashed' | 'dotted' | 'none' | 'solid'; +} + +// 定义组件 +export const component = { + id: 'Divider', + name: '分割线', + icon: 'tdesign:component-divider-vertical', + property: { + height: 30, + lineWidth: 1, + paddingType: 'none', + lineColor: '#dcdfe6', + borderType: 'solid', + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Divider/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/Divider/index.vue new file mode 100644 index 00000000..1736db38 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Divider/index.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Divider/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/Divider/property.vue new file mode 100644 index 00000000..7746b73b --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Divider/property.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Popover/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/Popover/config.ts new file mode 100644 index 00000000..b842d19f --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Popover/config.ts @@ -0,0 +1,26 @@ +import type { DiyComponent } from '#/components/diy-editor/util'; + +/** 弹窗广告属性 */ +export interface PopoverProperty { + list: PopoverItemProperty[]; +} + +export interface PopoverItemProperty { + // 图片地址 + imgUrl: string; + // 跳转连接 + url: string; + // 显示类型:仅显示一次、每次启动都会显示 + showType: 'always' | 'once'; +} + +// 定义组件 +export const component = { + id: 'Popover', + name: '弹窗广告', + icon: 'carbon:popup', + position: 'fixed', + property: { + list: [{ showType: 'once' }], + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Popover/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/Popover/index.vue new file mode 100644 index 00000000..bc724eca --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Popover/index.vue @@ -0,0 +1,44 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/Popover/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/Popover/property.vue new file mode 100644 index 00000000..0d69fd9d --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/Popover/property.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/component.tsx b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/component.tsx new file mode 100644 index 00000000..d4dbfee4 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/component.tsx @@ -0,0 +1,4 @@ +// 导出所有优惠券相关组件 +export { CouponDiscount } from './coupon-discount'; +export { CouponDiscountDesc } from './coupon-discount-desc'; +export { CouponValidTerm } from './coupon-validTerm'; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/config.ts new file mode 100644 index 00000000..ddfc1857 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/config.ts @@ -0,0 +1,50 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 商品卡片属性 */ +export interface CouponCardProperty { + // 列数 + columns: number; + // 背景图 + bgImg: string; + // 文字颜色 + textColor: string; + // 按钮样式 + button: { + // 背景颜色 + bgColor: string; + // 颜色 + color: string; + }; + // 间距 + space: number; + // 优惠券编号列表 + couponIds: number[]; + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'CouponCard', + name: '优惠券', + icon: 'ep:ticket', + property: { + columns: 1, + bgImg: '', + textColor: '#E9B461', + button: { + color: '#434343', + bgColor: '', + }, + space: 0, + couponIds: [], + style: { + bgType: 'color', + bgColor: '', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-discount-desc.tsx b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-discount-desc.tsx new file mode 100644 index 00000000..634cb88c --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-discount-desc.tsx @@ -0,0 +1,35 @@ +import type { MallCouponTemplateApi } from '#/api/mall/promotion/coupon/couponTemplate'; + +import { defineComponent } from 'vue'; + +import { floatToFixed2 } from '@vben/utils'; + +import { PromotionDiscountTypeEnum } from '#/utils/constants'; + +// 优惠描述 +export const CouponDiscountDesc = defineComponent({ + name: 'CouponDiscountDesc', + props: { + coupon: { + type: Object as () => MallCouponTemplateApi.CouponTemplate, + required: true, + }, + }, + setup(props) { + const coupon = props.coupon as MallCouponTemplateApi.CouponTemplate; + // 使用条件 + const useCondition = + coupon.usePrice > 0 ? `满${floatToFixed2(coupon.usePrice)}元,` : ''; + // 优惠描述 + const discountDesc = + coupon.discountType === PromotionDiscountTypeEnum.PRICE.type + ? `减${floatToFixed2(coupon.discountPrice)}元` + : `打${coupon.discountPercent / 10}折`; + return () => ( +
+ {useCondition} + {discountDesc} +
+ ); + }, +}); diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-discount.tsx b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-discount.tsx new file mode 100644 index 00000000..bde532e4 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-discount.tsx @@ -0,0 +1,35 @@ +import type { MallCouponTemplateApi } from '#/api/mall/promotion/coupon/couponTemplate'; + +import { defineComponent } from 'vue'; + +import { floatToFixed2 } from '@vben/utils'; + +import { PromotionDiscountTypeEnum } from '#/utils/constants'; + +// 优惠值 +export const CouponDiscount = defineComponent({ + name: 'CouponDiscount', + props: { + coupon: { + type: Object as () => MallCouponTemplateApi.CouponTemplate, + required: true, + }, + }, + setup(props) { + const coupon = props.coupon as MallCouponTemplateApi.CouponTemplate; + // 折扣 + let value = `${coupon.discountPercent / 10}`; + let suffix = ' 折'; + // 满减 + if (coupon.discountType === PromotionDiscountTypeEnum.PRICE.type) { + value = floatToFixed2(coupon.discountPrice); + suffix = ' 元'; + } + return () => ( +
+ {value} + {suffix} +
+ ); + }, +}); diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-validTerm.tsx b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-validTerm.tsx new file mode 100644 index 00000000..c96903f1 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/coupon-validTerm.tsx @@ -0,0 +1,29 @@ +import type { MallCouponTemplateApi } from '#/api/mall/promotion/coupon/couponTemplate'; + +import { defineComponent } from 'vue'; + +import { formatDate } from '@vben/utils'; + +import { CouponTemplateValidityTypeEnum } from '#/utils/constants'; + +// 有效期 +export const CouponValidTerm = defineComponent({ + name: 'CouponValidTerm', + props: { + coupon: { + type: Object as () => MallCouponTemplateApi.CouponTemplate, + required: true, + }, + }, + setup(props) { + const coupon = props.coupon as MallCouponTemplateApi.CouponTemplate; + const text = + coupon.validityType === CouponTemplateValidityTypeEnum.DATE.type + ? `有效期:${formatDate(coupon.validStartTime, 'YYYY-MM-DD')} 至 ${formatDate( + coupon.validEndTime, + 'YYYY-MM-DD', + )}` + : `领取后第 ${coupon.fixedStartTerm} - ${coupon.fixedEndTerm} 天内可用`; + return () =>
{text}
; + }, +}); diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/index.vue new file mode 100644 index 00000000..eb5fbb1a --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/index.vue @@ -0,0 +1,162 @@ + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/property.vue new file mode 100644 index 00000000..55332ded --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/coupon-card/property.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/config.ts new file mode 100644 index 00000000..7972bd3b --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/config.ts @@ -0,0 +1,36 @@ +import type { DiyComponent } from '#/components/diy-editor/util'; + +// 悬浮按钮属性 +export interface FloatingActionButtonProperty { + // 展开方向 + direction: 'horizontal' | 'vertical'; + // 是否显示文字 + showText: boolean; + // 按钮列表 + list: FloatingActionButtonItemProperty[]; +} + +// 悬浮按钮项属性 +export interface FloatingActionButtonItemProperty { + // 图片地址 + imgUrl: string; + // 跳转连接 + url: string; + // 文字 + text: string; + // 文字颜色 + textColor: string; +} + +// 定义组件 +export const component = { + id: 'FloatingActionButton', + name: '悬浮按钮', + icon: 'tabler:float-right', + position: 'fixed', + property: { + direction: 'vertical', + showText: true, + list: [{ textColor: '#fff' }], + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/index.vue new file mode 100644 index 00000000..eb656376 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/index.vue @@ -0,0 +1,92 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/property.vue new file mode 100644 index 00000000..2be023a8 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/floating-action-button/property.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/controller.ts b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/controller.ts new file mode 100644 index 00000000..93a264b5 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/controller.ts @@ -0,0 +1,175 @@ +import type { StyleValue } from 'vue'; + +import type { HotZoneItemProperty } from '#/components/diy-editor/components/mobile/HotZone/config'; + +// 热区的最小宽高 +export const HOT_ZONE_MIN_SIZE = 100; + +// 控制的类型 +export enum CONTROL_TYPE_ENUM { + LEFT, + TOP, + WIDTH, + HEIGHT, +} + +// 定义热区的控制点 +export interface ControlDot { + position: string; + types: CONTROL_TYPE_ENUM[]; + style: StyleValue; +} + +// 热区的8个控制点 +export const CONTROL_DOT_LIST = [ + { + position: '左上角', + types: [ + CONTROL_TYPE_ENUM.LEFT, + CONTROL_TYPE_ENUM.TOP, + CONTROL_TYPE_ENUM.WIDTH, + CONTROL_TYPE_ENUM.HEIGHT, + ], + style: { left: '-5px', top: '-5px', cursor: 'nwse-resize' }, + }, + { + position: '上方中间', + types: [CONTROL_TYPE_ENUM.TOP, CONTROL_TYPE_ENUM.HEIGHT], + style: { + left: '50%', + top: '-5px', + cursor: 'n-resize', + transform: 'translateX(-50%)', + }, + }, + { + position: '右上角', + types: [ + CONTROL_TYPE_ENUM.TOP, + CONTROL_TYPE_ENUM.WIDTH, + CONTROL_TYPE_ENUM.HEIGHT, + ], + style: { right: '-5px', top: '-5px', cursor: 'nesw-resize' }, + }, + { + position: '右侧中间', + types: [CONTROL_TYPE_ENUM.WIDTH], + style: { + right: '-5px', + top: '50%', + cursor: 'e-resize', + transform: 'translateX(-50%)', + }, + }, + { + position: '右下角', + types: [CONTROL_TYPE_ENUM.WIDTH, CONTROL_TYPE_ENUM.HEIGHT], + style: { right: '-5px', bottom: '-5px', cursor: 'nwse-resize' }, + }, + { + position: '下方中间', + types: [CONTROL_TYPE_ENUM.HEIGHT], + style: { + left: '50%', + bottom: '-5px', + cursor: 's-resize', + transform: 'translateX(-50%)', + }, + }, + { + position: '左下角', + types: [ + CONTROL_TYPE_ENUM.LEFT, + CONTROL_TYPE_ENUM.WIDTH, + CONTROL_TYPE_ENUM.HEIGHT, + ], + style: { left: '-5px', bottom: '-5px', cursor: 'nesw-resize' }, + }, + { + position: '左侧中间', + types: [CONTROL_TYPE_ENUM.LEFT, CONTROL_TYPE_ENUM.WIDTH], + style: { + left: '-5px', + top: '50%', + cursor: 'w-resize', + transform: 'translateX(-50%)', + }, + }, +] as ControlDot[]; + +// region 热区的缩放 +// 热区的缩放比例 +export const HOT_ZONE_SCALE_RATE = 2; +// 缩小:缩回适合手机屏幕的大小 +export const zoomOut = (list?: HotZoneItemProperty[]) => { + return ( + list?.map((hotZone) => ({ + ...hotZone, + left: (hotZone.left /= HOT_ZONE_SCALE_RATE), + top: (hotZone.top /= HOT_ZONE_SCALE_RATE), + width: (hotZone.width /= HOT_ZONE_SCALE_RATE), + height: (hotZone.height /= HOT_ZONE_SCALE_RATE), + })) || [] + ); +}; +// 放大:作用是为了方便在电脑屏幕上编辑 +export const zoomIn = (list?: HotZoneItemProperty[]) => { + return ( + list?.map((hotZone) => ({ + ...hotZone, + left: (hotZone.left *= HOT_ZONE_SCALE_RATE), + top: (hotZone.top *= HOT_ZONE_SCALE_RATE), + width: (hotZone.width *= HOT_ZONE_SCALE_RATE), + height: (hotZone.height *= HOT_ZONE_SCALE_RATE), + })) || [] + ); +}; +// endregion + +/** + * 封装热区拖拽 + * + * 注:为什么不使用vueuse的useDraggable。在本场景下,其使用方式比较复杂 + * @param hotZone 热区 + * @param downEvent 鼠标按下事件 + * @param callback 回调函数 + */ +export const useDraggable = ( + hotZone: HotZoneItemProperty, + downEvent: MouseEvent, + callback: ( + left: number, + top: number, + width: number, + height: number, + moveWidth: number, + moveHeight: number, + ) => void, +) => { + // 阻止事件冒泡 + downEvent.stopPropagation(); + + // 移动前的鼠标坐标 + const { clientX: startX, clientY: startY } = downEvent; + // 移动前的热区坐标、大小 + const { left, top, width, height } = hotZone; + + // 监听鼠标移动 + const handleMouseMove = (e: MouseEvent) => { + // 移动宽度 + const moveWidth = e.clientX - startX; + // 移动高度 + const moveHeight = e.clientY - startY; + // 移动回调 + callback(left, top, width, height, moveWidth, moveHeight); + }; + + // 松开鼠标后,结束拖拽 + const handleMouseUp = () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); +}; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/index.vue new file mode 100644 index 00000000..0a72633d --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/index.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/config.ts new file mode 100644 index 00000000..71e39d9c --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/config.ts @@ -0,0 +1,46 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 热区属性 */ +export interface HotZoneProperty { + // 图片地址 + imgUrl: string; + // 导航菜单列表 + list: HotZoneItemProperty[]; + // 组件样式 + style: ComponentStyle; +} + +/** 热区项目属性 */ +export interface HotZoneItemProperty { + // 链接的名称 + name: string; + // 链接 + url: string; + // 宽 + width: number; + // 高 + height: number; + // 上 + top: number; + // 左 + left: number; +} + +// 定义组件 +export const component = { + id: 'HotZone', + name: '热区', + icon: 'tabler:hand-click', + property: { + imgUrl: '', + list: [] as HotZoneItemProperty[], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/index.vue new file mode 100644 index 00000000..dd36b550 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/index.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/property.vue new file mode 100644 index 00000000..e3c602f6 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/hot-zone/property.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/config.ts new file mode 100644 index 00000000..53a87403 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/config.ts @@ -0,0 +1,30 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 图片展示属性 */ +export interface ImageBarProperty { + // 图片链接 + imgUrl: string; + // 跳转链接 + url: string; + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'ImageBar', + name: '图片展示', + icon: 'ep:picture', + property: { + imgUrl: '', + url: '', + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/index.vue new file mode 100644 index 00000000..4562f7b3 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/index.vue @@ -0,0 +1,31 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/property.vue new file mode 100644 index 00000000..ce1b3ad5 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/image-bar/property.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/index.ts b/apps/web-ele/src/components/diy-editor/components/mobile/index.ts new file mode 100644 index 00000000..454e06a0 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/index.ts @@ -0,0 +1,69 @@ +import { defineAsyncComponent } from 'vue'; + +/* + * 组件注册 + * + * 组件规范: + * 1. 每个子目录就是一个独立的组件,每个目录包括以下三个文件: + * 2. config.ts:组件配置,必选,用于定义组件、组件默认的属性、定义属性的类型 + * 3. index.vue:组件展示,用于展示组件的渲染效果。可以不提供,如 Page(页面设置),只需要属性配置表单即可 + * 4. property.vue:组件属性表单,用于配置组件,必选, + * + * 注: + * 组件ID以config.ts中配置的id为准,与组件目录的名称无关,但还是建议组件目录的名称与组件ID保持一致 + */ + +// 导入组件界面模块 +const viewModules: Record = import.meta.glob('./*/*.vue'); +// 导入配置模块 +const configModules: Record = import.meta.glob('./*/config.ts', { + eager: true, +}); + +// 界面模块 +const components: Record = {}; +// 组件配置模块 +const componentConfigs: Record = {}; + +// 组件界面的类型 +type ViewType = 'index' | 'property'; + +/** + * 注册组件的界面模块 + * + * @param componentId 组件ID + * @param configPath 配置模块的文件路径 + * @param viewType 组件界面的类型 + */ +const registerComponentViewModule = ( + componentId: string, + configPath: string, + viewType: ViewType, +) => { + const viewPath = configPath.replace('config.ts', `${viewType}.vue`); + const viewModule = viewModules[viewPath]; + if (viewModule) { + // 定义异步组件 + components[componentId] = defineAsyncComponent(viewModule); + } +}; + +// 注册 +Object.keys(configModules).forEach((modulePath: string) => { + const component = configModules[modulePath].component; + const componentId = component?.id; + if (componentId) { + // 注册组件 + componentConfigs[componentId] = component; + // 注册预览界面 + registerComponentViewModule(componentId, modulePath, 'index'); + // 注册属性配置表单 + registerComponentViewModule( + `${componentId}Property`, + modulePath, + 'property', + ); + } +}); + +export { componentConfigs, components }; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/config.ts new file mode 100644 index 00000000..b364fbb3 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/config.ts @@ -0,0 +1,56 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 广告魔方属性 */ +export interface MagicCubeProperty { + // 上圆角 + borderRadiusTop: number; + // 下圆角 + borderRadiusBottom: number; + // 间隔 + space: number; + // 导航菜单列表 + list: MagicCubeItemProperty[]; + // 组件样式 + style: ComponentStyle; +} + +/** 广告魔方项目属性 */ +export interface MagicCubeItemProperty { + // 图标链接 + imgUrl: string; + // 链接 + url: string; + // 宽 + width: number; + // 高 + height: number; + // 上 + top: number; + // 左 + left: number; + // 右 + right: number; + // 下 + bottom: number; +} + +// 定义组件 +export const component = { + id: 'MagicCube', + name: '广告魔方', + icon: 'bi:columns', + property: { + borderRadiusTop: 0, + borderRadiusBottom: 0, + space: 0, + list: [], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/index.vue new file mode 100644 index 00000000..5a3aa7e5 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/index.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/property.vue new file mode 100644 index 00000000..80efbae6 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/magic-cube/property.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/config.ts new file mode 100644 index 00000000..4ae675a4 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/config.ts @@ -0,0 +1,83 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +import { cloneDeep } from '@vben/utils'; + +/** 宫格导航属性 */ +export interface MenuGridProperty { + // 列数 + column: number; + // 导航菜单列表 + list: MenuGridItemProperty[]; + // 组件样式 + style: ComponentStyle; +} + +/** 宫格导航项目属性 */ +export interface MenuGridItemProperty { + // 图标链接 + iconUrl: string; + // 标题 + title: string; + // 标题颜色 + titleColor: string; + // 副标题 + subtitle: string; + // 副标题颜色 + subtitleColor: string; + // 链接 + url: string; + // 角标 + badge: { + // 角标背景颜色 + bgColor: string; + // 是否显示 + show: boolean; + // 角标文字 + text: string; + // 角标文字颜色 + textColor: string; + }; +} + +export const EMPTY_MENU_GRID_ITEM_PROPERTY = { + title: '标题', + titleColor: '#333', + subtitle: '副标题', + subtitleColor: '#bbb', + badge: { + show: false, + textColor: '#fff', + bgColor: '#FF6000', + }, +} as MenuGridItemProperty; + +// 定义组件 +export const component = { + id: 'MenuGrid', + name: '宫格导航', + icon: 'bi:grid-3x3-gap', + property: { + column: 3, + list: [cloneDeep(EMPTY_MENU_GRID_ITEM_PROPERTY)], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + marginLeft: 8, + marginRight: 8, + padding: 8, + paddingTop: 8, + paddingRight: 8, + paddingBottom: 8, + paddingLeft: 8, + borderRadius: 8, + borderTopLeftRadius: 8, + borderTopRightRadius: 8, + borderBottomRightRadius: 8, + borderBottomLeftRadius: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/index.vue new file mode 100644 index 00000000..2036ede9 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/index.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/property.vue new file mode 100644 index 00000000..88039d35 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-grid/property.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/config.ts new file mode 100644 index 00000000..4be25674 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/config.ts @@ -0,0 +1,52 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +import { cloneDeep } from '@vben/utils'; + +/** 列表导航属性 */ +export interface MenuListProperty { + // 导航菜单列表 + list: MenuListItemProperty[]; + // 组件样式 + style: ComponentStyle; +} + +/** 列表导航项目属性 */ +export interface MenuListItemProperty { + // 图标链接 + iconUrl: string; + // 标题 + title: string; + // 标题颜色 + titleColor: string; + // 副标题 + subtitle: string; + // 副标题颜色 + subtitleColor: string; + // 链接 + url: string; +} + +export const EMPTY_MENU_LIST_ITEM_PROPERTY = { + title: '标题', + titleColor: '#333', + subtitle: '副标题', + subtitleColor: '#bbb', +}; + +// 定义组件 +export const component = { + id: 'MenuList', + name: '列表导航', + icon: 'fa-solid:list', + property: { + list: [cloneDeep(EMPTY_MENU_LIST_ITEM_PROPERTY)], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/index.vue new file mode 100644 index 00000000..12670dcb --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/index.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/property.vue new file mode 100644 index 00000000..a98edc25 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-list/property.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/config.ts new file mode 100644 index 00000000..535287d4 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/config.ts @@ -0,0 +1,70 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +import { cloneDeep } from '@vben/utils'; + +/** 菜单导航属性 */ +export interface MenuSwiperProperty { + // 布局: 图标+文字 | 图标 + layout: 'icon' | 'iconText'; + // 行数 + row: number; + // 列数 + column: number; + // 导航菜单列表 + list: MenuSwiperItemProperty[]; + // 组件样式 + style: ComponentStyle; +} +/** 菜单导航项目属性 */ +export interface MenuSwiperItemProperty { + // 图标链接 + iconUrl: string; + // 标题 + title: string; + // 标题颜色 + titleColor: string; + // 链接 + url: string; + // 角标 + badge: { + // 角标背景颜色 + bgColor: string; + // 是否显示 + show: boolean; + // 角标文字 + text: string; + // 角标文字颜色 + textColor: string; + }; +} + +export const EMPTY_MENU_SWIPER_ITEM_PROPERTY = { + title: '标题', + titleColor: '#333', + badge: { + show: false, + textColor: '#fff', + bgColor: '#FF6000', + }, +} as MenuSwiperItemProperty; + +// 定义组件 +export const component = { + id: 'MenuSwiper', + name: '菜单导航', + icon: 'bi:grid-3x2-gap', + property: { + layout: 'iconText', + row: 1, + column: 3, + list: [cloneDeep(EMPTY_MENU_SWIPER_ITEM_PROPERTY)], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/index.vue new file mode 100644 index 00000000..0d69c7c8 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/index.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/property.vue new file mode 100644 index 00000000..62dd6e92 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/menu-swiper/property.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/components/cell-property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/components/cell-property.vue new file mode 100644 index 00000000..b34e0091 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/components/cell-property.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/config.ts new file mode 100644 index 00000000..38325d5a --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/config.ts @@ -0,0 +1,82 @@ +import type { DiyComponent } from '#/components/diy-editor/util'; + +/** 顶部导航栏属性 */ +export interface NavigationBarProperty { + // 背景类型 + bgType: 'color' | 'img'; + // 背景颜色 + bgColor: string; + // 图片链接 + bgImg: string; + // 样式类型:默认 | 沉浸式 + styleType: 'inner' | 'normal'; + // 常驻显示 + alwaysShow: boolean; + // 小程序单元格列表 + mpCells: NavigationBarCellProperty[]; + // 其它平台单元格列表 + otherCells: NavigationBarCellProperty[]; + // 本地变量 + _local: { + // 预览顶部导航(小程序) + previewMp: boolean; + // 预览顶部导航(非小程序) + previewOther: boolean; + }; +} + +/** 顶部导航栏 - 单元格 属性 */ +export interface NavigationBarCellProperty { + // 类型:文字 | 图片 | 搜索框 + type: 'image' | 'search' | 'text'; + // 宽度 + width: number; + // 高度 + height: number; + // 顶部位置 + top: number; + // 左侧位置 + left: number; + // 文字内容 + text: string; + // 文字颜色 + textColor: string; + // 图片地址 + imgUrl: string; + // 图片链接 + url: string; + // 搜索框:提示文字 + placeholder: string; + // 搜索框:边框圆角半径 + borderRadius: number; +} + +// 定义组件 +export const component = { + id: 'NavigationBar', + name: '顶部导航栏', + icon: 'tabler:layout-navbar', + property: { + bgType: 'color', + bgColor: '#fff', + bgImg: '', + styleType: 'normal', + alwaysShow: true, + mpCells: [ + { + type: 'text', + textColor: '#111111', + }, + ], + otherCells: [ + { + type: 'text', + textColor: '#111111', + }, + ], + _local: { + previewMp: true, + previewOther: false, + }, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/index.vue new file mode 100644 index 00000000..4a32acb8 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/index.vue @@ -0,0 +1,112 @@ + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/property.vue new file mode 100644 index 00000000..ce3e3f69 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/navigation-bar/property.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/config.ts new file mode 100644 index 00000000..31dc1379 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/config.ts @@ -0,0 +1,49 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 公告栏属性 */ +export interface NoticeBarProperty { + // 图标地址 + iconUrl: string; + // 公告内容列表 + contents: NoticeContentProperty[]; + // 背景颜色 + backgroundColor: string; + // 文字颜色 + textColor: string; + // 组件样式 + style: ComponentStyle; +} + +/** 内容属性 */ +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', + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/index.vue new file mode 100644 index 00000000..589e8937 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/index.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/property.vue new file mode 100644 index 00000000..935e5ec4 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/notice-bar/property.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/page-config/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/page-config/config.ts new file mode 100644 index 00000000..29855bb7 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/page-config/config.ts @@ -0,0 +1,23 @@ +import type { DiyComponent } from '#/components/diy-editor/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; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/page-config/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/page-config/property.vue new file mode 100644 index 00000000..4dca2797 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/page-config/property.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/product-card/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/product-card/config.ts new file mode 100644 index 00000000..ea3c9e4d --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/product-card/config.ts @@ -0,0 +1,100 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 商品卡片属性 */ +export interface ProductCardProperty { + // 布局类型:单列大图 | 单列小图 | 双列 + layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'; + // 商品字段 + fields: { + // 商品简介 + introduction: ProductCardFieldProperty; + // 商品市场价 + marketPrice: ProductCardFieldProperty; + // 商品名称 + name: ProductCardFieldProperty; + // 商品价格 + price: ProductCardFieldProperty; + // 商品销量 + salesCount: ProductCardFieldProperty; + // 商品库存 + stock: ProductCardFieldProperty; + }; + // 角标 + badge: { + // 角标图片 + imgUrl: string; + // 是否显示 + show: boolean; + }; + // 按钮 + btnBuy: { + // 文字按钮:背景渐变起始颜色 + bgBeginColor: string; + // 文字按钮:背景渐变结束颜色 + bgEndColor: string; + // 图片按钮:图片地址 + imgUrl: string; + // 文字 + text: string; + // 类型:文字 | 图片 + type: 'img' | 'text'; + }; + // 上圆角 + borderRadiusTop: number; + // 下圆角 + borderRadiusBottom: number; + // 间距 + space: number; + // 商品编号列表 + spuIds: number[]; + // 组件样式 + style: ComponentStyle; +} +// 商品字段 +export interface ProductCardFieldProperty { + // 是否显示 + show: boolean; + // 颜色 + color: string; +} + +// 定义组件 +export const component = { + id: 'ProductCard', + name: '商品卡片', + icon: 'fluent:text-column-two-left-24-filled', + property: { + layoutType: 'oneColBigImg', + fields: { + name: { show: true, color: '#000' }, + introduction: { show: true, color: '#999' }, + price: { show: true, color: '#ff3000' }, + marketPrice: { show: true, color: '#c4c4c4' }, + salesCount: { show: true, color: '#c4c4c4' }, + stock: { show: false, color: '#c4c4c4' }, + }, + badge: { show: false, imgUrl: '' }, + btnBuy: { + type: 'text', + text: '立即购买', + // todo: @owen 根据主题色配置 + bgBeginColor: '#FF6000', + bgEndColor: '#FE832A', + imgUrl: '', + }, + borderRadiusTop: 6, + borderRadiusBottom: 6, + space: 8, + spuIds: [], + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/product-card/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/product-card/index.vue new file mode 100644 index 00000000..b1cf736e --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/product-card/index.vue @@ -0,0 +1,190 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/product-card/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/product-card/property.vue new file mode 100644 index 00000000..e0b3dfb7 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/product-card/property.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/product-list/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/product-list/config.ts new file mode 100644 index 00000000..0f68a515 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/product-list/config.ts @@ -0,0 +1,67 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 商品栏属性 */ +export interface ProductListProperty { + // 布局类型:双列 | 三列 | 水平滑动 + layoutType: 'horizSwiper' | 'threeCol' | 'twoCol'; + // 商品字段 + fields: { + // 商品名称 + name: ProductListFieldProperty; + // 商品价格 + price: ProductListFieldProperty; + }; + // 角标 + badge: { + // 角标图片 + imgUrl: string; + // 是否显示 + show: boolean; + }; + // 上圆角 + borderRadiusTop: number; + // 下圆角 + borderRadiusBottom: number; + // 间距 + space: number; + // 商品编号列表 + spuIds: number[]; + // 组件样式 + style: ComponentStyle; +} +// 商品字段 +export interface ProductListFieldProperty { + // 是否显示 + show: boolean; + // 颜色 + color: string; +} + +// 定义组件 +export const component = { + id: 'ProductList', + name: '商品栏', + icon: 'fluent:text-column-two-24-filled', + property: { + layoutType: 'twoCol', + fields: { + name: { show: true, color: '#000' }, + price: { show: true, color: '#ff3000' }, + }, + badge: { show: false, imgUrl: '' }, + borderRadiusTop: 8, + borderRadiusBottom: 8, + space: 8, + spuIds: [], + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/product-list/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/product-list/index.vue new file mode 100644 index 00000000..0e7ec6e1 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/product-list/index.vue @@ -0,0 +1,150 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/product-list/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/product-list/property.vue new file mode 100644 index 00000000..f4e6d968 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/product-list/property.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/config.ts new file mode 100644 index 00000000..9ad0304b --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/config.ts @@ -0,0 +1,28 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 营销文章属性 */ +export interface PromotionArticleProperty { + // 文章编号 + id: number; + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'PromotionArticle', + name: '营销文章', + icon: 'ph:article-medium', + property: { + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/index.vue new file mode 100644 index 00000000..10e9f5aa --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/index.vue @@ -0,0 +1,33 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/property.vue new file mode 100644 index 00000000..82d3f35b --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-article/property.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/config.ts new file mode 100644 index 00000000..fba3a4a8 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/config.ts @@ -0,0 +1,99 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 拼团属性 */ +export interface PromotionCombinationProperty { + // 布局类型:单列 | 三列 + layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'; + // 商品字段 + fields: { + // 商品简介 + introduction: PromotionCombinationFieldProperty; + // 市场价 + marketPrice: PromotionCombinationFieldProperty; + // 商品名称 + name: PromotionCombinationFieldProperty; + // 商品价格 + price: PromotionCombinationFieldProperty; + // 商品销量 + salesCount: PromotionCombinationFieldProperty; + // 商品库存 + stock: PromotionCombinationFieldProperty; + }; + // 角标 + badge: { + // 角标图片 + imgUrl: string; + // 是否显示 + show: boolean; + }; + // 按钮 + btnBuy: { + // 文字按钮:背景渐变起始颜色 + bgBeginColor: string; + // 文字按钮:背景渐变结束颜色 + bgEndColor: string; + // 图片按钮:图片地址 + imgUrl: string; + // 文字 + text: string; + // 类型:文字 | 图片 + type: 'img' | 'text'; + }; + // 上圆角 + borderRadiusTop: number; + // 下圆角 + borderRadiusBottom: number; + // 间距 + space: number; + // 拼团活动编号 + activityIds: number[]; + // 组件样式 + style: ComponentStyle; +} + +// 商品字段 +export interface PromotionCombinationFieldProperty { + // 是否显示 + show: boolean; + // 颜色 + color: string; +} + +// 定义组件 +export const component = { + id: 'PromotionCombination', + name: '拼团', + icon: 'mdi:account-group', + property: { + layoutType: 'oneColBigImg', + fields: { + name: { show: true, color: '#000' }, + introduction: { show: true, color: '#999' }, + price: { show: true, color: '#ff3000' }, + marketPrice: { show: true, color: '#c4c4c4' }, + salesCount: { show: true, color: '#c4c4c4' }, + stock: { show: false, color: '#c4c4c4' }, + }, + badge: { show: false, imgUrl: '' }, + btnBuy: { + type: 'text', + text: '去拼团', + bgBeginColor: '#FF6000', + bgEndColor: '#FE832A', + imgUrl: '', + }, + borderRadiusTop: 8, + borderRadiusBottom: 8, + space: 8, + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/index.vue new file mode 100644 index 00000000..82f1f5bd --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/index.vue @@ -0,0 +1,233 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/property.vue new file mode 100644 index 00000000..da57011d --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-combination/property.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/config.ts new file mode 100644 index 00000000..4484f312 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/config.ts @@ -0,0 +1,99 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 积分商城属性 */ +export interface PromotionPointProperty { + // 布局类型:单列 | 三列 + layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'; + // 商品字段 + fields: { + // 商品简介 + introduction: PromotionPointFieldProperty; + // 市场价 + marketPrice: PromotionPointFieldProperty; + // 商品名称 + name: PromotionPointFieldProperty; + // 商品价格 + price: PromotionPointFieldProperty; + // 商品销量 + salesCount: PromotionPointFieldProperty; + // 商品库存 + stock: PromotionPointFieldProperty; + }; + // 角标 + badge: { + // 角标图片 + imgUrl: string; + // 是否显示 + show: boolean; + }; + // 按钮 + btnBuy: { + // 文字按钮:背景渐变起始颜色 + bgBeginColor: string; + // 文字按钮:背景渐变结束颜色 + bgEndColor: string; + // 图片按钮:图片地址 + imgUrl: string; + // 文字 + text: string; + // 类型:文字 | 图片 + type: 'img' | 'text'; + }; + // 上圆角 + borderRadiusTop: number; + // 下圆角 + borderRadiusBottom: number; + // 间距 + space: number; + // 秒杀活动编号 + activityIds: number[]; + // 组件样式 + style: ComponentStyle; +} + +// 商品字段 +export interface PromotionPointFieldProperty { + // 是否显示 + show: boolean; + // 颜色 + color: string; +} + +// 定义组件 +export const component = { + id: 'PromotionPoint', + name: '积分商城', + icon: 'ep:present', + property: { + layoutType: 'oneColBigImg', + fields: { + name: { show: true, color: '#000' }, + introduction: { show: true, color: '#999' }, + price: { show: true, color: '#ff3000' }, + marketPrice: { show: true, color: '#c4c4c4' }, + salesCount: { show: true, color: '#c4c4c4' }, + stock: { show: false, color: '#c4c4c4' }, + }, + badge: { show: false, imgUrl: '' }, + btnBuy: { + type: 'text', + text: '立即兑换', + bgBeginColor: '#FF6000', + bgEndColor: '#FE832A', + imgUrl: '', + }, + borderRadiusTop: 8, + borderRadiusBottom: 8, + space: 8, + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/index.vue new file mode 100644 index 00000000..3ff8336d --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/index.vue @@ -0,0 +1,234 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/property.vue new file mode 100644 index 00000000..c028feac --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-point/property.vue @@ -0,0 +1,180 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/config.ts new file mode 100644 index 00000000..fcba6c7e --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/config.ts @@ -0,0 +1,99 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 秒杀属性 */ +export interface PromotionSeckillProperty { + // 布局类型:单列 | 三列 + layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'; + // 商品字段 + fields: { + // 商品简介 + introduction: PromotionSeckillFieldProperty; + // 市场价 + marketPrice: PromotionSeckillFieldProperty; + // 商品名称 + name: PromotionSeckillFieldProperty; + // 商品价格 + price: PromotionSeckillFieldProperty; + // 商品销量 + salesCount: PromotionSeckillFieldProperty; + // 商品库存 + stock: PromotionSeckillFieldProperty; + }; + // 角标 + badge: { + // 角标图片 + imgUrl: string; + // 是否显示 + show: boolean; + }; + // 按钮 + btnBuy: { + // 文字按钮:背景渐变起始颜色 + bgBeginColor: string; + // 文字按钮:背景渐变结束颜色 + bgEndColor: string; + // 图片按钮:图片地址 + imgUrl: string; + // 文字 + text: string; + // 类型:文字 | 图片 + type: 'img' | 'text'; + }; + // 上圆角 + borderRadiusTop: number; + // 下圆角 + borderRadiusBottom: number; + // 间距 + space: number; + // 秒杀活动编号 + activityIds: number[]; + // 组件样式 + style: ComponentStyle; +} + +// 商品字段 +export interface PromotionSeckillFieldProperty { + // 是否显示 + show: boolean; + // 颜色 + color: string; +} + +// 定义组件 +export const component = { + id: 'PromotionSeckill', + name: '秒杀', + icon: 'mdi:calendar-time', + property: { + layoutType: 'oneColBigImg', + fields: { + name: { show: true, color: '#000' }, + introduction: { show: true, color: '#999' }, + price: { show: true, color: '#ff3000' }, + marketPrice: { show: true, color: '#c4c4c4' }, + salesCount: { show: true, color: '#c4c4c4' }, + stock: { show: false, color: '#c4c4c4' }, + }, + badge: { show: false, imgUrl: '' }, + btnBuy: { + type: 'text', + text: '立即秒杀', + bgBeginColor: '#FF6000', + bgEndColor: '#FE832A', + imgUrl: '', + }, + borderRadiusTop: 8, + borderRadiusBottom: 8, + space: 8, + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/index.vue new file mode 100644 index 00000000..b497437b --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/index.vue @@ -0,0 +1,229 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/property.vue new file mode 100644 index 00000000..3dd246f0 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/promotion-seckill/property.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/config.ts new file mode 100644 index 00000000..64ab098a --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/config.ts @@ -0,0 +1,46 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 搜索框属性 */ +export interface SearchProperty { + height: number; // 搜索栏高度 + showScan: boolean; // 显示扫一扫 + borderRadius: number; // 框体样式 + placeholder: string; // 占位文字 + placeholderPosition: PlaceholderPosition; // 占位文字位置 + backgroundColor: string; // 框体颜色 + textColor: string; // 字体颜色 + hotKeywords: string[]; // 热词 + style: ComponentStyle; +} + +// 文字位置 +export type PlaceholderPosition = 'center' | 'left'; + +// 定义组件 +export const component = { + id: 'SearchBar', + name: '搜索框', + icon: 'ep:search', + property: { + height: 28, + showScan: false, + borderRadius: 0, + placeholder: '搜索商品', + placeholderPosition: 'left', + backgroundColor: 'rgb(238, 238, 238)', + textColor: 'rgb(150, 151, 153)', + hotKeywords: [], + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + paddingTop: 8, + paddingRight: 8, + paddingBottom: 8, + paddingLeft: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/index.vue new file mode 100644 index 00000000..e7c77030 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/index.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/property.vue new file mode 100644 index 00000000..149f52fc --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/search-bar/property.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/config.ts new file mode 100644 index 00000000..bc9488e1 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/config.ts @@ -0,0 +1,172 @@ +import type { DiyComponent } from '#/components/diy-editor/util'; + +/** 底部导航菜单属性 */ +export interface TabBarProperty { + // 选项列表 + items: TabBarItemProperty[]; + // 主题 + theme: string; + // 样式 + style: TabBarStyle; +} + +// 选项属性 +export interface TabBarItemProperty { + // 标签文字 + text: string; + // 链接 + url: string; + // 默认图标链接 + iconUrl: string; + // 选中的图标链接 + activeIconUrl: string; +} + +// 样式 +export interface TabBarStyle { + // 背景类型 + bgType: 'color' | 'img'; + // 背景颜色 + bgColor: string; + // 图片链接 + bgImg: string; + // 默认颜色 + color: string; + // 选中的颜色 + activeColor: string; +} + +// 定义组件 +export const component = { + id: 'TabBar', + name: '底部导航', + icon: 'fluent:table-bottom-row-16-filled', + property: { + theme: 'red', + style: { + bgType: 'color', + bgColor: '#fff', + color: '#282828', + activeColor: '#fc4141', + }, + items: [ + { + text: '首页', + url: '/pages/index/index', + iconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-001.png', + activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/1-002.png', + }, + { + text: '分类', + url: '/pages/index/category?id=3', + iconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-001.png', + activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/2-002.png', + }, + { + text: '购物车', + url: '/pages/index/cart', + iconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-001.png', + activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/3-002.png', + }, + { + text: '我的', + url: '/pages/index/user', + iconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-001.png', + activeIconUrl: 'http://mall.yudao.iocoder.cn/static/images/4-002.png', + }, + ], + }, +} as DiyComponent; + +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', + }, +]; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/index.vue new file mode 100644 index 00000000..9c1ddd83 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/index.vue @@ -0,0 +1,79 @@ + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/property.vue new file mode 100644 index 00000000..fab41b64 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/tab-bar/property.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/config.ts new file mode 100644 index 00000000..64d49ad6 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/config.ts @@ -0,0 +1,76 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 标题栏属性 */ +export interface TitleBarProperty { + // 背景图 + bgImgUrl: string; + // 偏移 + marginLeft: number; + // 显示位置 + textAlign: 'center' | 'left'; + // 主标题 + title: string; + // 副标题 + description: string; + // 标题大小 + titleSize: number; + // 描述大小 + descriptionSize: number; + // 标题粗细 + titleWeight: number; + // 描述粗细 + descriptionWeight: number; + // 标题颜色 + titleColor: string; + // 描述颜色 + descriptionColor: string; + // 高度 + height: number; + // 查看更多 + more: { + // 是否显示查看更多 + show: false; + // 自定义文字 + text: string; + // 样式选择 + type: 'all' | 'icon' | 'text'; + // 链接 + url: string; + }; + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'TitleBar', + name: '标题栏', + icon: 'material-symbols:line-start', + property: { + title: '主标题', + description: '副标题', + titleSize: 16, + descriptionSize: 12, + titleWeight: 400, + textAlign: 'left', + descriptionWeight: 200, + titleColor: 'rgba(50, 50, 51, 10)', + descriptionColor: 'rgba(150, 151, 153, 10)', + marginLeft: 0, + height: 40, + more: { + // 查看更多 + show: false, + type: 'icon', + text: '查看更多', + url: '', + }, + style: { + bgType: 'color', + bgColor: '#fff', + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/index.vue new file mode 100644 index 00000000..8ee389d8 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/index.vue @@ -0,0 +1,88 @@ + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/property.vue new file mode 100644 index 00000000..45a4147c --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/title-bar/property.vue @@ -0,0 +1,168 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-card/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/user-card/config.ts new file mode 100644 index 00000000..e674a0a3 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-card/config.ts @@ -0,0 +1,24 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 用户卡片属性 */ +export interface UserCardProperty { + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'UserCard', + name: '用户卡片', + icon: 'mdi:user-card-details', + property: { + style: { + bgType: 'color', + bgColor: '', + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-card/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-card/index.vue new file mode 100644 index 00000000..9cb312f3 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-card/index.vue @@ -0,0 +1,35 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-card/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-card/property.vue new file mode 100644 index 00000000..38f5d2b5 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-card/property.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/config.ts new file mode 100644 index 00000000..efcb7f2e --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/config.ts @@ -0,0 +1,26 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 用户卡券属性 */ +export interface UserCouponProperty { + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'UserCoupon', + name: '用户卡券', + icon: 'ep:ticket', + property: { + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/index.vue new file mode 100644 index 00000000..2df2df32 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/index.vue @@ -0,0 +1,17 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/property.vue new file mode 100644 index 00000000..c9fb1fbf --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-coupon/property.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-order/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/user-order/config.ts new file mode 100644 index 00000000..0c2e825a --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-order/config.ts @@ -0,0 +1,26 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 用户订单属性 */ +export interface UserOrderProperty { + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'UserOrder', + name: '用户订单', + icon: 'ep:list', + property: { + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-order/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-order/index.vue new file mode 100644 index 00000000..ab527ace --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-order/index.vue @@ -0,0 +1,17 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-order/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-order/property.vue new file mode 100644 index 00000000..d403c325 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-order/property.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/config.ts new file mode 100644 index 00000000..8393760b --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/config.ts @@ -0,0 +1,26 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 用户资产属性 */ +export interface UserWalletProperty { + // 组件样式 + style: ComponentStyle; +} + +// 定义组件 +export const component = { + id: 'UserWallet', + name: '用户资产', + icon: 'ep:wallet-filled', + property: { + style: { + bgType: 'color', + bgColor: '', + marginLeft: 8, + marginRight: 8, + marginBottom: 8, + } as ComponentStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/index.vue new file mode 100644 index 00000000..7581e54c --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/index.vue @@ -0,0 +1,17 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/property.vue new file mode 100644 index 00000000..851e7f2f --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/user-wallet/property.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/video-player/config.ts b/apps/web-ele/src/components/diy-editor/components/mobile/video-player/config.ts new file mode 100644 index 00000000..dc2dd886 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/video-player/config.ts @@ -0,0 +1,40 @@ +import type { + ComponentStyle, + DiyComponent, +} from '#/components/diy-editor/util'; + +/** 视频播放属性 */ +export interface VideoPlayerProperty { + // 视频链接 + videoUrl: string; + // 封面链接 + posterUrl: string; + // 是否自动播放 + autoplay: boolean; + // 组件样式 + style: VideoPlayerStyle; +} + +// 视频播放样式 +export interface VideoPlayerStyle extends ComponentStyle { + // 视频高度 + height: number; +} + +// 定义组件 +export const component = { + id: 'VideoPlayer', + name: '视频播放', + icon: 'ep:video-play', + property: { + videoUrl: '', + posterUrl: '', + autoplay: false, + style: { + bgType: 'color', + bgColor: '#fff', + marginBottom: 8, + height: 300, + } as VideoPlayerStyle, + }, +} as DiyComponent; diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/video-player/index.vue b/apps/web-ele/src/components/diy-editor/components/mobile/video-player/index.vue new file mode 100644 index 00000000..ddd448d9 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/video-player/index.vue @@ -0,0 +1,36 @@ + + + + diff --git a/apps/web-ele/src/components/diy-editor/components/mobile/video-player/property.vue b/apps/web-ele/src/components/diy-editor/components/mobile/video-player/property.vue new file mode 100644 index 00000000..d07835f2 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/components/mobile/video-player/property.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/apps/web-ele/src/components/diy-editor/index.vue b/apps/web-ele/src/components/diy-editor/index.vue new file mode 100644 index 00000000..7f7ce0e3 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/index.vue @@ -0,0 +1,659 @@ + +