diff --git a/.vscode/extensions.json b/.vscode/extensions.json index e8dc9ed9b..c67d983e2 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-antd/src/api/erp/product/category/index.ts b/apps/web-antd/src/api/erp/product/category/index.ts index b16a91e3a..74e5465c1 100644 --- a/apps/web-antd/src/api/erp/product/category/index.ts +++ b/apps/web-antd/src/api/erp/product/category/index.ts @@ -4,11 +4,12 @@ export namespace ErpProductCategoryApi { /** ERP 产品分类信息 */ export interface ProductCategory { id?: number; // 分类编号 - parentId: number; // 父分类编号 + parentId?: number; // 父分类编号 name: string; // 分类名称 - code: string; // 分类编码 - sort: number; // 分类排序 - status: number; // 开启状态 + code?: string; // 分类编码 + sort?: number; // 分类排序 + status?: number; // 开启状态 + children?: ProductCategory[]; // 子分类 } } diff --git a/apps/web-antd/src/api/erp/stock/out/index.ts b/apps/web-antd/src/api/erp/stock/out/index.ts index 2224e2ddb..a3873f948 100644 --- a/apps/web-antd/src/api/erp/stock/out/index.ts +++ b/apps/web-antd/src/api/erp/stock/out/index.ts @@ -2,7 +2,7 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; -namespace ErpStockOutApi { +export namespace ErpStockOutApi { /** 其它出库单信息 */ export interface StockOut { id?: number; // 出库编号 @@ -13,6 +13,24 @@ namespace ErpStockOutApi { totalPrice: number; // 合计金额,单位:元 status: number; // 状态 remark: string; // 备注 + fileUrl?: string; // 附件 + items?: StockOutItem[]; // 出库产品清单 + } + + /** 其它出库单产品信息 */ + export interface StockOutItem { + id?: number; // 编号 + warehouseId?: number; // 仓库编号 + productId?: number; // 产品编号 + productName?: string; // 产品名称 + productUnitId?: number; // 产品单位编号 + productUnitName?: string; // 产品单位名称 + productBarCode?: string; // 产品条码 + count: number; // 数量 + productPrice: number; // 产品单价 + totalPrice: number; // 总价 + stockCount?: number; // 库存数量 + remark?: string; // 备注 } /** 其它出库单分页查询参数 */ diff --git a/apps/web-antd/src/api/infra/file-config/index.ts b/apps/web-antd/src/api/infra/file-config/index.ts index 20a0ab3fa..1a2fb7707 100644 --- a/apps/web-antd/src/api/infra/file-config/index.ts +++ b/apps/web-antd/src/api/infra/file-config/index.ts @@ -16,6 +16,7 @@ export namespace InfraFileConfigApi { accessKey?: string; accessSecret?: string; pathStyle?: boolean; + enablePublicAccess?: boolean; domain: string; } diff --git a/apps/web-antd/src/components/Tinyflow/index.ts b/apps/web-antd/src/components/Tinyflow/index.ts index 33db19a5e..e014e38cc 100644 --- a/apps/web-antd/src/components/Tinyflow/index.ts +++ b/apps/web-antd/src/components/Tinyflow/index.ts @@ -1,2 +1,2 @@ -export { default as Tinyflow } from './tinyflow.vue'; +export { default as Tinyflow } from './Tinyflow.vue'; export * from './ui/typing'; diff --git a/apps/web-antd/src/views/ai/workflow/form/modules/workflow-design.vue b/apps/web-antd/src/views/ai/workflow/form/modules/workflow-design.vue index 6659b80be..fb4ec8cf2 100644 --- a/apps/web-antd/src/views/ai/workflow/form/modules/workflow-design.vue +++ b/apps/web-antd/src/views/ai/workflow/form/modules/workflow-design.vue @@ -10,7 +10,7 @@ import { isNumber } from '@vben/utils'; import { Button, Input, Select } from 'ant-design-vue'; import { testWorkflow } from '#/api/ai/workflow'; -import { Tinyflow } from '#/components/tinyflow'; +import { Tinyflow } from '#/components/Tinyflow'; defineProps<{ provider: any; diff --git a/apps/web-antd/src/views/erp/product/category/data.ts b/apps/web-antd/src/views/erp/product/category/data.ts new file mode 100644 index 000000000..9d95075cb --- /dev/null +++ b/apps/web-antd/src/views/erp/product/category/data.ts @@ -0,0 +1,125 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { ErpProductCategoryApi } from '#/api/erp/product/category'; + +import { handleTree } from '@vben/utils'; + +import { z } from '#/adapter/form'; +import { getProductCategoryList } from '#/api/erp/product/category'; +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'parentId', + label: '上级分类', + component: 'ApiTreeSelect', + componentProps: { + allowClear: true, + api: async () => { + const data = await getProductCategoryList(); + data.unshift({ + id: 0, + name: '顶级分类', + }); + return handleTree(data); + }, + labelField: 'name', + valueField: 'id', + childrenField: 'children', + placeholder: '请选择上级分类', + treeDefaultExpandAll: true, + }, + rules: 'selectRequired', + }, + { + fieldName: 'name', + label: '分类名称', + component: 'Input', + componentProps: { + placeholder: '请输入分类名称', + }, + rules: 'required', + }, + { + fieldName: 'code', + label: '分类编码', + component: 'Input', + componentProps: { + placeholder: '请输入分类编码', + }, + rules: z.string().regex(/^[A-Z]+$/, '分类编码必须为大写字母'), + }, + { + fieldName: 'sort', + label: '显示顺序', + component: 'InputNumber', + componentProps: { + min: 0, + controlsPosition: 'right', + placeholder: '请输入显示顺序', + }, + rules: 'required', + }, + + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '分类名称', + align: 'left', + treeNode: true, + }, + { + field: 'code', + title: '分类编码', + }, + { + field: 'sort', + title: '显示顺序', + }, + { + field: 'status', + title: '分类状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 220, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/erp/product/category/index.vue b/apps/web-antd/src/views/erp/product/category/index.vue index 47c5b65b9..01fdede9e 100644 --- a/apps/web-antd/src/views/erp/product/category/index.vue +++ b/apps/web-antd/src/views/erp/product/category/index.vue @@ -1,34 +1,166 @@ diff --git a/apps/web-antd/src/views/erp/product/category/modules/form.vue b/apps/web-antd/src/views/erp/product/category/modules/form.vue new file mode 100644 index 000000000..ad6ffa89b --- /dev/null +++ b/apps/web-antd/src/views/erp/product/category/modules/form.vue @@ -0,0 +1,92 @@ + + + diff --git a/apps/web-antd/src/views/erp/product/product/data.ts b/apps/web-antd/src/views/erp/product/product/data.ts new file mode 100644 index 000000000..8b44beef8 --- /dev/null +++ b/apps/web-antd/src/views/erp/product/product/data.ts @@ -0,0 +1,220 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { handleTree } from '@vben/utils'; + +import { z } from '#/adapter/form'; +import { getProductCategorySimpleList } from '#/api/erp/product/category'; +import { getProductUnitSimpleList } from '#/api/erp/product/unit'; +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'name', + label: '名称', + rules: 'required', + componentProps: { + placeholder: '请输入名称', + }, + }, + { + fieldName: 'barCode', + label: '条码', + component: 'Input', + rules: 'required', + componentProps: { + placeholder: '请输入条码', + }, + }, + { + fieldName: 'categoryId', + label: '分类', + component: 'ApiTreeSelect', + componentProps: { + api: async () => { + const data = await getProductCategorySimpleList(); + return handleTree(data); + }, + + labelField: 'name', + valueField: 'id', + childrenField: 'children', + placeholder: '请选择分类', + treeDefaultExpandAll: true, + }, + rules: 'required', + }, + { + fieldName: 'unitId', + label: '单位', + component: 'ApiSelect', + componentProps: { + api: getProductUnitSimpleList, + labelField: 'name', + valueField: 'id', + placeholder: '请选择单位', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'standard', + label: '规格', + component: 'Input', + componentProps: { + placeholder: '请输入规格', + }, + }, + { + fieldName: 'expiryDay', + label: '保质期天数', + component: 'InputNumber', + componentProps: { + placeholder: '请输入保质期天数', + }, + }, + { + fieldName: 'weight', + label: '重量(kg)', + component: 'InputNumber', + componentProps: { + placeholder: '请输入重量(kg)', + }, + }, + { + fieldName: 'purchasePrice', + label: '采购价格', + component: 'InputNumber', + componentProps: { + placeholder: '请输入采购价格,单位:元', + }, + }, + { + fieldName: 'salePrice', + label: '销售价格', + component: 'InputNumber', + componentProps: { + placeholder: '请输入销售价格,单位:元', + }, + }, + { + fieldName: 'minPrice', + label: '最低价格', + component: 'InputNumber', + componentProps: { + placeholder: '请输入最低价格,单位:元', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名称', + component: 'Input', + }, + { + fieldName: 'categoryId', + label: '分类', + component: 'ApiTreeSelect', + componentProps: { + api: async () => { + const data = await getProductCategorySimpleList(); + return handleTree(data); + }, + + labelField: 'name', + valueField: 'id', + childrenField: 'children', + placeholder: '请选择分类', + treeDefaultExpandAll: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'barCode', + title: '条码', + }, + { + field: 'name', + title: '名称', + }, + { + field: 'standard', + title: '规格', + }, + { + field: 'categoryName', + title: '分类', + }, + { + field: 'unitName', + title: '单位', + }, + { + field: 'purchasePrice', + title: '采购价格', + }, + { + field: 'salePrice', + title: '销售价格', + }, + { + field: 'minPrice', + title: '最低价格', + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/erp/product/product/index.vue b/apps/web-antd/src/views/erp/product/product/index.vue index d52ab9c92..1748c0d09 100644 --- a/apps/web-antd/src/views/erp/product/product/index.vue +++ b/apps/web-antd/src/views/erp/product/product/index.vue @@ -1,34 +1,152 @@ diff --git a/apps/web-antd/src/views/erp/product/product/modules/form.vue b/apps/web-antd/src/views/erp/product/product/modules/form.vue new file mode 100644 index 000000000..cbaf8072c --- /dev/null +++ b/apps/web-antd/src/views/erp/product/product/modules/form.vue @@ -0,0 +1,86 @@ + + + diff --git a/apps/web-antd/src/views/erp/product/unit/data.ts b/apps/web-antd/src/views/erp/product/unit/data.ts new file mode 100644 index 000000000..7de094158 --- /dev/null +++ b/apps/web-antd/src/views/erp/product/unit/data.ts @@ -0,0 +1,89 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'name', + label: '单位名称', + rules: 'required', + }, + { + fieldName: 'status', + label: '单位状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '单位名称', + component: 'Input', + }, + { + fieldName: 'status', + label: '单位状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '单位编号', + }, + { + field: 'name', + title: '单位名称', + }, + { + field: 'status', + title: '单位状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/erp/product/unit/index.vue b/apps/web-antd/src/views/erp/product/unit/index.vue index 70e5ebd61..1386c131f 100644 --- a/apps/web-antd/src/views/erp/product/unit/index.vue +++ b/apps/web-antd/src/views/erp/product/unit/index.vue @@ -1,34 +1,152 @@ diff --git a/apps/web-antd/src/views/erp/product/unit/modules/form.vue b/apps/web-antd/src/views/erp/product/unit/modules/form.vue new file mode 100644 index 000000000..4871e227c --- /dev/null +++ b/apps/web-antd/src/views/erp/product/unit/modules/form.vue @@ -0,0 +1,88 @@ + + + diff --git a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue index 828acbe15..7805c0b22 100644 --- a/apps/web-antd/src/views/erp/purchase/order/modules/form.vue +++ b/apps/web-antd/src/views/erp/purchase/order/modules/form.vue @@ -114,7 +114,11 @@ const [Modal, modalApi] = useVbenModal({ // 提交表单 const data = (await formApi.getValues()) as ErpPurchaseOrderApi.PurchaseOrder; - data.items = formData.value?.items; + data.items = formData.value?.items?.map((item) => ({ + ...item, + // 解决新增采购订单报错 + id: undefined, + })); // 将文件数组转换为字符串 if (data.fileUrl && Array.isArray(data.fileUrl)) { data.fileUrl = data.fileUrl.length > 0 ? data.fileUrl[0] : ''; diff --git a/apps/web-antd/src/views/erp/stock/in/modules/form.vue b/apps/web-antd/src/views/erp/stock/in/modules/form.vue index fffca0978..a18f6c1ce 100644 --- a/apps/web-antd/src/views/erp/stock/in/modules/form.vue +++ b/apps/web-antd/src/views/erp/stock/in/modules/form.vue @@ -88,7 +88,10 @@ const [Modal, modalApi] = useVbenModal({ modalApi.lock(); // 提交表单 const data = (await formApi.getValues()) as ErpStockInApi.StockIn; - data.items = formData.value?.items; + data.items = formData.value?.items?.map((item) => ({ + ...item, + id: undefined, + })); // 将文件数组转换为字符串 if (data.fileUrl && Array.isArray(data.fileUrl)) { data.fileUrl = data.fileUrl.length > 0 ? data.fileUrl[0] : ''; diff --git a/apps/web-antd/src/views/erp/stock/out/data.ts b/apps/web-antd/src/views/erp/stock/out/data.ts new file mode 100644 index 000000000..ca2095c34 --- /dev/null +++ b/apps/web-antd/src/views/erp/stock/out/data.ts @@ -0,0 +1,329 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { createRequiredValidation } from '#/adapter/vxe-table'; +import { getProductSimpleList } from '#/api/erp/product/product'; +import { getCustomerSimpleList } from '#/api/erp/sale/customer'; +import { getSimpleUserList } from '#/api/system/user'; +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 表单的配置项 */ +export function useFormSchema(formType: string): VbenFormSchema[] { + return [ + { + component: 'Input', + componentProps: { + style: { display: 'none' }, + }, + fieldName: 'id', + label: 'ID', + hideLabel: true, + formItemClass: 'hidden', + }, + { + component: 'Input', + componentProps: { + placeholder: '系统自动生成', + disabled: true, + }, + fieldName: 'no', + label: '出库单号', + disabled: formType === 'detail', + }, + { + component: 'DatePicker', + componentProps: { + placeholder: '选择出库时间', + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + style: { width: '100%' }, + }, + disabled: formType === 'detail', + fieldName: 'outTime', + label: '出库时间', + rules: 'required', + }, + { + component: 'ApiSelect', + componentProps: { + placeholder: '请选择客户', + allowClear: true, + showSearch: true, + api: getCustomerSimpleList, + fieldNames: { + label: 'name', + value: 'id', + }, + }, + disabled: formType === 'detail', + fieldName: 'customerId', + label: '客户', + }, + + { + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + autoSize: { minRows: 2, maxRows: 4 }, + class: 'w-full', + }, + disabled: formType === 'detail', + fieldName: 'remark', + label: '备注', + formItemClass: 'col-span-3', + }, + { + component: 'FileUpload', + disabled: formType === 'detail', + componentProps: { + maxNumber: 1, + maxSize: 10, + accept: [ + 'pdf', + 'doc', + 'docx', + 'xls', + 'xlsx', + 'txt', + 'jpg', + 'jpeg', + 'png', + ], + showDescription: true, + }, + fieldName: 'fileUrl', + label: '附件', + formItemClass: 'col-span-3', + }, + { + fieldName: 'product', + disabled: formType === 'detail', + label: '产品清单', + component: 'Input', + formItemClass: 'col-span-3', + }, + ]; +} + +/** 出库产品清单表格列定义 */ +export function useStockInItemTableColumns( + isValidating?: any, +): VxeTableGridOptions['columns'] { + return [ + { type: 'seq', title: '序号', minWidth: 50, fixed: 'left' }, + { + field: 'warehouseId', + title: '仓库名称', + minWidth: 150, + slots: { default: 'warehouseId' }, + className: createRequiredValidation(isValidating, 'warehouseId'), + }, + { + field: 'productId', + title: '产品名称', + minWidth: 200, + slots: { default: 'productId' }, + className: createRequiredValidation(isValidating, 'productId'), + }, + { + field: 'stockCount', + title: '库存', + minWidth: 100, + }, + { + field: 'productBarCode', + title: '条码', + minWidth: 120, + }, + { + field: 'productUnitName', + title: '单位', + minWidth: 80, + }, + { + field: 'count', + title: '数量', + minWidth: 120, + slots: { default: 'count' }, + className: createRequiredValidation(isValidating, 'count'), + }, + { + field: 'productPrice', + title: '产品单价', + minWidth: 120, + slots: { default: 'productPrice' }, + }, + { + field: 'totalPrice', + title: '金额', + minWidth: 120, + formatter: 'formatAmount2', + }, + { + field: 'remark', + title: '备注', + minWidth: 150, + slots: { default: 'remark' }, + }, + { + title: '操作', + width: 50, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'no', + label: '出库单号', + component: 'Input', + componentProps: { + placeholder: '请输入出库单号', + allowClear: true, + }, + }, + { + fieldName: 'productId', + label: '产品', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择产品', + allowClear: true, + showSearch: true, + api: getProductSimpleList, + labelField: 'name', + valueField: 'id', + filterOption: false, + }, + }, + { + fieldName: 'outTime', + label: '出库时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始日期', '结束日期'], + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + }, + }, + { + fieldName: 'customerId', + label: '客户', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择客户', + allowClear: true, + showSearch: true, + api: getCustomerSimpleList, + labelField: 'name', + valueField: 'id', + filterOption: false, + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + allowClear: true, + options: getDictOptions(DICT_TYPE.ERP_AUDIT_STATUS, 'number'), + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Input', + componentProps: { + placeholder: '请输入备注', + allowClear: true, + }, + }, + { + fieldName: 'creator', + label: '创建人', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择创建人', + allowClear: true, + showSearch: true, + api: getSimpleUserList, + labelField: 'nickname', + valueField: 'id', + filterOption: false, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + type: 'checkbox', + width: 50, + fixed: 'left', + }, + { + field: 'no', + title: '出库单号', + minWidth: 180, + }, + { + field: 'productNames', + title: '产品信息', + minWidth: 200, + showOverflow: 'tooltip', + }, + { + field: 'customerName', + title: '客户', + minWidth: 120, + }, + { + field: 'outTime', + title: '出库时间', + minWidth: 180, + cellRender: { + name: 'CellDateTime', + }, + }, + { + field: 'creatorName', + title: '创建人', + minWidth: 100, + }, + { + field: 'totalCount', + title: '数量', + minWidth: 100, + }, + { + field: 'totalPrice', + title: '价格', + minWidth: 100, + }, + { + field: 'status', + title: '状态', + minWidth: 90, + fixed: 'right', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.ERP_AUDIT_STATUS }, + }, + }, + { + title: '操作', + width: 300, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/erp/stock/out/index.vue b/apps/web-antd/src/views/erp/stock/out/index.vue index afbf0c8a5..b42896b37 100644 --- a/apps/web-antd/src/views/erp/stock/out/index.vue +++ b/apps/web-antd/src/views/erp/stock/out/index.vue @@ -1,34 +1,219 @@ diff --git a/apps/web-antd/src/views/erp/stock/out/modules/form.vue b/apps/web-antd/src/views/erp/stock/out/modules/form.vue new file mode 100644 index 000000000..7e8a84031 --- /dev/null +++ b/apps/web-antd/src/views/erp/stock/out/modules/form.vue @@ -0,0 +1,196 @@ + + + diff --git a/apps/web-antd/src/views/erp/stock/out/modules/stock-out-item-form.vue b/apps/web-antd/src/views/erp/stock/out/modules/stock-out-item-form.vue new file mode 100644 index 000000000..14ff4fe13 --- /dev/null +++ b/apps/web-antd/src/views/erp/stock/out/modules/stock-out-item-form.vue @@ -0,0 +1,367 @@ + + + + + diff --git a/apps/web-antd/src/views/infra/apiAccessLog/data.ts b/apps/web-antd/src/views/infra/apiAccessLog/data.ts index 42164ef9d..e9cc48651 100644 --- a/apps/web-antd/src/views/infra/apiAccessLog/data.ts +++ b/apps/web-antd/src/views/infra/apiAccessLog/data.ts @@ -5,7 +5,7 @@ import type { DescriptionItemSchema } from '#/components/description'; import { h } from 'vue'; import { JsonViewer } from '@vben/common-ui'; -import { formatDateTime, isObject } from '@vben/utils'; +import { formatDateTime } from '@vben/utils'; import { DictTag } from '#/components/dict-tag'; import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; @@ -192,13 +192,13 @@ export function useDetailSchema(): DescriptionItemSchema[] { field: 'requestParams', label: '请求参数', content: (data) => { - if (isObject(data.requestParams)) { + if (data.requestParams) { return h(JsonViewer, { - value: data.requestParams, + value: JSON.parse(data.requestParams), previewMode: true, }); } - return data.requestParams; + return ''; }, }, { diff --git a/apps/web-antd/src/views/infra/apiErrorLog/data.ts b/apps/web-antd/src/views/infra/apiErrorLog/data.ts index d5a4e9031..0d39dfe40 100644 --- a/apps/web-antd/src/views/infra/apiErrorLog/data.ts +++ b/apps/web-antd/src/views/infra/apiErrorLog/data.ts @@ -5,7 +5,9 @@ import type { DescriptionItemSchema } from '#/components/description'; import { h } from 'vue'; import { JsonViewer } from '@vben/common-ui'; -import { formatDateTime, isObject } from '@vben/utils'; +import { formatDateTime } from '@vben/utils'; + +import { Textarea } from 'ant-design-vue'; import { DictTag } from '#/components/dict-tag'; import { @@ -177,13 +179,13 @@ export function useDetailSchema(): DescriptionItemSchema[] { field: 'requestParams', label: '请求参数', content: (data) => { - if (isObject(data.requestParams)) { + if (data.requestParams) { return h(JsonViewer, { - value: data.requestParams, + value: JSON.parse(data.requestParams), previewMode: true, }); } - return data.requestParams; + return ''; }, }, { @@ -201,13 +203,10 @@ export function useDetailSchema(): DescriptionItemSchema[] { field: 'exceptionStackTrace', label: '异常堆栈', content: (data) => { - if (isObject(data.exceptionStackTrace)) { - return h(JsonViewer, { - value: data.exceptionStackTrace, - previewMode: true, - }); - } - return data.exceptionStackTrace; + return h(Textarea, { + value: data.exceptionStackTrace, + rows: 20, + }); }, }, { diff --git a/apps/web-antd/src/views/infra/fileConfig/data.ts b/apps/web-antd/src/views/infra/fileConfig/data.ts index 58cc4cd93..b28d53deb 100644 --- a/apps/web-antd/src/views/infra/fileConfig/data.ts +++ b/apps/web-antd/src/views/infra/fileConfig/data.ts @@ -200,6 +200,25 @@ export function useFormSchema(): VbenFormSchema[] { }, defaultValue: false, }, + { + fieldName: 'config.enablePublicAccess', + label: '公开访问', + component: 'RadioGroup', + componentProps: { + options: [ + { label: '公开', value: true }, + { label: '私有', value: false }, + ], + buttonStyle: 'solid', + optionType: 'button', + }, + rules: 'required', + dependencies: { + triggerFields: ['storage'], + show: (formValues) => formValues.storage === 20, + }, + defaultValue: false, + }, // 通用 { fieldName: 'config.domain', diff --git a/apps/web-ele/.env.development b/apps/web-ele/.env.development index 02edf8dd7..77c13d398 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 910fd64cc..ac0408ec4 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 260f13b89..3651c1b87 100644 --- a/apps/web-ele/package.json +++ b/apps/web-ele/package.json @@ -50,7 +50,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/infra/file-config/index.ts b/apps/web-ele/src/api/infra/file-config/index.ts index 20a0ab3fa..1a2fb7707 100644 --- a/apps/web-ele/src/api/infra/file-config/index.ts +++ b/apps/web-ele/src/api/infra/file-config/index.ts @@ -16,6 +16,7 @@ export namespace InfraFileConfigApi { accessKey?: string; accessSecret?: string; pathStyle?: boolean; + enablePublicAccess?: boolean; domain: string; } 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 c0d53d6b2..486f05aa6 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 daa5e4b06..afdface5a 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 e11e8828a..9a7e121dd 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 000000000..c982804c7 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 000000000..b85562e42 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 c366b2784..9b31950f4 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 000000000..06d71be76 --- /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 000000000..550b88d76 --- /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 000000000..5b608c4e1 --- /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 000000000..16170c230 --- /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 000000000..24062a191 --- /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 000000000..5a9b803d1 --- /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 000000000..628c1c559 --- /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 000000000..749d36a32 --- /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 000000000..df256770c --- /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 000000000..21da40439 --- /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 000000000..7147ef9b2 --- /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 000000000..1736db389 --- /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 000000000..7746b73bd --- /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 000000000..b842d19f5 --- /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 000000000..bc724eca9 --- /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 000000000..0d69fd9db --- /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 000000000..d4dbfee44 --- /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 000000000..ddfc1857a --- /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 000000000..634cb88c6 --- /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 000000000..bde532e4a --- /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 000000000..c96903f15 --- /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 000000000..eb5fbb1a2 --- /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 000000000..55332dede --- /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 000000000..7972bd3bc --- /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 000000000..eb6563766 --- /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 000000000..2be023a87 --- /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 000000000..93a264b5e --- /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 000000000..0a72633d6 --- /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 000000000..71e39d9cd --- /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 000000000..dd36b550f --- /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 000000000..e3c602f65 --- /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 000000000..53a87403c --- /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 000000000..4562f7b32 --- /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 000000000..ce1b3ad5b --- /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 000000000..454e06a0b --- /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 000000000..b364fbb35 --- /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 000000000..5a3aa7e57 --- /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 000000000..80efbae66 --- /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 000000000..4ae675a49 --- /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 000000000..2036ede96 --- /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 000000000..88039d352 --- /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 000000000..4be256749 --- /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 000000000..12670dcb0 --- /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 000000000..a98edc254 --- /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 000000000..535287d40 --- /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 000000000..0d69c7c86 --- /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 000000000..62dd6e92d --- /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 000000000..b34e00917 --- /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 000000000..38325d5a9 --- /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 000000000..4a32acb80 --- /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 000000000..ce3e3f698 --- /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 000000000..31dc13794 --- /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 000000000..589e89373 --- /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 000000000..935e5ec4d --- /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 000000000..29855bb73 --- /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 000000000..4dca2797e --- /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 000000000..ea3c9e4da --- /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 000000000..b1cf736e8 --- /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 000000000..e0b3dfb77 --- /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 000000000..0f68a515f --- /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 000000000..0e7ec6e1b --- /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 000000000..f4e6d9686 --- /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 000000000..9ad0304bc --- /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 000000000..10e9f5aa3 --- /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 000000000..82d3f35b4 --- /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 000000000..fba3a4a85 --- /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 000000000..82f1f5bd7 --- /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 000000000..da57011de --- /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 000000000..4484f3125 --- /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 000000000..3ff8336dd --- /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 000000000..c028feacd --- /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 000000000..fcba6c7e0 --- /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 000000000..b497437b0 --- /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 000000000..3dd246f02 --- /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 000000000..64ab098a4 --- /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 000000000..e7c770304 --- /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 000000000..149f52fce --- /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 000000000..bc9488e1c --- /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 000000000..9c1ddd834 --- /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 000000000..fab41b648 --- /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 000000000..64d49ad6c --- /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 000000000..8ee389d88 --- /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 000000000..45a4147c0 --- /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 000000000..e674a0a32 --- /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 000000000..9cb312f37 --- /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 000000000..38f5d2b5d --- /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 000000000..efcb7f2ef --- /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 000000000..2df2df328 --- /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 000000000..c9fb1fbfb --- /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 000000000..0c2e825a3 --- /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 000000000..ab527acee --- /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 000000000..d403c325b --- /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 000000000..8393760b4 --- /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 000000000..7581e54c9 --- /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 000000000..851e7f2f1 --- /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 000000000..dc2dd8866 --- /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 000000000..ddd448d96 --- /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 000000000..d07835f25 --- /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 000000000..7f7ce0e38 --- /dev/null +++ b/apps/web-ele/src/components/diy-editor/index.vue @@ -0,0 +1,659 @@ + +