From d8f4979a476d8353c280e4d9881faefc407deed5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 25 Oct 2025 21:02:09 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ele=E3=80=91=E3=80=90?= =?UTF-8?q?mall=E3=80=91diy/page=20=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-ele/src/router/routes/modules/mall.ts | 4 +- .../promotion/components/diy-editor/index.vue | 2 +- .../decorate.vue => decorate/index.vue} | 0 .../views/mall/promotion/diy/template/data.ts | 7 +- .../decorate.vue => decorate/index.vue} | 140 ++++++++---------- .../mall/promotion/diy/template/index.vue | 22 ++- .../promotion/diy/template/modules/form.vue | 13 +- 7 files changed, 86 insertions(+), 102 deletions(-) rename apps/web-ele/src/views/mall/promotion/diy/page/{modules/decorate.vue => decorate/index.vue} (100%) rename apps/web-ele/src/views/mall/promotion/diy/template/{modules/decorate.vue => decorate/index.vue} (68%) diff --git a/apps/web-ele/src/router/routes/modules/mall.ts b/apps/web-ele/src/router/routes/modules/mall.ts index 6d9303943..1c2f40496 100644 --- a/apps/web-ele/src/router/routes/modules/mall.ts +++ b/apps/web-ele/src/router/routes/modules/mall.ts @@ -98,7 +98,7 @@ const routes: RouteRecordRaw[] = [ activePath: '/mall/promotion/diy-template/diy-template', }, component: () => - import('#/views/mall/promotion/diy/template/modules/decorate.vue'), + import('#/views/mall/promotion/diy/template/decorate/index.vue'), }, { path: 'page/decorate/:id', @@ -110,7 +110,7 @@ const routes: RouteRecordRaw[] = [ activePath: '/mall/promotion/diy-template/diy-page', }, component: () => - import('#/views/mall/promotion/diy/page/modules/decorate.vue'), + import('#/views/mall/promotion/diy/page/decorate/index.vue'), }, ], }, diff --git a/apps/web-ele/src/views/mall/promotion/components/diy-editor/index.vue b/apps/web-ele/src/views/mall/promotion/components/diy-editor/index.vue index b2e5a2556..f9f7d9c89 100644 --- a/apps/web-ele/src/views/mall/promotion/components/diy-editor/index.vue +++ b/apps/web-ele/src/views/mall/promotion/components/diy-editor/index.vue @@ -267,7 +267,7 @@ const handleDeleteComponent = (index: number) => { }; // 注入无感刷新页面函数 -const reload = inject<() => void>('reload'); +const reload = inject<() => void>('reload'); // TODO @芋艿:是 vue3 + element-plus 独有的,可以清理掉。 // 重置 const handleReset = () => { if (reload) reload(); diff --git a/apps/web-ele/src/views/mall/promotion/diy/page/modules/decorate.vue b/apps/web-ele/src/views/mall/promotion/diy/page/decorate/index.vue similarity index 100% rename from apps/web-ele/src/views/mall/promotion/diy/page/modules/decorate.vue rename to apps/web-ele/src/views/mall/promotion/diy/page/decorate/index.vue diff --git a/apps/web-ele/src/views/mall/promotion/diy/template/data.ts b/apps/web-ele/src/views/mall/promotion/diy/template/data.ts index ca09c59fa..e3c8f1421 100644 --- a/apps/web-ele/src/views/mall/promotion/diy/template/data.ts +++ b/apps/web-ele/src/views/mall/promotion/diy/template/data.ts @@ -3,6 +3,8 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import { DICT_TYPE } from '@vben/constants'; +import { getRangePickerDefaultProps } from '#/utils'; + /** 表单配置 */ export function useFormSchema(): VbenFormSchema[] { return [ @@ -61,9 +63,8 @@ export function useGridFormSchema(): VbenFormSchema[] { label: '创建时间', component: 'RangePicker', componentProps: { - placeholder: ['开始时间', '结束时间'], - clearable: true, - valueFormat: 'YYYY-MM-DD HH:mm:ss', + ...getRangePickerDefaultProps(), + allowClear: true, }, }, ]; diff --git a/apps/web-ele/src/views/mall/promotion/diy/template/modules/decorate.vue b/apps/web-ele/src/views/mall/promotion/diy/template/decorate/index.vue similarity index 68% rename from apps/web-ele/src/views/mall/promotion/diy/template/modules/decorate.vue rename to apps/web-ele/src/views/mall/promotion/diy/template/decorate/index.vue index 6beff4f2b..566dc0d5e 100644 --- a/apps/web-ele/src/views/mall/promotion/diy/template/modules/decorate.vue +++ b/apps/web-ele/src/views/mall/promotion/diy/template/decorate/index.vue @@ -3,67 +3,75 @@ import type { MallDiyPageApi } from '#/api/mall/promotion/diy/page'; import type { MallDiyTemplateApi } from '#/api/mall/promotion/diy/template'; import type { DiyComponentLibrary } from '#/views/mall/promotion/components'; // 商城的 DIY 组件,在 DiyEditor 目录下 -import { onMounted, reactive, ref, unref } from 'vue'; -import { useRouter } from 'vue-router'; +import { onMounted, reactive, ref } from 'vue'; +import { useRoute } from 'vue-router'; +import { useTabs } from '@vben/hooks'; import { IconifyIcon } from '@vben/icons'; import { useAccessStore } from '@vben/stores'; import { isEmpty } from '@vben/utils'; -import { ElMessage } from 'element-plus'; +import { + ElLoading, + ElMessage, + ElRadioButton, + ElRadioGroup, + ElTooltip, +} from 'element-plus'; import * as DiyPageApi from '#/api/mall/promotion/diy/page'; -// TODO @疯狂:要不要建个 decorate 目录,然后挪进去,改成 index.vue,这样可以更明确看到是个独立界面哈,更好找 import * as DiyTemplateApi from '#/api/mall/promotion/diy/template'; import { DiyEditor, PAGE_LIBS } from '#/views/mall/promotion/components'; /** 装修模板表单 */ defineOptions({ name: 'DiyTemplateDecorate' }); -// 左上角工具栏操作按钮 +const route = useRoute(); +const { refreshTab } = useTabs(); + +const DIY_PAGE_INDEX_KEY = 'diy_page_index'; // 特殊:存储 reset 重置时,当前 selectedTemplateItem 值,从而进行恢复 + const selectedTemplateItem = ref(0); const templateItems = reactive([ { name: '基础设置', icon: 'ep:iphone' }, { name: '首页', icon: 'ep:home-filled' }, { name: '我的', icon: 'ep:user-filled' }, -]); +]); // 左上角工具栏操作按钮 -const formLoading = ref(false); // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 const formData = ref(); -const formRef = ref(); // 表单 Ref -// 当前编辑的属性 const currentFormData = ref< MallDiyPageApi.DiyPage | MallDiyTemplateApi.DiyTemplateProperty >({ property: '', -} as MallDiyPageApi.DiyPage); -// templateItem 对应的缓存 +} as MallDiyPageApi.DiyPage); // 当前编辑的属性 const currentFormDataMap = ref< Map ->(new Map()); -// 商城 H5 预览地址 -const previewUrl = ref(''); +>(new Map()); // templateItem 对应的缓存 -// 获取详情 -const getPageDetail = async (id: any) => { - formLoading.value = true; +const previewUrl = ref(''); // 商城 H5 预览地址 + +const templateLibs = [] as DiyComponentLibrary[]; // 模板组件库 +const libs = ref(templateLibs); // 当前组件库 + +/** 获取详情 */ +async function getPageDetail(id: any) { + const loadingInstance = ElLoading.service({ + text: '加载中...', + }); try { formData.value = await DiyTemplateApi.getDiyTemplateProperty(id); + // 拼接手机预览链接 const domain = import.meta.env.VITE_MALL_H5_DOMAIN; const accessStore = useAccessStore(); previewUrl.value = `${domain}?templateId=${formData.value.id}&${accessStore.tenantId}`; } finally { - formLoading.value = false; + loadingInstance.close(); } -}; +} -// 模板组件库 -const templateLibs = [] as DiyComponentLibrary[]; -// 当前组件库 -const libs = ref(templateLibs); -// 模板选项切换 -const handleTemplateItemChange = (val: number) => { +/** 模板选项切换 */ +function handleTemplateItemChange(val: any) { // 缓存模版编辑数据 currentFormDataMap.value.set( templateItems[selectedTemplateItem.value]?.name || '', @@ -74,7 +82,8 @@ const handleTemplateItemChange = (val: number) => { // 切换模版 selectedTemplateItem.value = val; - // 编辑模板 + + // 情况一:编辑模板 if (val === 0) { libs.value = templateLibs; currentFormData.value = (isEmpty(data) ? formData.value : data) as @@ -83,7 +92,7 @@ const handleTemplateItemChange = (val: number) => { return; } - // 编辑页面 + // 情况二:编辑页面 libs.value = PAGE_LIBS; currentFormData.value = ( isEmpty(data) @@ -93,14 +102,13 @@ const handleTemplateItemChange = (val: number) => { ) : data ) as MallDiyPageApi.DiyPage | MallDiyTemplateApi.DiyTemplateProperty; -}; +} -// 提交表单 -const submitForm = async () => { - // 校验表单 - if (!formRef.value) return; - // 提交请求 - formLoading.value = true; +/** 提交表单 */ +async function submitForm() { + const loadingInstance = ElLoading.service({ + text: '保存中...', + }); try { // 对所有的 templateItems 都进行保存,有缓存则保存缓存,解决都有修改时只保存了当前所编辑的 templateItem,导致装修效果存在差异 for (const [i, templateItem] of templateItems.entries()) { @@ -109,14 +117,14 @@ const submitForm = async () => { if (i === 0) { // 提交模板属性 await DiyTemplateApi.updateDiyTemplateProperty( - isEmpty(data) ? unref(formData)! : data, + isEmpty(data) ? formData.value! : data, ); continue; } // 提交页面属性 // 情况二:提交当前正在编辑的页面 if (currentFormData.value?.name.includes(templateItem.name)) { - await DiyPageApi.updateDiyPageProperty(unref(currentFormData)!); + await DiyPageApi.updateDiyPageProperty(currentFormData.value!); continue; } // 情况三:提交页面编辑缓存 @@ -126,36 +134,18 @@ const submitForm = async () => { } ElMessage.success('保存成功'); } finally { - formLoading.value = false; + loadingInstance.close(); } -}; +} -// 重置表单 -const resetForm = () => { - formData.value = { - id: undefined, - name: '', - used: false, - usedTime: undefined, - remark: '', - previewPicUrls: [], - property: '', - pages: [], - } as MallDiyTemplateApi.DiyTemplateProperty; - formRef.value?.resetFields(); -}; - -// 重置时记录当前编辑的页面 -const handleEditorReset = () => storePageIndex(); - -// #region 无感刷新 -// 记录标识 -const DIY_PAGE_INDEX_KEY = 'diy_page_index'; -// 1. 记录 -const storePageIndex = () => +/** 刷新当前 Tab */ +function handleEditorReset() { sessionStorage.setItem(DIY_PAGE_INDEX_KEY, `${selectedTemplateItem.value}`); -// 2. 恢复 -const recoverPageIndex = () => { + refreshTab(); +} + +/** 恢复当前 Tab 之前的 index(selectedTemplateItem) */ +function recoverPageIndex() { // 恢复重置前的页面,默认是第一个页面 const pageIndex = Number(sessionStorage.getItem(DIY_PAGE_INDEX_KEY)) || 0; // 移除标记 @@ -173,26 +163,24 @@ const recoverPageIndex = () => { if (pageIndex !== selectedTemplateItem.value) { handleTemplateItemChange(pageIndex); } -}; -// #endregion +} /** 初始化 */ -const { currentRoute } = useRouter(); onMounted(async () => { - resetForm(); - if (!currentRoute.value.params.id) { + if (!route.params.id) { ElMessage.warning('参数错误,页面编号不能为空!'); return; } // 查询详情 - await getPageDetail(currentRoute.value.params.id); + formData.value = {} as MallDiyTemplateApi.DiyTemplateProperty; + await getPageDetail(route.params.id); // 恢复重置前的页面 recoverPageIndex(); }); diff --git a/apps/web-ele/src/views/mall/promotion/diy/template/index.vue b/apps/web-ele/src/views/mall/promotion/diy/template/index.vue index 74abcb732..456b50d13 100644 --- a/apps/web-ele/src/views/mall/promotion/diy/template/index.vue +++ b/apps/web-ele/src/views/mall/promotion/diy/template/index.vue @@ -33,32 +33,38 @@ function handleRefresh() { gridApi.query(); } -/** 创建DIY模板 */ +/** 创建 DIY 模板 */ function handleCreate() { formModalApi.setData(null).open(); } -/** 编辑DIY模板 */ +/** 编辑 DIY 模板 */ function handleEdit(row: MallDiyTemplateApi.DiyTemplate) { formModalApi.setData(row).open(); } /** 装修模板 */ function handleDecorate(row: MallDiyTemplateApi.DiyTemplate) { - // 跳转到装修页面 router.push({ name: 'DiyTemplateDecorate', params: { id: row.id } }); } /** 使用模板 */ async function handleUse(row: MallDiyTemplateApi.DiyTemplate) { await confirm(`是否使用模板"${row.name}"?`); - // 发起删除 - await useDiyTemplate(row.id as number); - ElMessage.success('使用成功'); - handleRefresh(); + + const loadingInstance = ElLoading.service({ + text: `正在使用模板"${row.name}"...`, + }); + try { + await useDiyTemplate(row.id as number); + ElMessage.success('使用成功'); + handleRefresh(); + } finally { + loadingInstance.close(); + } } -/** 删除DIY模板 */ +/** 删除 DIY 模板 */ async function handleDelete(row: MallDiyTemplateApi.DiyTemplate) { const loadingInstance = ElLoading.service({ text: $t('ui.actionMessage.deleting', [row.name]), diff --git a/apps/web-ele/src/views/mall/promotion/diy/template/modules/form.vue b/apps/web-ele/src/views/mall/promotion/diy/template/modules/form.vue index 886d3946e..8e088d7cf 100644 --- a/apps/web-ele/src/views/mall/promotion/diy/template/modules/form.vue +++ b/apps/web-ele/src/views/mall/promotion/diy/template/modules/form.vue @@ -16,9 +16,7 @@ import { $t } from '#/locales'; import { useFormSchema } from '../data'; -/** 提交表单 */ const emit = defineEmits(['success']); - const formData = ref(); const getTitle = computed(() => { return formData.value?.id @@ -47,15 +45,6 @@ const [Modal, modalApi] = useVbenModal({ modalApi.lock(); // 提交表单 const data = (await formApi.getValues()) as MallDiyTemplateApi.DiyTemplate; - - // 确保必要的默认值 - if (!data.previewPicUrls) { - data.previewPicUrls = []; - } - if (data.used === undefined) { - data.used = false; - } - try { await (formData.value?.id ? updateDiyTemplate(data) @@ -91,7 +80,7 @@ const [Modal, modalApi] = useVbenModal({ From 5e259eb685f70626b2d578d40d01f275a07d5469 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 25 Oct 2025 21:27:37 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat=EF=BC=9A=E3=80=90antd=E3=80=91?= =?UTF-8?q?=E3=80=90mall=E3=80=91diy=20=E4=B8=BB=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E7=9A=84=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/mall/promotion/diy/page.ts | 20 +- .../src/api/mall/promotion/diy/template.ts | 24 +- .../src/router/routes/modules/mall.ts | 34 +++ .../promotion/components/diy-editor/index.vue | 44 ++++ .../promotion/components/diy-editor/util.ts | 125 +++++++++++ .../views/mall/promotion/components/index.ts | 2 + .../src/views/mall/promotion/diy/page/data.ts | 7 +- .../promotion/diy/page/decorate/index.vue | 64 ++++++ .../views/mall/promotion/diy/page/index.vue | 16 +- .../mall/promotion/diy/page/modules/form.vue | 8 +- .../views/mall/promotion/diy/template/data.ts | 7 +- .../promotion/diy/template/decorate/index.vue | 208 ++++++++++++++++++ .../mall/promotion/diy/template/index.vue | 34 ++- .../promotion/diy/template/modules/form.vue | 13 +- .../mall/promotion/diy/template/index.vue | 1 - 15 files changed, 552 insertions(+), 55 deletions(-) create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/util.ts create mode 100644 apps/web-antd/src/views/mall/promotion/diy/page/decorate/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/diy/template/decorate/index.vue diff --git a/apps/web-antd/src/api/mall/promotion/diy/page.ts b/apps/web-antd/src/api/mall/promotion/diy/page.ts index d332cc09e..afdface5a 100644 --- a/apps/web-antd/src/api/mall/promotion/diy/page.ts +++ b/apps/web-antd/src/api/mall/promotion/diy/page.ts @@ -5,12 +5,18 @@ import { requestClient } from '#/api/request'; export namespace MallDiyPageApi { /** 装修页面 */ export interface DiyPage { - id?: number; // 页面编号 - templateId?: number; // 模板编号 - name: string; // 页面名称 - remark: string; // 备注 - previewPicUrls: string[]; // 预览图片地址数组 - property: string; // 页面属性 + /** 页面编号 */ + id?: number; + /** 模板编号 */ + templateId?: number; + /** 页面名称 */ + name: string; + /** 备注 */ + remark: string; + /** 预览图片地址数组 */ + previewPicUrls: string[]; + /** 页面属性 */ + property: string; } } @@ -46,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-antd/src/api/mall/promotion/diy/template.ts b/apps/web-antd/src/api/mall/promotion/diy/template.ts index 9b7596e85..f7d82d352 100644 --- a/apps/web-antd/src/api/mall/promotion/diy/template.ts +++ b/apps/web-antd/src/api/mall/promotion/diy/template.ts @@ -7,18 +7,26 @@ import { requestClient } from '#/api/request'; export namespace MallDiyTemplateApi { /** 装修模板 */ export interface DiyTemplate { - id?: number; // 模板编号 - name: string; // 模板名称 - used: boolean; // 是否使用 - usedTime?: Date; // 使用时间 - remark: string; // 备注 - previewPicUrls: string[]; // 预览图片地址数组 - property: string; // 模板属性 + /** 模板编号 */ + id?: number; + /** 模板名称 */ + name: string; + /** 是否使用 */ + used: boolean; + /** 使用时间 */ + usedTime?: Date; + /** 备注 */ + remark: string; + /** 预览图片地址数组 */ + previewPicUrls: string[]; + /** 模板属性 */ + property: string; } /** 装修模板属性(包含页面列表) */ export interface DiyTemplateProperty extends DiyTemplate { - pages: MallDiyPageApi.DiyPage[]; // 页面列表 + /** 页面列表 */ + pages: MallDiyPageApi.DiyPage[]; } } diff --git a/apps/web-antd/src/router/routes/modules/mall.ts b/apps/web-antd/src/router/routes/modules/mall.ts index 870c111f5..db8fcab5e 100644 --- a/apps/web-antd/src/router/routes/modules/mall.ts +++ b/apps/web-antd/src/router/routes/modules/mall.ts @@ -71,6 +71,40 @@ const routes: RouteRecordRaw[] = [ }, ], }, + { + path: '/diy', + name: 'DiyCenter', + meta: { + title: '营销中心', + icon: 'lucide:shopping-bag', + keepAlive: true, + hideInMenu: true, + }, + children: [ + { + path: String.raw`template/decorate/:id(\d+)`, + name: 'DiyTemplateDecorate', + meta: { + title: '模板装修', + activePath: '/mall/promotion/diy-template/diy-template', + }, + component: () => + import('#/views/mall/promotion/diy/template/decorate/index.vue'), + }, + { + path: 'page/decorate/:id', + name: 'DiyPageDecorate', + meta: { + title: '页面装修', + noCache: false, + hidden: true, + activePath: '/mall/promotion/diy-template/diy-page', + }, + component: () => + import('#/views/mall/promotion/diy/page/decorate/index.vue'), + }, + ], + }, ]; export default routes; diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue new file mode 100644 index 000000000..4f0124fe3 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/util.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/util.ts new file mode 100644 index 000000000..b273e8a92 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/util.ts @@ -0,0 +1,125 @@ +// 页面装修组件 +export interface DiyComponent { + // 用于区分同一种组件的不同实例 + uid?: number; + // 组件唯一标识 + id: string; + // 组件名称 + name: string; + // 组件图标 + icon: string; + /* + 组件位置: + top: 固定于手机顶部,例如 顶部的导航栏 + bottom: 固定于手机底部,例如 底部的菜单导航栏 + center: 位于手机中心,每个组件占一行,顺序向下排列 + 空:同center + fixed: 由组件自己决定位置,如弹窗位于手机中心、浮动按钮一般位于手机右下角 + */ + position?: '' | 'bottom' | 'center' | 'fixed' | 'top'; + // 组件属性 + property: T; +} + +// 页面装修组件库 +export interface DiyComponentLibrary { + // 组件库名称 + name: string; + // 是否展开 + extended: boolean; + // 组件列表 + components: string[]; +} + +// 组件样式 +export interface ComponentStyle { + // 背景类型 + bgType: 'color' | 'img'; + // 背景颜色 + bgColor: string; + // 背景图片 + bgImg: string; + // 外边距 + margin: number; + marginTop: number; + marginRight: number; + marginBottom: number; + marginLeft: number; + // 内边距 + padding: number; + paddingTop: number; + paddingRight: number; + paddingBottom: number; + paddingLeft: number; + // 边框圆角 + borderRadius: number; + borderTopLeftRadius: number; + borderTopRightRadius: number; + borderBottomRightRadius: number; + borderBottomLeftRadius: number; +} + +// 页面配置 +export interface PageConfig { + // 页面属性 + page: any; + // 顶部导航栏属性 + navigationBar: any; + // 底部导航菜单属性 + tabBar?: any; + // 页面组件列表 + components: PageComponent[]; +} +// 页面组件,只保留组件ID,组件属性 +export type PageComponent = Pick, 'id' | 'property'>; + +// 页面组件库 +export const PAGE_LIBS = [ + { + name: '基础组件', + extended: true, + components: [ + 'SearchBar', + 'NoticeBar', + 'MenuSwiper', + 'MenuGrid', + 'MenuList', + 'Popover', + 'FloatingActionButton', + ], + }, + { + name: '图文组件', + extended: true, + components: [ + 'ImageBar', + 'Carousel', + 'TitleBar', + 'VideoPlayer', + 'Divider', + 'MagicCube', + 'HotZone', + ], + }, + { + name: '商品组件', + extended: true, + components: ['ProductCard', 'ProductList'], + }, + { + name: '用户组件', + extended: true, + components: ['UserCard', 'UserOrder', 'UserWallet', 'UserCoupon'], + }, + { + name: '营销组件', + extended: true, + components: [ + 'PromotionCombination', + 'PromotionSeckill', + 'PromotionPoint', + 'CouponCard', + 'PromotionArticle', + ], + }, +] as DiyComponentLibrary[]; diff --git a/apps/web-antd/src/views/mall/promotion/components/index.ts b/apps/web-antd/src/views/mall/promotion/components/index.ts index b28e0c632..a382904c1 100644 --- a/apps/web-antd/src/views/mall/promotion/components/index.ts +++ b/apps/web-antd/src/views/mall/promotion/components/index.ts @@ -1,3 +1,5 @@ +export { default as DiyEditor } from './diy-editor/index.vue'; +export { type DiyComponentLibrary, PAGE_LIBS } from './diy-editor/util'; export { default as SpuAndSkuList } from './spu-and-sku-list.vue'; export { default as SpuSkuSelect } from './spu-sku-select.vue'; diff --git a/apps/web-antd/src/views/mall/promotion/diy/page/data.ts b/apps/web-antd/src/views/mall/promotion/diy/page/data.ts index 5e6682825..cec26ffcf 100644 --- a/apps/web-antd/src/views/mall/promotion/diy/page/data.ts +++ b/apps/web-antd/src/views/mall/promotion/diy/page/data.ts @@ -1,6 +1,8 @@ import type { VbenFormSchema } from '#/adapter/form'; import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import { getRangePickerDefaultProps } from '#/utils'; + /** 表单配置 */ export function useFormSchema(): VbenFormSchema[] { return [ @@ -51,7 +53,7 @@ export function useGridFormSchema(): VbenFormSchema[] { component: 'Input', componentProps: { placeholder: '请输入页面名称', - allowClear: true, + clearable: true, }, }, { @@ -59,9 +61,8 @@ export function useGridFormSchema(): VbenFormSchema[] { label: '创建时间', component: 'RangePicker', componentProps: { - placeholder: ['开始时间', '结束时间'], + ...getRangePickerDefaultProps(), allowClear: true, - valueFormat: 'YYYY-MM-DD HH:mm:ss', }, }, ]; diff --git a/apps/web-antd/src/views/mall/promotion/diy/page/decorate/index.vue b/apps/web-antd/src/views/mall/promotion/diy/page/decorate/index.vue new file mode 100644 index 000000000..d2ba2441e --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/page/decorate/index.vue @@ -0,0 +1,64 @@ + + diff --git a/apps/web-antd/src/views/mall/promotion/diy/page/index.vue b/apps/web-antd/src/views/mall/promotion/diy/page/index.vue index 65bc4da59..c1af949b1 100644 --- a/apps/web-antd/src/views/mall/promotion/diy/page/index.vue +++ b/apps/web-antd/src/views/mall/promotion/diy/page/index.vue @@ -6,6 +6,8 @@ import { useRouter } from 'vue-router'; import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; +import { message } from 'ant-design-vue'; + import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteDiyPage, getDiyPagePage } from '#/api/mall/promotion/diy/page'; import { $t } from '#/locales'; @@ -37,7 +39,6 @@ function handleEdit(row: MallDiyPageApi.DiyPage) { formModalApi.setData(row).open(); } -// TODO @xingyu:装修未实现 /** 装修页面 */ function handleDecorate(row: MallDiyPageApi.DiyPage) { push({ name: 'DiyPageDecorate', params: { id: row.id } }); @@ -45,8 +46,17 @@ function handleDecorate(row: MallDiyPageApi.DiyPage) { /** 删除 DIY 页面 */ async function handleDelete(row: MallDiyPageApi.DiyPage) { - await deleteDiyPage(row.id as number); - handleRefresh(); + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting', [row.name]), + duration: 0, + }); + try { + await deleteDiyPage(row.id as number); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + handleRefresh(); + } finally { + hideLoading(); + } } const [Grid, gridApi] = useVbenVxeGrid({ diff --git a/apps/web-antd/src/views/mall/promotion/diy/page/modules/form.vue b/apps/web-antd/src/views/mall/promotion/diy/page/modules/form.vue index 5045bf240..b3e383e83 100644 --- a/apps/web-antd/src/views/mall/promotion/diy/page/modules/form.vue +++ b/apps/web-antd/src/views/mall/promotion/diy/page/modules/form.vue @@ -45,12 +45,6 @@ const [Modal, modalApi] = useVbenModal({ modalApi.lock(); // 提交表单 const data = (await formApi.getValues()) as MallDiyPageApi.DiyPage; - - // 确保必要的默认值 - if (!data.previewPicUrls) { - data.previewPicUrls = []; - } - try { await (formData.value?.id ? updateDiyPage(data) : createDiyPage(data)); // 关闭并提示 @@ -84,7 +78,7 @@ const [Modal, modalApi] = useVbenModal({ diff --git a/apps/web-antd/src/views/mall/promotion/diy/template/data.ts b/apps/web-antd/src/views/mall/promotion/diy/template/data.ts index 8c736f1ac..e3c8f1421 100644 --- a/apps/web-antd/src/views/mall/promotion/diy/template/data.ts +++ b/apps/web-antd/src/views/mall/promotion/diy/template/data.ts @@ -3,6 +3,8 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import { DICT_TYPE } from '@vben/constants'; +import { getRangePickerDefaultProps } from '#/utils'; + /** 表单配置 */ export function useFormSchema(): VbenFormSchema[] { return [ @@ -53,7 +55,7 @@ export function useGridFormSchema(): VbenFormSchema[] { component: 'Input', componentProps: { placeholder: '请输入模板名称', - allowClear: true, + clearable: true, }, }, { @@ -61,9 +63,8 @@ export function useGridFormSchema(): VbenFormSchema[] { label: '创建时间', component: 'RangePicker', componentProps: { - placeholder: ['开始时间', '结束时间'], + ...getRangePickerDefaultProps(), allowClear: true, - valueFormat: 'YYYY-MM-DD HH:mm:ss', }, }, ]; diff --git a/apps/web-antd/src/views/mall/promotion/diy/template/decorate/index.vue b/apps/web-antd/src/views/mall/promotion/diy/template/decorate/index.vue new file mode 100644 index 000000000..efe233077 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/template/decorate/index.vue @@ -0,0 +1,208 @@ + + diff --git a/apps/web-antd/src/views/mall/promotion/diy/template/index.vue b/apps/web-antd/src/views/mall/promotion/diy/template/index.vue index da7be750e..ec43bcea0 100644 --- a/apps/web-antd/src/views/mall/promotion/diy/template/index.vue +++ b/apps/web-antd/src/views/mall/promotion/diy/template/index.vue @@ -43,7 +43,6 @@ function handleEdit(row: MallDiyTemplateApi.DiyTemplate) { formModalApi.setData(row).open(); } -// TODO @xingyu:装修未实现 /** 装修模板 */ function handleDecorate(row: MallDiyTemplateApi.DiyTemplate) { router.push({ name: 'DiyTemplateDecorate', params: { id: row.id } }); @@ -51,20 +50,33 @@ function handleDecorate(row: MallDiyTemplateApi.DiyTemplate) { /** 使用模板 */ async function handleUse(row: MallDiyTemplateApi.DiyTemplate) { - confirm({ - content: `是否使用模板"${row.name}"?`, - }).then(async () => { - // 发起删除 + await confirm(`是否使用模板"${row.name}"?`); + const hideLoading = message.loading({ + content: `正在使用模板"${row.name}"...`, + duration: 0, + }); + try { await useDiyTemplate(row.id as number); message.success('使用成功'); handleRefresh(); - }); + } finally { + hideLoading(); + } } -/** 删除DIY模板 */ +/** 删除 DIY 模板 */ async function handleDelete(row: MallDiyTemplateApi.DiyTemplate) { - await deleteDiyTemplate(row.id as number); - handleRefresh(); + const hideLoading = message.loading({ + content: $t('ui.actionMessage.deleting', [row.name]), + duration: 0, + }); + try { + await deleteDiyTemplate(row.id as number); + message.success($t('ui.actionMessage.deleteSuccess', [row.name])); + handleRefresh(); + } finally { + hideLoading(); + } } const [Grid, gridApi] = useVbenVxeGrid({ @@ -142,14 +154,14 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, { label: '使用', - type: 'link' as const, + type: 'link', auth: ['promotion:diy-template:use'], ifShow: !row.used, onClick: handleUse.bind(null, row), }, { label: $t('common.delete'), - type: 'link' as const, + type: 'link', danger: true, icon: ACTION_ICON.DELETE, auth: ['promotion:diy-template:delete'], diff --git a/apps/web-antd/src/views/mall/promotion/diy/template/modules/form.vue b/apps/web-antd/src/views/mall/promotion/diy/template/modules/form.vue index c262b70c7..339c949e9 100644 --- a/apps/web-antd/src/views/mall/promotion/diy/template/modules/form.vue +++ b/apps/web-antd/src/views/mall/promotion/diy/template/modules/form.vue @@ -16,9 +16,7 @@ import { $t } from '#/locales'; import { useFormSchema } from '../data'; -/** 提交表单 */ const emit = defineEmits(['success']); - const formData = ref(); const getTitle = computed(() => { return formData.value?.id @@ -47,15 +45,6 @@ const [Modal, modalApi] = useVbenModal({ modalApi.lock(); // 提交表单 const data = (await formApi.getValues()) as MallDiyTemplateApi.DiyTemplate; - - // 确保必要的默认值 - if (!data.previewPicUrls) { - data.previewPicUrls = []; - } - if (data.used === undefined) { - data.used = false; - } - try { await (formData.value?.id ? updateDiyTemplate(data) @@ -91,7 +80,7 @@ const [Modal, modalApi] = useVbenModal({ diff --git a/apps/web-ele/src/views/mall/promotion/diy/template/index.vue b/apps/web-ele/src/views/mall/promotion/diy/template/index.vue index 456b50d13..df68ff883 100644 --- a/apps/web-ele/src/views/mall/promotion/diy/template/index.vue +++ b/apps/web-ele/src/views/mall/promotion/diy/template/index.vue @@ -51,7 +51,6 @@ function handleDecorate(row: MallDiyTemplateApi.DiyTemplate) { /** 使用模板 */ async function handleUse(row: MallDiyTemplateApi.DiyTemplate) { await confirm(`是否使用模板"${row.name}"?`); - const loadingInstance = ElLoading.service({ text: `正在使用模板"${row.name}"...`, }); From db1b3be27a68cb941bc312fc73d75eebdc8ac2ee Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 25 Oct 2025 23:18:55 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat=EF=BC=9A=E3=80=90antd=E3=80=91?= =?UTF-8?q?=E3=80=90mall=E3=80=91diy-editor=20=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=EF=BC=88=E6=9A=82=E6=97=B6=E4=B8=8D=E5=8F=AF=E7=94=A8=EF=BC=8C?= =?UTF-8?q?=E4=BF=9D=E8=AF=81=E7=95=8C=E9=9D=A2=E5=85=88=E6=9C=89=E3=80=82?= =?UTF-8?q?=E3=80=82=E3=80=82=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/package.json | 3 +- .../src/assets/imgs/diy/app-nav-bar-mp.png | Bin 0 -> 3595 bytes .../src/assets/imgs/diy/statusBar.png | Bin 0 -> 8917 bytes .../components/product-category-select.vue | 68 ++ .../app-link-input/app-link-select-dialog.vue | 231 ++++++ .../components/app-link-input/data.ts | 220 ++++++ .../components/app-link-input/index.vue | 47 ++ .../components/color-input/index.vue | 36 + .../component-container-property.vue | 185 +++++ .../components/component-container.vue | 268 +++++++ .../components/component-library.vue | 219 ++++++ .../components/mobile/Carousel/config.ts | 61 ++ .../components/mobile/Carousel/index.vue | 48 ++ .../components/mobile/Carousel/property.vue | 121 ++++ .../components/mobile/Divider/config.ts | 29 + .../components/mobile/Divider/index.vue | 29 + .../components/mobile/Divider/property.vue | 6 + .../components/mobile/Popover/config.ts | 26 + .../components/mobile/Popover/index.vue | 43 ++ .../components/mobile/Popover/property.vue | 4 + .../mobile/coupon-card/component.tsx | 4 + .../components/mobile/coupon-card/config.ts | 50 ++ .../coupon-card/coupon-discount-desc.tsx | 34 + .../mobile/coupon-card/coupon-discount.tsx | 34 + .../mobile/coupon-card/coupon-validTerm.tsx | 28 + .../components/mobile/coupon-card/index.vue | 161 +++++ .../mobile/coupon-card/property.vue | 7 + .../mobile/floating-action-button/config.ts | 36 + .../mobile/floating-action-button/index.vue | 92 +++ .../floating-action-button/property.vue | 4 + .../hot-zone-edit-dialog/controller.ts | 175 +++++ .../components/hot-zone-edit-dialog/index.vue | 11 + .../components/mobile/hot-zone/config.ts | 46 ++ .../components/mobile/hot-zone/index.vue | 46 ++ .../components/mobile/hot-zone/property.vue | 80 +++ .../components/mobile/image-bar/config.ts | 30 + .../components/mobile/image-bar/index.vue | 30 + .../components/mobile/image-bar/property.vue | 40 ++ .../diy-editor/components/mobile/index.ts | 69 ++ .../components/mobile/magic-cube/config.ts | 56 ++ .../components/mobile/magic-cube/index.vue | 83 +++ .../components/mobile/magic-cube/property.vue | 9 + .../components/mobile/menu-grid/config.ts | 83 +++ .../components/mobile/menu-grid/index.vue | 46 ++ .../components/mobile/menu-grid/property.vue | 90 +++ .../components/mobile/menu-list/config.ts | 52 ++ .../components/mobile/menu-list/index.vue | 39 + .../components/mobile/menu-list/property.vue | 7 + .../components/mobile/menu-swiper/config.ts | 70 ++ .../components/mobile/menu-swiper/index.vue | 136 ++++ .../mobile/menu-swiper/property.vue | 6 + .../components/cell-property.vue | 8 + .../mobile/navigation-bar/config.ts | 82 +++ .../mobile/navigation-bar/index.vue | 112 +++ .../mobile/navigation-bar/property.vue | 117 +++ .../components/mobile/notice-bar/config.ts | 49 ++ .../components/mobile/notice-bar/index.vue | 37 + .../components/mobile/notice-bar/property.vue | 7 + .../components/mobile/page-config/config.ts | 23 + .../mobile/page-config/property.vue | 45 ++ .../components/mobile/product-card/config.ts | 100 +++ .../components/mobile/product-card/index.vue | 189 +++++ .../mobile/product-card/property.vue | 6 + .../components/mobile/product-list/config.ts | 67 ++ .../components/mobile/product-list/index.vue | 149 ++++ .../mobile/product-list/property.vue | 112 +++ .../mobile/promotion-article/config.ts | 28 + .../mobile/promotion-article/index.vue | 33 + .../mobile/promotion-article/property.vue | 67 ++ .../mobile/promotion-combination/config.ts | 99 +++ .../mobile/promotion-combination/index.vue | 232 ++++++ .../mobile/promotion-combination/property.vue | 181 +++++ .../mobile/promotion-point/config.ts | 99 +++ .../mobile/promotion-point/index.vue | 233 ++++++ .../mobile/promotion-point/property.vue | 6 + .../mobile/promotion-seckill/config.ts | 99 +++ .../mobile/promotion-seckill/index.vue | 228 ++++++ .../mobile/promotion-seckill/property.vue | 11 + .../components/mobile/search-bar/config.ts | 46 ++ .../components/mobile/search-bar/index.vue | 83 +++ .../components/mobile/search-bar/property.vue | 9 + .../components/mobile/tab-bar/config.ts | 172 +++++ .../components/mobile/tab-bar/index.vue | 79 +++ .../components/mobile/tab-bar/property.vue | 121 ++++ .../components/mobile/title-bar/config.ts | 76 ++ .../components/mobile/title-bar/index.vue | 87 +++ .../components/mobile/title-bar/property.vue | 6 + .../components/mobile/user-card/config.ts | 24 + .../components/mobile/user-card/index.vue | 34 + .../components/mobile/user-card/property.vue | 20 + .../components/mobile/user-coupon/config.ts | 26 + .../components/mobile/user-coupon/index.vue | 16 + .../mobile/user-coupon/property.vue | 20 + .../components/mobile/user-order/config.ts | 26 + .../components/mobile/user-order/index.vue | 16 + .../components/mobile/user-order/property.vue | 20 + .../components/mobile/user-wallet/config.ts | 26 + .../components/mobile/user-wallet/index.vue | 16 + .../mobile/user-wallet/property.vue | 20 + .../components/mobile/video-player/config.ts | 40 ++ .../components/mobile/video-player/index.vue | 35 + .../mobile/video-player/property.vue | 58 ++ .../promotion/components/diy-editor/index.vue | 667 +++++++++++++++++- .../promotion/components/diy-editor/util.ts | 10 +- .../promotion/components/draggable/index.vue | 99 +++ .../views/mall/promotion/components/index.ts | 10 +- .../components/input-with-color/index.vue | 31 + .../components/magic-cube-editor/index.vue | 302 ++++++++ .../components/magic-cube-editor/util.ts | 72 ++ .../promotion/components/spu-and-sku-list.vue | 238 ------- .../promotion/components/spu-sku-select.vue | 316 --------- .../views/mall/promotion/components/types.ts | 11 - .../vertical-button-group/index.vue | 15 + 113 files changed, 7955 insertions(+), 609 deletions(-) create mode 100644 apps/web-antd/src/assets/imgs/diy/app-nav-bar-mp.png create mode 100644 apps/web-antd/src/assets/imgs/diy/statusBar.png create mode 100644 apps/web-antd/src/views/mall/product/category/components/product-category-select.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/app-link-input/app-link-select-dialog.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/app-link-input/data.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/app-link-input/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/color-input/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-library.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Popover/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Popover/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Popover/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/component.tsx create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/coupon-discount-desc.tsx create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/coupon-discount.tsx create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/coupon-validTerm.tsx create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/floating-action-button/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/floating-action-button/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/floating-action-button/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/controller.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/components/hot-zone-edit-dialog/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/index.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-grid/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-grid/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-grid/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-swiper/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-swiper/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-swiper/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/navigation-bar/components/cell-property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/navigation-bar/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/navigation-bar/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/navigation-bar/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/page-config/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/page-config/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/product-card/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/product-card/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/product-card/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/product-list/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/product-list/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/product-list/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-article/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-article/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-article/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-combination/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-combination/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-combination/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-point/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-point/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-point/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-seckill/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-seckill/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/promotion-seckill/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/search-bar/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/search-bar/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/search-bar/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/tab-bar/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/tab-bar/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/tab-bar/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/title-bar/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/title-bar/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/title-bar/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-card/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-card/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-card/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-coupon/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-coupon/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-coupon/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-order/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-order/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-order/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-wallet/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-wallet/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/user-wallet/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/video-player/config.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/video-player/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/video-player/property.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/draggable/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/input-with-color/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/magic-cube-editor/index.vue create mode 100644 apps/web-antd/src/views/mall/promotion/components/magic-cube-editor/util.ts delete mode 100644 apps/web-antd/src/views/mall/promotion/components/spu-and-sku-list.vue delete mode 100644 apps/web-antd/src/views/mall/promotion/components/spu-sku-select.vue delete mode 100644 apps/web-antd/src/views/mall/promotion/components/types.ts create mode 100644 apps/web-antd/src/views/mall/promotion/components/vertical-button-group/index.vue diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json index c2237dda6..dd8b2435c 100644 --- a/apps/web-antd/package.json +++ b/apps/web-antd/package.json @@ -61,6 +61,7 @@ "vue": "catalog:", "vue-dompurify-html": "catalog:", "vue-router": "catalog:", - "vue3-signature": "catalog:" + "vue3-signature": "catalog:", + "vuedraggable": "catalog:" } } diff --git a/apps/web-antd/src/assets/imgs/diy/app-nav-bar-mp.png b/apps/web-antd/src/assets/imgs/diy/app-nav-bar-mp.png new file mode 100644 index 0000000000000000000000000000000000000000..c982804c7287c904468dad6252fd393c6cbd271f GIT binary patch literal 3595 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 Y)KD1lT9stKL4Yr5ae1*HB8Gwg2lSJ;0RR91 literal 0 HcmV?d00001 diff --git a/apps/web-antd/src/views/mall/product/category/components/product-category-select.vue b/apps/web-antd/src/views/mall/product/category/components/product-category-select.vue new file mode 100644 index 000000000..b54c6f0d2 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/category/components/product-category-select.vue @@ -0,0 +1,68 @@ + + diff --git a/apps/web-antd/src/views/mall/promotion/components/app-link-input/app-link-select-dialog.vue b/apps/web-antd/src/views/mall/promotion/components/app-link-input/app-link-select-dialog.vue new file mode 100644 index 000000000..4102d7063 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/app-link-input/app-link-select-dialog.vue @@ -0,0 +1,231 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/app-link-input/data.ts b/apps/web-antd/src/views/mall/promotion/components/app-link-input/data.ts new file mode 100644 index 000000000..3eb3db71f --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/app-link-input/data.ts @@ -0,0 +1,220 @@ +/** 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-antd/src/views/mall/promotion/components/app-link-input/index.vue b/apps/web-antd/src/views/mall/promotion/components/app-link-input/index.vue new file mode 100644 index 000000000..368ca6500 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/app-link-input/index.vue @@ -0,0 +1,47 @@ + + diff --git a/apps/web-antd/src/views/mall/promotion/components/color-input/index.vue b/apps/web-antd/src/views/mall/promotion/components/color-input/index.vue new file mode 100644 index 000000000..96c9b3b5f --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/color-input/index.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue new file mode 100644 index 000000000..700faa796 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue @@ -0,0 +1,185 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue new file mode 100644 index 000000000..4cfae8d55 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue @@ -0,0 +1,268 @@ + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-library.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-library.vue new file mode 100644 index 000000000..4ae265286 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-library.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/config.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/config.ts new file mode 100644 index 000000000..514f45e89 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/config.ts @@ -0,0 +1,61 @@ +import type { + ComponentStyle, + DiyComponent, +} from '../../../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-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/index.vue new file mode 100644 index 000000000..b79872625 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/index.vue @@ -0,0 +1,48 @@ + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/property.vue new file mode 100644 index 000000000..6437898bd --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/property.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/config.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/config.ts new file mode 100644 index 000000000..17e5a79bf --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/config.ts @@ -0,0 +1,29 @@ +import type { DiyComponent } from '../../../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-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/index.vue new file mode 100644 index 000000000..1736db389 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/index.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/property.vue new file mode 100644 index 000000000..d683e0b5c --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Divider/property.vue @@ -0,0 +1,6 @@ + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Popover/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Popover/property.vue new file mode 100644 index 000000000..de599eb63 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Popover/property.vue @@ -0,0 +1,4 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/property.vue new file mode 100644 index 000000000..19f2f7bc2 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/coupon-card/property.vue @@ -0,0 +1,7 @@ + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/floating-action-button/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/floating-action-button/property.vue new file mode 100644 index 000000000..bf3c071d8 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/floating-action-button/property.vue @@ -0,0 +1,4 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/property.vue new file mode 100644 index 000000000..b0b9596e4 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/hot-zone/property.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/config.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/config.ts new file mode 100644 index 000000000..1d2c4ac01 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/config.ts @@ -0,0 +1,30 @@ +import type { + ComponentStyle, + DiyComponent, +} from '../../../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-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/index.vue new file mode 100644 index 000000000..201831030 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/index.vue @@ -0,0 +1,30 @@ + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/property.vue new file mode 100644 index 000000000..b32213318 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/image-bar/property.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/index.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/index.ts new file mode 100644 index 000000000..454e06a0b --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/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-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/config.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/config.ts new file mode 100644 index 000000000..ff9cbb8f0 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/config.ts @@ -0,0 +1,56 @@ +import type { + ComponentStyle, + DiyComponent, +} from '../../../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-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/index.vue new file mode 100644 index 000000000..d2c6d6779 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/index.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/property.vue new file mode 100644 index 000000000..ce5578a0c --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/magic-cube/property.vue @@ -0,0 +1,9 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-grid/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-grid/property.vue new file mode 100644 index 000000000..45a92daec --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-grid/property.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/config.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/config.ts new file mode 100644 index 000000000..389982595 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/config.ts @@ -0,0 +1,52 @@ +import type { + ComponentStyle, + DiyComponent, +} from '../../../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-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/index.vue new file mode 100644 index 000000000..cfe38a9ae --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/index.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/property.vue new file mode 100644 index 000000000..f2de06c79 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-list/property.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-swiper/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-swiper/property.vue new file mode 100644 index 000000000..201db0f29 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/menu-swiper/property.vue @@ -0,0 +1,6 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/navigation-bar/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/navigation-bar/property.vue new file mode 100644 index 000000000..ce3e3f698 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/navigation-bar/property.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/config.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/config.ts new file mode 100644 index 000000000..9eb1ca8e1 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/config.ts @@ -0,0 +1,49 @@ +import type { + ComponentStyle, + DiyComponent, +} from '../../../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-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/index.vue new file mode 100644 index 000000000..a087c6ef8 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/index.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/property.vue new file mode 100644 index 000000000..10c482958 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/notice-bar/property.vue @@ -0,0 +1,7 @@ + + +