diff --git a/src/api/crm/customer/index.ts b/src/api/crm/customer/index.ts index 0cbba590..59260cbc 100644 --- a/src/api/crm/customer/index.ts +++ b/src/api/crm/customer/index.ts @@ -1,13 +1,14 @@ import request from '@/config/axios' export interface CustomerVO { - id: number + id?: number name: string industryId: number level: number source: number - followUpStatus: boolean - lockStatus: boolean + followUpStatus?: boolean + lockStatus?: boolean + dealStatus?: boolean mobile: string telephone: string website: string @@ -16,13 +17,20 @@ export interface CustomerVO { email: string description: string remark: string - ownerUserId: number - roUserIds: string - rwUserIds: string - areaId: number + ownerUserId?: number + ownerUserName?: string + ownerUserDept?: string + roUserIds?: string + rwUserIds?: string + areaId?: number + areaName?: string detailAddress: string - contactLastTime: Date + contactLastTime?: Date contactNextTime: Date + createTime?: Date + updateTime?: Date + creator?: string + creatorName?: string } // 查询客户列表 diff --git a/src/api/crm/productCategory/index.ts b/src/api/crm/productCategory/index.ts index cdf8a966..6341d1bc 100644 --- a/src/api/crm/productCategory/index.ts +++ b/src/api/crm/productCategory/index.ts @@ -1,5 +1,6 @@ import request from '@/config/axios' +// TODO @zange:挪到 product 下,建个 category 包,挪进去哈; export interface ProductCategoryVO { id: number name: string diff --git a/src/api/login/index.ts b/src/api/login/index.ts index 1ffb38d6..ef86563b 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -27,6 +27,11 @@ export const getTenantIdByName = (name: string) => { return request.get({ url: '/system/tenant/get-id-by-name?name=' + name }) } +// 使用租户域名,获得租户信息 +export const getTenantByWebsite = (website: string) => { + return request.get({ url: '/system/tenant/get-by-website?website=' + website }) +} + // 登出 export const loginOut = () => { return request.post({ url: '/system/auth/logout' }) diff --git a/src/api/mall/promotion/diy/page.ts b/src/api/mall/promotion/diy/page.ts new file mode 100644 index 00000000..1cd34282 --- /dev/null +++ b/src/api/mall/promotion/diy/page.ts @@ -0,0 +1,45 @@ +import request from '@/config/axios' + +export interface DiyPageVO { + id?: number + templateId?: number + name: string + remark: string + previewImageUrls: string[] + property: string +} + +// 查询装修页面列表 +export const getDiyPagePage = async (params: any) => { + return await request.get({ url: `/promotion/diy-page/page`, params }) +} + +// 查询装修页面详情 +export const getDiyPage = async (id: number) => { + return await request.get({ url: `/promotion/diy-page/get?id=` + id }) +} + +// 新增装修页面 +export const createDiyPage = async (data: DiyPageVO) => { + return await request.post({ url: `/promotion/diy-page/create`, data }) +} + +// 修改装修页面 +export const updateDiyPage = async (data: DiyPageVO) => { + return await request.put({ url: `/promotion/diy-page/update`, data }) +} + +// 删除装修页面 +export const deleteDiyPage = async (id: number) => { + return await request.delete({ url: `/promotion/diy-page/delete?id=` + id }) +} + +// 获得装修页面属性 +export const getDiyPageProperty = async (id: number) => { + return await request.get({ url: `/promotion/diy-page/get-property?id=` + id }) +} + +// 更新装修页面属性 +export const updateDiyPageProperty = async (data: DiyPageVO) => { + return await request.put({ url: `/promotion/diy-page/update-property`, data }) +} diff --git a/src/api/mall/promotion/diy/template.ts b/src/api/mall/promotion/diy/template.ts new file mode 100644 index 00000000..f8d4bc80 --- /dev/null +++ b/src/api/mall/promotion/diy/template.ts @@ -0,0 +1,58 @@ +import request from '@/config/axios' +import { DiyPageVO } from '@/api/mall/promotion/diy/page' + +export interface DiyTemplateVO { + id?: number + name: string + used: boolean + usedTime?: Date + remark: string + previewImageUrls: string[] + property: string +} + +export interface DiyTemplatePropertyVO extends DiyTemplateVO { + pages: DiyPageVO[] +} + +// 查询装修模板列表 +export const getDiyTemplatePage = async (params: any) => { + return await request.get({ url: `/promotion/diy-template/page`, params }) +} + +// 查询装修模板详情 +export const getDiyTemplate = async (id: number) => { + return await request.get({ url: `/promotion/diy-template/get?id=` + id }) +} + +// 新增装修模板 +export const createDiyTemplate = async (data: DiyTemplateVO) => { + return await request.post({ url: `/promotion/diy-template/create`, data }) +} + +// 修改装修模板 +export const updateDiyTemplate = async (data: DiyTemplateVO) => { + return await request.put({ url: `/promotion/diy-template/update`, data }) +} + +// 删除装修模板 +export const deleteDiyTemplate = async (id: number) => { + return await request.delete({ url: `/promotion/diy-template/delete?id=` + id }) +} + +// 使用装修模板 +export const useDiyTemplate = async (id: number) => { + return await request.put({ url: `/promotion/diy-template/use?id=` + id }) +} + +// 获得装修模板属性 +export const getDiyTemplateProperty = async (id: number) => { + return await request.get({ + url: `/promotion/diy-template/get-property?id=` + id + }) +} + +// 更新装修模板属性 +export const updateDiyTemplateProperty = async (data: DiyTemplateVO) => { + return await request.put({ url: `/promotion/diy-template/update-property`, data }) +} diff --git a/src/api/pay/demo/transfer/index.ts b/src/api/pay/demo/transfer/index.ts new file mode 100644 index 00000000..a95b0d5c --- /dev/null +++ b/src/api/pay/demo/transfer/index.ts @@ -0,0 +1,25 @@ +import request from '@/config/axios' + +export interface DemoTransferVO { + price: number + type: number + userName: string + alipayLogonId: string + openid: string +} + +// 创建示例转账单 +export function createDemoTransfer(data: DemoTransferVO) { + return request.post({ + url: '/pay/demo-transfer/create', + data: data + }) +} + +// 获得示例订单分页 +export function getDemoTransferPage(query: PageParam) { + return request.get({ + url: '/pay/demo-transfer/page', + params: query + }) +} diff --git a/src/api/pay/transfer/index.ts b/src/api/pay/transfer/index.ts new file mode 100644 index 00000000..7a58abf4 --- /dev/null +++ b/src/api/pay/transfer/index.ts @@ -0,0 +1,27 @@ +import request from '@/config/axios' + +export interface TransferVO { + appId: number + channelCode: string + merchantTransferId: string + type: number + price: number + subject: string + userName: string + alipayLogonId: string + openid: string +} + +// 新增转账单 +export const createTransfer = async (data: TransferVO) => { + return await request.post({ url: `/pay/transfer/create`, data }) +} + +// 查询转账单列表 +export const getTransferPage = async (params) => { + return await request.get({ url: `/pay/transfer/page`, params }) +} + +export const getTransfer = async (id: number) => { + return await request.get({ url: '/pay/transfer/get?id=' + id }) +} diff --git a/src/assets/imgs/diy/statusBar.png b/src/assets/imgs/diy/statusBar.png new file mode 100644 index 00000000..b85562e4 Binary files /dev/null and b/src/assets/imgs/diy/statusBar.png differ diff --git a/src/components/ColorInput/index.vue b/src/components/ColorInput/index.vue new file mode 100644 index 00000000..abd083a1 --- /dev/null +++ b/src/components/ColorInput/index.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/components/DiyEditor/components/ComponentContainer.vue b/src/components/DiyEditor/components/ComponentContainer.vue new file mode 100644 index 00000000..c013362f --- /dev/null +++ b/src/components/DiyEditor/components/ComponentContainer.vue @@ -0,0 +1,222 @@ + + + + + + diff --git a/src/components/DiyEditor/components/ComponentContainerProperty.vue b/src/components/DiyEditor/components/ComponentContainerProperty.vue new file mode 100644 index 00000000..5c5ed9a0 --- /dev/null +++ b/src/components/DiyEditor/components/ComponentContainerProperty.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/src/components/DiyEditor/components/ComponentLibrary.vue b/src/components/DiyEditor/components/ComponentLibrary.vue new file mode 100644 index 00000000..2bcd81fd --- /dev/null +++ b/src/components/DiyEditor/components/ComponentLibrary.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/Carousel/config.ts b/src/components/DiyEditor/components/mobile/Carousel/config.ts new file mode 100644 index 00000000..3e74a511 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/Carousel/config.ts @@ -0,0 +1,50 @@ +import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util' + +/** 轮播图属性 */ +export interface CarouselProperty { + // 类型:默认 | 卡片 + type: 'default' | 'card' + // 指示器样式:点 | 数字 + 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/src/components/DiyEditor/components/mobile/Carousel/index.vue b/src/components/DiyEditor/components/mobile/Carousel/index.vue new file mode 100644 index 00000000..940a9a56 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/Carousel/index.vue @@ -0,0 +1,43 @@ + + + + diff --git a/src/components/DiyEditor/components/mobile/Carousel/property.vue b/src/components/DiyEditor/components/mobile/Carousel/property.vue new file mode 100644 index 00000000..700e0005 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/Carousel/property.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/Divider/config.ts b/src/components/DiyEditor/components/mobile/Divider/config.ts new file mode 100644 index 00000000..9b553604 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/Divider/config.ts @@ -0,0 +1,29 @@ +import { DiyComponent } from '@/components/DiyEditor/util' + +/** 分割线属性 */ +export interface DividerProperty { + // 高度 + height: number + // 线宽 + lineWidth: number + // 边距类型 + paddingType: 'none' | 'horizontal' + // 颜色 + lineColor: string + // 类型 + borderType: 'solid' | 'dashed' | 'dotted' | 'none' +} + +// 定义组件 +export const component = { + id: 'Divider', + name: '分割线', + icon: 'tdesign:component-divider-vertical', + property: { + height: 30, + lineWidth: 1, + paddingType: 'none', + lineColor: '#dcdfe6', + borderType: 'solid' + } +} as DiyComponent diff --git a/src/components/DiyEditor/components/mobile/Divider/index.vue b/src/components/DiyEditor/components/mobile/Divider/index.vue new file mode 100644 index 00000000..f7785043 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/Divider/index.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/Divider/property.vue b/src/components/DiyEditor/components/mobile/Divider/property.vue new file mode 100644 index 00000000..3d7be26d --- /dev/null +++ b/src/components/DiyEditor/components/mobile/Divider/property.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/ImageBar/config.ts b/src/components/DiyEditor/components/mobile/ImageBar/config.ts new file mode 100644 index 00000000..68edf728 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/ImageBar/config.ts @@ -0,0 +1,27 @@ +import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/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/src/components/DiyEditor/components/mobile/ImageBar/index.vue b/src/components/DiyEditor/components/mobile/ImageBar/index.vue new file mode 100644 index 00000000..6f70c52d --- /dev/null +++ b/src/components/DiyEditor/components/mobile/ImageBar/index.vue @@ -0,0 +1,24 @@ + + + + diff --git a/src/components/DiyEditor/components/mobile/ImageBar/property.vue b/src/components/DiyEditor/components/mobile/ImageBar/property.vue new file mode 100644 index 00000000..58af1bc8 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/ImageBar/property.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/NavigationBar/config.ts b/src/components/DiyEditor/components/mobile/NavigationBar/config.ts new file mode 100644 index 00000000..f722d525 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/NavigationBar/config.ts @@ -0,0 +1,38 @@ +import { DiyComponent } from '@/components/DiyEditor/util' + +/** 顶部导航栏属性 */ +export interface NavigationBarProperty { + // 页面标题 + title: string + // 页面描述 + description: string + // 顶部导航高度 + navBarHeight: number + // 页面背景颜色 + backgroundColor: string + // 页面背景图片 + backgroundImage: string + // 样式类型:默认 | 沉浸式 + styleType: 'default' | 'immersion' + // 常驻显示 + alwaysShow: boolean + // 是否显示返回按钮 + showGoBack: boolean +} + +// 定义组件 +export const component = { + id: 'NavigationBar', + name: '顶部导航栏', + icon: 'tabler:layout-navbar', + property: { + title: '页面标题', + description: '', + navBarHeight: 35, + backgroundColor: '#fff', + backgroundImage: '', + styleType: 'default', + alwaysShow: true, + showGoBack: true + } +} as DiyComponent diff --git a/src/components/DiyEditor/components/mobile/NavigationBar/index.vue b/src/components/DiyEditor/components/mobile/NavigationBar/index.vue new file mode 100644 index 00000000..345b6681 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/NavigationBar/index.vue @@ -0,0 +1,59 @@ + + + diff --git a/src/components/DiyEditor/components/mobile/NavigationBar/property.vue b/src/components/DiyEditor/components/mobile/NavigationBar/property.vue new file mode 100644 index 00000000..c4ca4588 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/NavigationBar/property.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/NoticeBar/config.ts b/src/components/DiyEditor/components/mobile/NoticeBar/config.ts new file mode 100644 index 00000000..03e7143a --- /dev/null +++ b/src/components/DiyEditor/components/mobile/NoticeBar/config.ts @@ -0,0 +1,39 @@ +import { DiyComponent } from '@/components/DiyEditor/util' + +/** 公告栏属性 */ +export interface NoticeBarProperty { + // 图标地址 + iconUrl: string + // 公告内容列表 + contents: NoticeContentProperty[] + // 背景颜色 + backgroundColor: string + // 文字颜色 + textColor: string +} + +/** 内容属性 */ +export interface NoticeContentProperty { + // 内容文字 + text: string + // 链接地址 + url: string +} + +// 定义组件 +export const component = { + id: 'NoticeBar', + name: '公告栏', + icon: 'ep:bell', + property: { + iconUrl: 'http://mall.yudao.iocoder.cn/static/images/xinjian.png', + contents: [ + { + text: '', + url: '' + } + ], + backgroundColor: '#fff', + textColor: '#333' + } +} as DiyComponent diff --git a/src/components/DiyEditor/components/mobile/NoticeBar/index.vue b/src/components/DiyEditor/components/mobile/NoticeBar/index.vue new file mode 100644 index 00000000..fce1afbb --- /dev/null +++ b/src/components/DiyEditor/components/mobile/NoticeBar/index.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/NoticeBar/property.vue b/src/components/DiyEditor/components/mobile/NoticeBar/property.vue new file mode 100644 index 00000000..11e7f4b7 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/NoticeBar/property.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/PageConfig/config.ts b/src/components/DiyEditor/components/mobile/PageConfig/config.ts new file mode 100644 index 00000000..f8e45e45 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/PageConfig/config.ts @@ -0,0 +1,23 @@ +import { DiyComponent } from '@/components/DiyEditor/util' + +/** 页面设置属性 */ +export interface PageConfigProperty { + // 页面描述 + description: string + // 页面背景颜色 + backgroundColor: string + // 页面背景图片 + backgroundImage: string +} + +// 定义页面组件 +export const component = { + id: 'PageConfig', + name: '页面设置', + icon: 'ep:document', + property: { + description: '', + backgroundColor: '#f5f5f5', + backgroundImage: '' + } +} as DiyComponent diff --git a/src/components/DiyEditor/components/mobile/PageConfig/property.vue b/src/components/DiyEditor/components/mobile/PageConfig/property.vue new file mode 100644 index 00000000..278bc940 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/PageConfig/property.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/SearchBar/config.ts b/src/components/DiyEditor/components/mobile/SearchBar/config.ts new file mode 100644 index 00000000..ef47b27c --- /dev/null +++ b/src/components/DiyEditor/components/mobile/SearchBar/config.ts @@ -0,0 +1,43 @@ +import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/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 = 'left' | 'center' + +// 定义组件 +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/src/components/DiyEditor/components/mobile/SearchBar/index.vue b/src/components/DiyEditor/components/mobile/SearchBar/index.vue new file mode 100644 index 00000000..618c918b --- /dev/null +++ b/src/components/DiyEditor/components/mobile/SearchBar/index.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/SearchBar/property.vue b/src/components/DiyEditor/components/mobile/SearchBar/property.vue new file mode 100644 index 00000000..d121a1e3 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/SearchBar/property.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/TabBar/config.ts b/src/components/DiyEditor/components/mobile/TabBar/config.ts new file mode 100644 index 00000000..88d706fe --- /dev/null +++ b/src/components/DiyEditor/components/mobile/TabBar/config.ts @@ -0,0 +1,97 @@ +import { DiyComponent } from '@/components/DiyEditor/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/src/components/DiyEditor/components/mobile/TabBar/index.vue b/src/components/DiyEditor/components/mobile/TabBar/index.vue new file mode 100644 index 00000000..647e3369 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/TabBar/index.vue @@ -0,0 +1,58 @@ + + + diff --git a/src/components/DiyEditor/components/mobile/TabBar/property.vue b/src/components/DiyEditor/components/mobile/TabBar/property.vue new file mode 100644 index 00000000..eefdf54a --- /dev/null +++ b/src/components/DiyEditor/components/mobile/TabBar/property.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/TitleBar/config.ts b/src/components/DiyEditor/components/mobile/TitleBar/config.ts new file mode 100644 index 00000000..3d486cc3 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/TitleBar/config.ts @@ -0,0 +1,65 @@ +import { DiyComponent } from '@/components/DiyEditor/util' + +/** 标题栏属性 */ +export interface TitleBarProperty { + // 主标题 + title: string + // 副标题 + description: string + // 标题大小 + titleSize: number + // 描述大小 + descriptionSize: number + // 标题粗细 + titleWeight: number + // 显示位置 + position: 'left' | 'center' + // 描述粗细 + descriptionWeight: number + // 标题颜色 + titleColor: string + // 描述颜色 + descriptionColor: string + // 背景颜色 + backgroundColor: string + // 底部分割线 + showBottomBorder: false + // 查看更多 + more: { + // 是否显示查看更多 + show: false + // 样式选择 + type: 'text' | 'icon' | 'all' + // 自定义文字 + text: string + // 链接 + url: string + } +} + +// 定义组件 +export const component = { + id: 'TitleBar', + name: '标题栏', + icon: 'material-symbols:line-start', + property: { + title: '主标题', + description: '副标题', + titleSize: 16, + descriptionSize: 12, + titleWeight: 400, + position: 'left', + descriptionWeight: 200, + titleColor: 'rgba(50, 50, 51, 10)', + descriptionColor: 'rgba(150, 151, 153, 10)', + backgroundColor: 'rgba(255, 255, 255, 10)', + showBottomBorder: false, + more: { + //查看更多 + show: false, + type: 'icon', + text: '查看更多', + url: '' + } + } +} as DiyComponent diff --git a/src/components/DiyEditor/components/mobile/TitleBar/index.vue b/src/components/DiyEditor/components/mobile/TitleBar/index.vue new file mode 100644 index 00000000..aab65779 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/TitleBar/index.vue @@ -0,0 +1,80 @@ + + + diff --git a/src/components/DiyEditor/components/mobile/TitleBar/property.vue b/src/components/DiyEditor/components/mobile/TitleBar/property.vue new file mode 100644 index 00000000..3e4dac2d --- /dev/null +++ b/src/components/DiyEditor/components/mobile/TitleBar/property.vue @@ -0,0 +1,115 @@ + + + + diff --git a/src/components/DiyEditor/components/mobile/VideoPlayer/config.ts b/src/components/DiyEditor/components/mobile/VideoPlayer/config.ts new file mode 100644 index 00000000..30501cb8 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/VideoPlayer/config.ts @@ -0,0 +1,37 @@ +import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/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 ComponentStyle + } +} as DiyComponent diff --git a/src/components/DiyEditor/components/mobile/VideoPlayer/index.vue b/src/components/DiyEditor/components/mobile/VideoPlayer/index.vue new file mode 100644 index 00000000..a62dea08 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/VideoPlayer/index.vue @@ -0,0 +1,30 @@ + + + + diff --git a/src/components/DiyEditor/components/mobile/VideoPlayer/property.vue b/src/components/DiyEditor/components/mobile/VideoPlayer/property.vue new file mode 100644 index 00000000..96f317d6 --- /dev/null +++ b/src/components/DiyEditor/components/mobile/VideoPlayer/property.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/components/DiyEditor/components/mobile/index.ts b/src/components/DiyEditor/components/mobile/index.ts new file mode 100644 index 00000000..c0dc67da --- /dev/null +++ b/src/components/DiyEditor/components/mobile/index.ts @@ -0,0 +1,61 @@ +/* + * 组件注册 + * + * 组件规范: + * 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 = {} +// 组件配置模块 +const componentConfigs = {} + +// 组件界面的类型 +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 { components, componentConfigs } diff --git a/src/components/DiyEditor/index.vue b/src/components/DiyEditor/index.vue new file mode 100644 index 00000000..fbb7e103 --- /dev/null +++ b/src/components/DiyEditor/index.vue @@ -0,0 +1,454 @@ + + + + diff --git a/src/components/DiyEditor/util.ts b/src/components/DiyEditor/util.ts new file mode 100644 index 00000000..29b44cf6 --- /dev/null +++ b/src/components/DiyEditor/util.ts @@ -0,0 +1,120 @@ +import { ref, Ref } from 'vue' +import { PageConfigProperty } from '@/components/DiyEditor/components/mobile/PageConfig/config' +import { NavigationBarProperty } from '@/components/DiyEditor/components/mobile/NavigationBar/config' +import { TabBarProperty } from '@/components/DiyEditor/components/mobile/TabBar/config' + +// 页面装修组件 +export interface DiyComponent { + // 组件唯一标识 + id: string + // 组件名称 + name: string + // 组件图标 + icon: string + // 组件属性 + property: T +} + +// 页面装修组件库 +export interface DiyComponentLibrary { + // 组件库名称 + name: string + // 是否展开 + extended: boolean + // 组件列表 + components: string[] +} + +// 组件样式 +export interface ComponentStyle { + // 背景类型 + bgType: 'color' | 'img' + // 背景颜色 + bgColor: string + // 背景图片 + bgImg: string + // 外边距 + margin: number + marginTop: number + marginRight: number + marginBottom: number + marginLeft: number + // 内边距 + padding: number + paddingTop: number + paddingRight: number + paddingBottom: number + paddingLeft: number + // 边框圆角 + borderRadius: number + borderTopLeftRadius: number + borderTopRightRadius: number + borderBottomRightRadius: number + borderBottomLeftRadius: number +} + +// 页面配置 +export interface PageConfig { + // 页面属性 + page: PageConfigProperty + // 顶部导航栏属性 + navigationBar: NavigationBarProperty + // 底部导航菜单属性 + tabBar?: TabBarProperty + // 页面组件列表 + components: PageComponent[] +} +// 页面组件,只保留组件ID,组件属性 +export interface PageComponent extends Pick, 'id' | 'property'> {} + +// 属性表单监听 +export function usePropertyForm(modelValue: T, emit: Function): { formData: Ref } { + const formData = ref() + // 监听属性数据变动 + watch( + () => modelValue, + () => { + formData.value = modelValue + }, + { + deep: true, + immediate: true + } + ) + // 监听表单数据变动 + watch( + () => formData.value, + () => { + emit('update:modelValue', formData.value) + }, + { + deep: true + } + ) + + return { formData } +} + +// 页面组件库 +export const PAGE_LIBS = [ + { + name: '基础组件', + extended: true, + components: [ + 'SearchBar', + 'NoticeBar', + 'GridNavigation', + 'ListNavigation', + 'Divider', + 'TitleBar' + ] + }, + { name: '图文组件', extended: true, components: ['ImageBar', 'Carousel', 'VideoPlayer'] }, + { name: '商品组件', extended: true, components: ['ProductCard'] }, + { + name: '会员组件', + extended: true, + components: ['UserCard', 'OrderCard', 'WalletCard', 'CouponCard'] + }, + { name: '营销组件', extended: true, components: ['Combination', 'Seckill', 'Point', 'Coupon'] } +] as DiyComponentLibrary[] diff --git a/src/components/UploadFile/src/UploadFile.vue b/src/components/UploadFile/src/UploadFile.vue index c8a3b972..6895440b 100644 --- a/src/components/UploadFile/src/UploadFile.vue +++ b/src/components/UploadFile/src/UploadFile.vue @@ -33,11 +33,10 @@ diff --git a/src/layout/components/Footer/src/Footer.vue b/src/layout/components/Footer/src/Footer.vue index c350e38a..3eede386 100644 --- a/src/layout/components/Footer/src/Footer.vue +++ b/src/layout/components/Footer/src/Footer.vue @@ -19,6 +19,6 @@ const title = computed(() => appStore.getTitle) :class="prefixCls" class="h-[var(--app-footer-height)] bg-[var(--app-content-bg-color)] text-center leading-[var(--app-footer-height)] text-[var(--el-text-color-placeholder)] dark:bg-[var(--el-bg-color)]" > -

Copyright ©2022-{{ title }}

+ Copyright ©2022-{{ title }} diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index aa260cf1..58eb1733 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -459,6 +459,52 @@ const remainingRouter: AppRouteRecordRaw[] = [ component: () => import('@/views/pay/cashier/index.vue') } ] + }, + { + path: '/diy', + name: 'DiyCenter', + meta: { hidden: true }, + component: Layout, + children: [ + { + path: 'template/decorate/:id', + name: 'DiyTemplateDecorate', + meta: { + title: '模板装修', + noCache: true, + hidden: true + }, + component: () => import('@/views/mall/promotion/diy/template/decorate.vue') + }, + { + path: 'page/decorate/:id', + name: 'DiyPageDecorate', + meta: { + title: '页面装修', + noCache: true, + hidden: true + }, + component: () => import('@/views/mall/promotion/diy/page/decorate.vue') + } + ] + }, + { + path: '/crm', + component: Layout, + name: 'CrmCenter', + meta: { hidden: true }, + children: [ + { + path: 'customer/detail/:id', + name: 'CrmCustomerDetail', + meta: { + title: '客户详情', + noCache: true, + hidden: true + }, + component: () => import('@/views/crm/customer/detail/index.vue') + } + ] } ] diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 383fa401..9fe429e9 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -144,6 +144,8 @@ export enum DICT_TYPE { PAY_REFUND_STATUS = 'pay_refund_status', // 退款订单状态 PAY_NOTIFY_STATUS = 'pay_notify_status', // 商户支付回调状态 PAY_NOTIFY_TYPE = 'pay_notify_type', // 商户支付回调状态 + PAY_TRANSFER_STATUS = 'pay_transfer_status', // 转账订单状态 + PAY_TRANSFER_TYPE = 'pay_transfer_type', // 转账订单状态 // ========== MP 模块 ========== MP_AUTO_REPLY_REQUEST_MATCH = 'mp_auto_reply_request_match', // 自动回复请求匹配类型 diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 9bee2523..ef212505 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -193,10 +193,10 @@ const loginData = reactive({ }) const socialList = [ - { icon: 'ant-design:github-filled', type: 0 }, { icon: 'ant-design:wechat-filled', type: 30 }, - { icon: 'ant-design:alipay-circle-filled', type: 0 }, - { icon: 'ant-design:dingtalk-circle-filled', type: 20 } + { icon: 'ant-design:dingtalk-circle-filled', type: 20 }, + { icon: 'ant-design:github-filled', type: 0 }, + { icon: 'ant-design:alipay-circle-filled', type: 0 } ] // 获取验证码 @@ -210,7 +210,7 @@ const getCode = async () => { verify.value.show() } } -//获取租户ID +// 获取租户 ID const getTenantId = async () => { if (loginData.tenantEnable === 'true') { const res = await LoginApi.getTenantIdByName(loginData.loginForm.tenantName) @@ -230,6 +230,15 @@ const getCookie = () => { } } } +// 根据域名,获得租户信息 +const getTenantByWebsite = async () => { + const website = location.host + const res = await LoginApi.getTenantByWebsite(website) + if (res) { + loginData.loginForm.tenantName = res.name + authUtil.setTenantId(res.id) + } +} const loading = ref() // ElLoading.service 返回的实例 // 登录 const handleLogin = async (params) => { @@ -278,10 +287,15 @@ const doSocialLogin = async (type: number) => { } else { loginLoading.value = true if (loginData.tenantEnable === 'true') { - await message.prompt('请输入租户名称', t('common.reminder')).then(async ({ value }) => { - const res = await LoginApi.getTenantIdByName(value) - authUtil.setTenantId(res) - }) + // 尝试先通过 tenantName 获取租户 + await getTenantId() + // 如果获取不到,则需要弹出提示,进行处理 + if (!authUtil.getTenantId()) { + await message.prompt('请输入租户名称', t('common.reminder')).then(async ({ value }) => { + const res = await LoginApi.getTenantIdByName(value) + authUtil.setTenantId(res) + }) + } } // 计算 redirectUri // tricky: type、redirect需要先encode一次,否则钉钉回调会丢失。 @@ -307,6 +321,7 @@ watch( ) onMounted(() => { getCookie() + getTenantByWebsite() }) diff --git a/src/views/crm/clue/ClueForm.vue b/src/views/crm/clue/ClueForm.vue index 877b26d9..4321f952 100644 --- a/src/views/crm/clue/ClueForm.vue +++ b/src/views/crm/clue/ClueForm.vue @@ -10,7 +10,7 @@ - + @@ -31,7 +31,7 @@ - + @@ -46,7 +46,6 @@ diff --git a/src/views/crm/customer/detail/CustomerDetails.vue b/src/views/crm/customer/detail/CustomerDetails.vue new file mode 100644 index 00000000..1065b22c --- /dev/null +++ b/src/views/crm/customer/detail/CustomerDetails.vue @@ -0,0 +1,92 @@ + + + diff --git a/src/views/crm/customer/detail/index.vue b/src/views/crm/customer/detail/index.vue new file mode 100644 index 00000000..1caeadef --- /dev/null +++ b/src/views/crm/customer/detail/index.vue @@ -0,0 +1,154 @@ + + + diff --git a/src/views/crm/customer/index.vue b/src/views/crm/customer/index.vue index 7db9654d..073bf8cb 100644 --- a/src/views/crm/customer/index.vue +++ b/src/views/crm/customer/index.vue @@ -26,6 +26,51 @@ class="!w-240px" /> + + + + + + + + + + + + + + + 搜索 重置 @@ -67,8 +112,9 @@ - - + + + - - + +