diff --git a/apps/web-antd/src/adapter/vxe-table.ts b/apps/web-antd/src/adapter/vxe-table.ts index c4dcb2a86..7e71fd5ff 100644 --- a/apps/web-antd/src/adapter/vxe-table.ts +++ b/apps/web-antd/src/adapter/vxe-table.ts @@ -1,3 +1,4 @@ +import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { Recordable } from '@vben/types'; import { h } from 'vue'; @@ -63,7 +64,7 @@ setupVbenVxeTable({ round: true, showOverflow: true, size: 'small', - }, + } as VxeTableGridOptions, }); // 表格配置项可以用 cellRender: { name: 'CellImage' }, @@ -74,6 +75,16 @@ setupVbenVxeTable({ }, }); + vxeUI.renderer.add('CellImages', { + renderTableDefault(_renderOpts, params) { + const { column, row } = params; + if (column && column.field && row[column.field]) { + return row[column.field].map((item: any) => h(Image, { src: item })); + } + return ''; + }, + }); + // 表格配置项可以用 cellRender: { name: 'CellLink' }, vxeUI.renderer.add('CellLink', { renderTableDefault(renderOpts) { @@ -267,6 +278,38 @@ setupVbenVxeTable({ // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 // vxeUI.formats.add + + vxeUI.formats.add('formatPast2', { + tableCellFormatMethod({ cellValue }) { + if (cellValue === null || cellValue === undefined) { + return ''; + } + // 定义时间单位常量,便于维护 + const SECOND = 1000; + const MINUTE = 60 * SECOND; + const HOUR = 60 * MINUTE; + const DAY = 24 * HOUR; + + // 计算各时间单位 + const day = Math.floor(cellValue / DAY); + const hour = Math.floor((cellValue % DAY) / HOUR); + const minute = Math.floor((cellValue % HOUR) / MINUTE); + const second = Math.floor((cellValue % MINUTE) / SECOND); + + // 根据时间长短返回不同格式 + if (day > 0) { + return `${day} 天${hour} 小时 ${minute} 分钟`; + } + if (hour > 0) { + return `${hour} 小时 ${minute} 分钟`; + } + if (minute > 0) { + return `${minute} 分钟`; + } + return second > 0 ? `${second} 秒` : `${0} 秒`; + }, + }); + // add by 星语:数量格式化,例如说:金额 vxeUI.formats.add('formatNumber', { tableCellFormatMethod({ cellValue }, digits = 2) { @@ -284,7 +327,7 @@ setupVbenVxeTable({ }, }); - vxeUI.formats.add('formatFraction', { + vxeUI.formats.add('formatAmount2', { tableCellFormatMethod({ cellValue }) { if (cellValue === null || cellValue === undefined) { return '0.00'; diff --git a/apps/web-antd/src/api/bpm/category/index.ts b/apps/web-antd/src/api/bpm/category/index.ts index 4b509d298..d622183f0 100644 --- a/apps/web-antd/src/api/bpm/category/index.ts +++ b/apps/web-antd/src/api/bpm/category/index.ts @@ -3,7 +3,8 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; export namespace BpmCategoryApi { - /** BPM 流程分类 VO */ + /** 流程分类 VO */ + // TODO @jason:不用 VO 后缀哈 export interface CategoryVO { id: number; name: string; diff --git a/apps/web-antd/src/api/bpm/definition/index.ts b/apps/web-antd/src/api/bpm/definition/index.ts index 795caa1b5..b7e22bea9 100644 --- a/apps/web-antd/src/api/bpm/definition/index.ts +++ b/apps/web-antd/src/api/bpm/definition/index.ts @@ -2,9 +2,9 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; -/** 流程定义 */ export namespace BpmProcessDefinitionApi { - // 流程定义 + /** 流程定义 */ + // TODO @ziye:不用 VO 后缀哈 export interface ProcessDefinitionVO { id: string; version: number; diff --git a/apps/web-antd/src/api/bpm/form/index.ts b/apps/web-antd/src/api/bpm/form/index.ts index 78ce4d6d3..1c14a67e8 100644 --- a/apps/web-antd/src/api/bpm/form/index.ts +++ b/apps/web-antd/src/api/bpm/form/index.ts @@ -3,7 +3,8 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; export namespace BpmFormApi { - // 流程表单 + /** 流程表单 */ + // TODO @jason:不用 VO 后缀哈 export interface FormVO { id?: number | undefined; name: string; @@ -23,6 +24,7 @@ export async function getFormPage(params: PageParam) { } /** 获取表单详情 */ +// TODO @ziye:应该不会 string 的情况呢。 export async function getFormDetail(id: number | string) { return requestClient.get(`/bpm/form/get?id=${id}`); } diff --git a/apps/web-antd/src/api/bpm/model/index.ts b/apps/web-antd/src/api/bpm/model/index.ts index 455981782..655cfb034 100644 --- a/apps/web-antd/src/api/bpm/model/index.ts +++ b/apps/web-antd/src/api/bpm/model/index.ts @@ -12,6 +12,7 @@ export namespace BpmModelApi { } /** 流程定义 VO */ + // TODO @jason:不用 VO 后缀哈 export interface ProcessDefinitionVO { id: string; key?: string; diff --git a/apps/web-antd/src/api/bpm/oa/leave/index.ts b/apps/web-antd/src/api/bpm/oa/leave/index.ts index 4172ffbd0..90f6e2602 100644 --- a/apps/web-antd/src/api/bpm/oa/leave/index.ts +++ b/apps/web-antd/src/api/bpm/oa/leave/index.ts @@ -3,6 +3,7 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; export namespace BpmOALeaveApi { + // TODO @ziye:不用 VO 后缀 export interface LeaveVO { id: number; status: number; diff --git a/apps/web-antd/src/api/bpm/processExpression/index.ts b/apps/web-antd/src/api/bpm/processExpression/index.ts index 9444dd26e..3408c38c3 100644 --- a/apps/web-antd/src/api/bpm/processExpression/index.ts +++ b/apps/web-antd/src/api/bpm/processExpression/index.ts @@ -3,7 +3,8 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; export namespace BpmProcessExpressionApi { - /** BPM 流程表达式 VO */ + // TODO @ziye:不用 VO 后缀 + /** 流程表达式 VO */ export interface ProcessExpressionVO { id: number; // 编号 name: string; // 表达式名字 diff --git a/apps/web-antd/src/api/bpm/processInstance/index.ts b/apps/web-antd/src/api/bpm/processInstance/index.ts index 4f9b77959..67a6d9cf6 100644 --- a/apps/web-antd/src/api/bpm/processInstance/index.ts +++ b/apps/web-antd/src/api/bpm/processInstance/index.ts @@ -8,6 +8,7 @@ import type { BpmCandidateStrategyEnum, BpmNodeTypeEnum } from '#/utils'; import { requestClient } from '#/api/request'; export namespace BpmProcessInstanceApi { + // TODO @芋艿:一些注释缺少或者不对; export type Task = { id: number; name: string; @@ -42,7 +43,7 @@ export namespace BpmProcessInstanceApi { tasks: ApprovalTaskInfo[]; }; - // 流程实例 + /** 流程实例 */ export type ProcessInstanceVO = { businessKey: string; category: string; diff --git a/apps/web-antd/src/api/bpm/processListener/index.ts b/apps/web-antd/src/api/bpm/processListener/index.ts index 8d5c05c93..8d93107ac 100644 --- a/apps/web-antd/src/api/bpm/processListener/index.ts +++ b/apps/web-antd/src/api/bpm/processListener/index.ts @@ -3,6 +3,7 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; export namespace BpmProcessListenerApi { + // TODO @ziye:不用 VO 后缀 /** BPM 流程监听器 VO */ export interface ProcessListenerVO { id: number; // 编号 diff --git a/apps/web-antd/src/api/bpm/task/index.ts b/apps/web-antd/src/api/bpm/task/index.ts index 19cbede85..89a8ceede 100644 --- a/apps/web-antd/src/api/bpm/task/index.ts +++ b/apps/web-antd/src/api/bpm/task/index.ts @@ -5,6 +5,7 @@ import type { BpmProcessInstanceApi } from '../processInstance'; import { requestClient } from '#/api/request'; export namespace BpmTaskApi { + // TODO @ziye:不用 VO 后缀;注释使用 /** */ 风格; /** BPM 流程监听器 VO */ export interface TaskVO { id: number; // 编号 diff --git a/apps/web-antd/src/api/bpm/userGroup/index.ts b/apps/web-antd/src/api/bpm/userGroup/index.ts index f4c50f8b0..bae30827e 100644 --- a/apps/web-antd/src/api/bpm/userGroup/index.ts +++ b/apps/web-antd/src/api/bpm/userGroup/index.ts @@ -3,6 +3,7 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; export namespace BpmUserGroupApi { + // TODO @ziye:不用 VO 后缀 /** BPM 用户组 VO */ export interface UserGroupVO { id: number; diff --git a/apps/web-antd/src/api/infra/demo/demo01/index.ts b/apps/web-antd/src/api/infra/demo/demo01/index.ts index d1f646c61..c54a533f3 100644 --- a/apps/web-antd/src/api/infra/demo/demo01/index.ts +++ b/apps/web-antd/src/api/infra/demo/demo01/index.ts @@ -47,8 +47,7 @@ export function deleteDemo01Contact(id: number) { } /** 批量删除示例联系人 */ -// TODO @puhui999:ByIds,这种按照约定,是不带的,针对 Id 的情况哈。 -export function deleteDemo01ContactListByIds(ids: number[]) { +export function deleteDemo01ContactList(ids: number[]) { return requestClient.delete( `/infra/demo01-contact/delete-list?ids=${ids.join(',')}`, ); diff --git a/apps/web-antd/src/api/infra/demo/demo03/erp/index.ts b/apps/web-antd/src/api/infra/demo/demo03/erp/index.ts index ec18150cc..aac1829b7 100644 --- a/apps/web-antd/src/api/infra/demo/demo03/erp/index.ts +++ b/apps/web-antd/src/api/infra/demo/demo03/erp/index.ts @@ -62,7 +62,7 @@ export function deleteDemo03Student(id: number) { } /** 批量删除学生 */ -export function deleteDemo03StudentListByIds(ids: number[]) { +export function deleteDemo03StudentList(ids: number[]) { return requestClient.delete( `/infra/demo03-student-erp/delete-list?ids=${ids.join(',')}`, ); @@ -109,7 +109,7 @@ export function deleteDemo03Course(id: number) { } /** 批量删除学生课程 */ -export function deleteDemo03CourseListByIds(ids: number[]) { +export function deleteDemo03CourseList(ids: number[]) { return requestClient.delete( `/infra/demo03-student-erp/demo03-course/delete-list?ids=${ids.join(',')}`, ); @@ -155,7 +155,7 @@ export function deleteDemo03Grade(id: number) { } /** 批量删除学生班级 */ -export function deleteDemo03GradeListByIds(ids: number[]) { +export function deleteDemo03GradeList(ids: number[]) { return requestClient.delete( `/infra/demo03-student-erp/demo03-grade/delete-list?ids=${ids.join(',')}`, ); diff --git a/apps/web-antd/src/api/infra/demo/demo03/inner/index.ts b/apps/web-antd/src/api/infra/demo/demo03/inner/index.ts index 1521923b2..76b18fc01 100644 --- a/apps/web-antd/src/api/infra/demo/demo03/inner/index.ts +++ b/apps/web-antd/src/api/infra/demo/demo03/inner/index.ts @@ -64,7 +64,7 @@ export function deleteDemo03Student(id: number) { } /** 批量删除学生 */ -export function deleteDemo03StudentListByIds(ids: number[]) { +export function deleteDemo03StudentList(ids: number[]) { return requestClient.delete( `/infra/demo03-student-inner/delete-list?ids=${ids.join(',')}`, ); diff --git a/apps/web-antd/src/api/infra/demo/demo03/normal/index.ts b/apps/web-antd/src/api/infra/demo/demo03/normal/index.ts index 79143c82e..4d22e2e27 100644 --- a/apps/web-antd/src/api/infra/demo/demo03/normal/index.ts +++ b/apps/web-antd/src/api/infra/demo/demo03/normal/index.ts @@ -64,7 +64,7 @@ export function deleteDemo03Student(id: number) { } /** 批量删除学生 */ -export function deleteDemo03StudentListByIds(ids: number[]) { +export function deleteDemo03StudentList(ids: number[]) { return requestClient.delete( `/infra/demo03-student-normal/delete-list?ids=${ids.join(',')}`, ); diff --git a/apps/web-antd/src/api/mall/market/banner/index.ts b/apps/web-antd/src/api/mall/market/banner/index.ts new file mode 100644 index 000000000..9f9b4fab2 --- /dev/null +++ b/apps/web-antd/src/api/mall/market/banner/index.ts @@ -0,0 +1,47 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallBannerApi { + /** Banner 信息 */ + export interface Banner { + id: number; + title: string; + picUrl: string; + status: number; + url: string; + position: number; + sort: number; + memo: string; + } +} + +/** 查询Banner管理列表 */ +export function getBannerPage(params: PageParam) { + return requestClient.get>( + '/promotion/banner/page', + { params }, + ); +} + +/** 查询Banner管理详情 */ +export function getBanner(id: number) { + return requestClient.get( + `/promotion/banner/get?id=${id}`, + ); +} + +/** 新增Banner管理 */ +export function createBanner(data: MallBannerApi.Banner) { + return requestClient.post('/promotion/banner/create', data); +} + +/** 修改Banner管理 */ +export function updateBanner(data: MallBannerApi.Banner) { + return requestClient.put('/promotion/banner/update', data); +} + +/** 删除Banner管理 */ +export function deleteBanner(id: number) { + return requestClient.delete(`/promotion/banner/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/product/brand.ts b/apps/web-antd/src/api/mall/product/brand.ts new file mode 100644 index 000000000..7b82eb728 --- /dev/null +++ b/apps/web-antd/src/api/mall/product/brand.ts @@ -0,0 +1,58 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallBrandApi { + /** 商品品牌 */ + export interface Brand { + /** 品牌编号 */ + id?: number; + /** 品牌名称 */ + name: string; + /** 品牌图片 */ + picUrl: string; + /** 品牌排序 */ + sort?: number; + /** 品牌描述 */ + description?: string; + /** 开启状态 */ + status: number; + } +} + +/** 创建商品品牌 */ +export function createBrand(data: MallBrandApi.Brand) { + return requestClient.post('/product/brand/create', data); +} + +/** 更新商品品牌 */ +export function updateBrand(data: MallBrandApi.Brand) { + return requestClient.put('/product/brand/update', data); +} + +/** 删除商品品牌 */ +export function deleteBrand(id: number) { + return requestClient.delete(`/product/brand/delete?id=${id}`); +} + +/** 获得商品品牌 */ +export function getBrand(id: number) { + return requestClient.get(`/product/brand/get?id=${id}`); +} + +/** 获得商品品牌列表 */ +export function getBrandPage(params: PageParam) { + return requestClient.get>( + '/product/brand/page', + { + params, + }, + ); +} + +/** 获得商品品牌精简信息列表 */ +export function getSimpleBrandList() { + return requestClient.get( + '/product/brand/list-all-simple', + ); +} diff --git a/apps/web-antd/src/api/mall/product/category.ts b/apps/web-antd/src/api/mall/product/category.ts new file mode 100644 index 000000000..f30d6c6b7 --- /dev/null +++ b/apps/web-antd/src/api/mall/product/category.ts @@ -0,0 +1,51 @@ +import { requestClient } from '#/api/request'; + +export namespace MallCategoryApi { + /** 产品分类 */ + export interface Category { + /** 分类编号 */ + id?: number; + /** 父分类编号 */ + parentId?: number; + /** 分类名称 */ + name: string; + /** 移动端分类图 */ + picUrl: string; + /** 分类排序 */ + sort: number; + /** 开启状态 */ + status: number; + } +} + +/** 创建商品分类 */ +export function createCategory(data: MallCategoryApi.Category) { + return requestClient.post('/product/category/create', data); +} + +/** 更新商品分类 */ +export function updateCategory(data: MallCategoryApi.Category) { + return requestClient.put('/product/category/update', data); +} + +/** 删除商品分类 */ +export function deleteCategory(id: number) { + return requestClient.delete(`/product/category/delete?id=${id}`); +} + +/** 获得商品分类 */ +export function getCategory(id: number) { + return requestClient.get( + `/product/category/get?id=${id}`, + ); +} + +/** 获得商品分类列表 */ +export function getCategoryList(params: any) { + return requestClient.get( + '/product/category/list', + { + params, + }, + ); +} diff --git a/apps/web-antd/src/api/mall/product/comment.ts b/apps/web-antd/src/api/mall/product/comment.ts new file mode 100644 index 000000000..8990c2048 --- /dev/null +++ b/apps/web-antd/src/api/mall/product/comment.ts @@ -0,0 +1,81 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallCommentApi { + export interface Property { + propertyId: number; + propertyName: string; + valueId: number; + valueName: string; + } + /** 商品评论 */ + export interface Comment { + id: number; + userId: number; + userNickname: string; + userAvatar: string; + anonymous: boolean; + orderId: number; + orderItemId: number; + spuId: number; + spuName: string; + skuId: number; + visible: boolean; + scores: number; + descriptionScores: number; + benefitScores: number; + content: string; + picUrls: string[]; + replyStatus: boolean; + replyUserId: number; + replyContent: string; + replyTime: Date; + createTime: Date; + skuProperties: Property[]; + } + + /** 评论可见性更新 */ + export interface CommentVisibleUpdate { + id: number; + visible: boolean; + } + + /** 评论回复 */ + export interface CommentReply { + id: number; + replyContent: string; + } +} + +/** 查询商品评论列表 */ +export function getCommentPage(params: PageParam) { + return requestClient.get>( + '/product/comment/page', + { params }, + ); +} + +/** 查询商品评论详情 */ +export function getComment(id: number) { + return requestClient.get( + `/product/comment/get?id=${id}`, + ); +} + +/** 添加自评 */ +export function createComment(data: MallCommentApi.Comment) { + return requestClient.post('/product/comment/create', data); +} + +/** 显示 / 隐藏评论 */ +export function updateCommentVisible( + data: MallCommentApi.CommentVisibleUpdate, +) { + return requestClient.put('/product/comment/update-visible', data); +} + +/** 商家回复 */ +export function replyComment(data: MallCommentApi.CommentReply) { + return requestClient.put('/product/comment/reply', data); +} diff --git a/apps/web-antd/src/api/mall/product/favorite.ts b/apps/web-antd/src/api/mall/product/favorite.ts new file mode 100644 index 000000000..23f38d6bb --- /dev/null +++ b/apps/web-antd/src/api/mall/product/favorite.ts @@ -0,0 +1,23 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallFavoriteApi { + /** 商品收藏 */ + export interface Favorite { + /** 收藏编号 */ + id?: number; + /** 用户编号 */ + userId?: string; + /** 商品 SPU 编号 */ + spuId?: null | number; + } +} + +/** 获得商品收藏列表 */ +export function getFavoritePage(params: PageParam) { + return requestClient.get>( + '/product/favorite/page', + { params }, + ); +} diff --git a/apps/web-antd/src/api/mall/product/history.ts b/apps/web-antd/src/api/mall/product/history.ts new file mode 100644 index 000000000..f8505a738 --- /dev/null +++ b/apps/web-antd/src/api/mall/product/history.ts @@ -0,0 +1,29 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallHistoryApi { + /** 商品浏览记录 */ + export interface BrowseHistory { + /** 记录编号 */ + id?: number; + /** 用户编号 */ + userId?: number; + /** 商品 SPU 编号 */ + spuId?: number; + /** 浏览时间 */ + createTime?: Date; + } +} + +/** + * 获得商品浏览记录分页 + * + * @param params 请求参数 + */ +export function getBrowseHistoryPage(params: PageParam) { + return requestClient.get>( + '/product/browse-history/page', + { params }, + ); +} diff --git a/apps/web-antd/src/api/mall/product/property.ts b/apps/web-antd/src/api/mall/product/property.ts new file mode 100644 index 000000000..e13a700fa --- /dev/null +++ b/apps/web-antd/src/api/mall/product/property.ts @@ -0,0 +1,111 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallPropertyApi { + /** 商品属性 */ + export interface Property { + /** 属性编号 */ + id?: number; + /** 名称 */ + name: string; + /** 备注 */ + remark?: string; + } + + /** 属性值 */ + export interface PropertyValue { + /** 属性值编号 */ + id?: number; + /** 属性项的编号 */ + propertyId?: number; + /** 名称 */ + name: string; + /** 备注 */ + remark?: string; + } + + /** 属性值查询参数 */ + export interface PropertyValueQuery extends PageParam { + propertyId?: number; + } +} + +/** 创建属性项 */ +export function createProperty(data: MallPropertyApi.Property) { + return requestClient.post('/product/property/create', data); +} + +/** 更新属性项 */ +export function updateProperty(data: MallPropertyApi.Property) { + return requestClient.put('/product/property/update', data); +} + +/** 删除属性项 */ +export function deleteProperty(id: number) { + return requestClient.delete(`/product/property/delete?id=${id}`); +} + +/** 获得属性项 */ +export function getProperty(id: number) { + return requestClient.get( + `/product/property/get?id=${id}`, + ); +} + +/** 获得属性项分页 */ +export function getPropertyPage(params: PageParam) { + return requestClient.get>( + '/product/property/page', + { params }, + ); +} + +/** 获得属性项精简列表 */ +export function getPropertySimpleList() { + return requestClient.get( + '/product/property/simple-list', + ); +} + +/** 获得属性值分页 */ +export function getPropertyValuePage( + params: MallPropertyApi.PropertyValueQuery, +) { + return requestClient.get>( + '/product/property/value/page', + { params }, + ); +} + +/** 获得属性值 */ +export function getPropertyValue(id: number) { + return requestClient.get( + `/product/property/value/get?id=${id}`, + ); +} + +/** 创建属性值 */ +export function createPropertyValue(data: MallPropertyApi.PropertyValue) { + return requestClient.post('/product/property/value/create', data); +} + +/** 更新属性值 */ +export function updatePropertyValue(data: MallPropertyApi.PropertyValue) { + return requestClient.put('/product/property/value/update', data); +} + +/** 删除属性值 */ +export function deletePropertyValue(id: number) { + return requestClient.delete(`/product/property/value/delete?id=${id}`); +} + +/** 获得属性值精简列表 */ +export function getPropertyValueSimpleList(propertyId: number) { + return requestClient.get( + '/product/property/value/simple-list', + { + params: { propertyId }, + }, + ); +} diff --git a/apps/web-antd/src/api/mall/product/spu.ts b/apps/web-antd/src/api/mall/product/spu.ts new file mode 100644 index 000000000..e8915e020 --- /dev/null +++ b/apps/web-antd/src/api/mall/product/spu.ts @@ -0,0 +1,177 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallSpuApi { + /** 商品属性 */ + export interface Property { + /** 属性编号 */ + propertyId?: number; + /** 属性名称 */ + propertyName?: string; + /** 属性值编号 */ + valueId?: number; + /** 属性值名称 */ + valueName?: string; + } + + /** 商品 SKU */ + export interface Sku { + /** 商品 SKU 编号 */ + id?: number; + /** 商品 SKU 名称 */ + name?: string; + /** SPU 编号 */ + spuId?: number; + /** 属性数组 */ + properties?: Property[]; + /** 商品价格 */ + price?: number | string; + /** 市场价 */ + marketPrice?: number | string; + /** 成本价 */ + costPrice?: number | string; + /** 商品条码 */ + barCode?: string; + /** 图片地址 */ + picUrl?: string; + /** 库存 */ + stock?: number; + /** 商品重量,单位:kg 千克 */ + weight?: number; + /** 商品体积,单位:m^3 平米 */ + volume?: number; + /** 一级分销的佣金 */ + firstBrokeragePrice?: number | string; + /** 二级分销的佣金 */ + secondBrokeragePrice?: number | string; + /** 商品销量 */ + salesCount?: number; + } + + /** 优惠券模板 */ + export interface GiveCouponTemplate { + /** 优惠券编号 */ + id?: number; + /** 优惠券名称 */ + name?: string; + } + + /** 商品 SPU */ + export interface Spu { + /** 商品编号 */ + id?: number; + /** 商品名称 */ + name?: string; + /** 商品分类 */ + categoryId?: number; + /** 关键字 */ + keyword?: string; + /** 单位 */ + unit?: number | undefined; + /** 商品封面图 */ + picUrl?: string; + /** 商品轮播图 */ + sliderPicUrls?: string[]; + /** 商品简介 */ + introduction?: string; + /** 配送方式 */ + deliveryTypes?: number[]; + /** 运费模版 */ + deliveryTemplateId?: number | undefined; + /** 商品品牌编号 */ + brandId?: number; + /** 商品规格 */ + specType?: boolean; + /** 分销类型 */ + subCommissionType?: boolean; + /** sku数组 */ + skus?: Sku[]; + /** 商品详情 */ + description?: string; + /** 商品排序 */ + sort?: number; + /** 赠送积分 */ + giveIntegral?: number; + /** 虚拟销量 */ + virtualSalesCount?: number; + /** 商品价格 */ + price?: number; + /** 商品拼团价格 */ + combinationPrice?: number; + /** 商品秒杀价格 */ + seckillPrice?: number; + /** 商品销量 */ + salesCount?: number; + /** 市场价 */ + marketPrice?: number; + /** 成本价 */ + costPrice?: number; + /** 商品库存 */ + stock?: number; + /** 商品创建时间 */ + createTime?: Date; + /** 商品状态 */ + status?: number; + } + + /** 商品状态更新 */ + export interface StatusUpdate { + /** 商品编号 */ + id: number; + /** 商品状态 */ + status: number; + } +} + +/** 获得商品 SPU 列表 */ +export function getSpuPage(params: PageParam) { + return requestClient.get>('/product/spu/page', { + params, + }); +} + +/** 获得商品 SPU 列表 tabsCount */ +export function getTabsCount() { + return requestClient.get>('/product/spu/get-count'); +} + +/** 创建商品 SPU */ +export function createSpu(data: MallSpuApi.Spu) { + return requestClient.post('/product/spu/create', data); +} + +/** 更新商品 SPU */ +export function updateSpu(data: MallSpuApi.Spu) { + return requestClient.put('/product/spu/update', data); +} + +/** 更新商品 SPU 状态 */ +export function updateStatus(data: MallSpuApi.StatusUpdate) { + return requestClient.put('/product/spu/update-status', data); +} + +/** 获得商品 SPU */ +export function getSpu(id: number) { + return requestClient.get(`/product/spu/get-detail?id=${id}`); +} + +/** 获得商品 SPU 详情列表 */ +export function getSpuDetailList(ids: number[]) { + return requestClient.get(`/product/spu/list?spuIds=${ids}`); +} + +/** 删除商品 SPU */ +export function deleteSpu(id: number) { + return requestClient.delete(`/product/spu/delete?id=${id}`); +} + +/** 导出商品 SPU Excel */ +export function exportSpu(params: PageParam) { + return requestClient.download('/product/spu/export', { params }); +} + +/** 获得商品 SPU 精简列表 */ +export function getSpuSimpleList() { + return requestClient.get('/product/spu/list-all-simple'); +} diff --git a/apps/web-antd/src/api/mall/promotion/article/index.ts b/apps/web-antd/src/api/mall/promotion/article/index.ts new file mode 100644 index 000000000..9a2ac97d7 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/article/index.ts @@ -0,0 +1,65 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallArticleApi { + /** 文章管理 */ + export interface Article { + /** 文章编号 */ + id: number; + /** 分类编号 */ + categoryId: number; + /** 文章标题 */ + title: string; + /** 作者 */ + author: string; + /** 封面图 */ + picUrl: string; + /** 文章简介 */ + introduction: string; + /** 浏览数量 */ + browseCount: string; + /** 排序 */ + sort: number; + /** 状态 */ + status: number; + /** 商品编号 */ + spuId: number; + /** 是否热门 */ + recommendHot: boolean; + /** 是否轮播图 */ + recommendBanner: boolean; + /** 文章内容 */ + content: string; + } +} + +/** 查询文章管理列表 */ +export function getArticlePage(params: PageParam) { + return requestClient.get>( + '/promotion/article/page', + { params }, + ); +} + +/** 查询文章管理详情 */ +export function getArticle(id: number) { + return requestClient.get( + `/promotion/article/get?id=${id}`, + ); +} + +/** 新增文章管理 */ +export function createArticle(data: MallArticleApi.Article) { + return requestClient.post('/promotion/article/create', data); +} + +/** 修改文章管理 */ +export function updateArticle(data: MallArticleApi.Article) { + return requestClient.put('/promotion/article/update', data); +} + +/** 删除文章管理 */ +export function deleteArticle(id: number) { + return requestClient.delete(`/promotion/article/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/articleCategory/index.ts b/apps/web-antd/src/api/mall/promotion/articleCategory/index.ts new file mode 100644 index 000000000..8bf1cff42 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/articleCategory/index.ts @@ -0,0 +1,60 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallArticleCategoryApi { + /** 文章分类 */ + export interface ArticleCategory { + /** 分类编号 */ + id: number; + /** 分类名称 */ + name: string; + /** 分类图片 */ + picUrl: string; + /** 状态 */ + status: number; + /** 排序 */ + sort: number; + } +} + +/** 查询文章分类列表 */ +export function getArticleCategoryPage(params: PageParam) { + return requestClient.get>( + '/promotion/article-category/page', + { params }, + ); +} + +/** 查询文章分类精简信息列表 */ +export function getSimpleArticleCategoryList() { + return requestClient.get( + '/promotion/article-category/list-all-simple', + ); +} + +/** 查询文章分类详情 */ +export function getArticleCategory(id: number) { + return requestClient.get( + `/promotion/article-category/get?id=${id}`, + ); +} + +/** 新增文章分类 */ +export function createArticleCategory( + data: MallArticleCategoryApi.ArticleCategory, +) { + return requestClient.post('/promotion/article-category/create', data); +} + +/** 修改文章分类 */ +export function updateArticleCategory( + data: MallArticleCategoryApi.ArticleCategory, +) { + return requestClient.put('/promotion/article-category/update', data); +} + +/** 删除文章分类 */ +export function deleteArticleCategory(id: number) { + return requestClient.delete(`/promotion/article-category/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/bargain/bargainActivity.ts b/apps/web-antd/src/api/mall/promotion/bargain/bargainActivity.ts new file mode 100644 index 000000000..c2a3dfdf0 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/bargain/bargainActivity.ts @@ -0,0 +1,106 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { MallSpuApi } from '#/api/mall/product/spu'; + +import { requestClient } from '#/api/request'; + +export namespace MallBargainActivityApi { + /** 砍价活动 */ + export interface BargainActivity { + /** 活动编号 */ + id?: number; + /** 活动名称 */ + name?: string; + /** 开始时间 */ + startTime?: Date; + /** 结束时间 */ + endTime?: Date; + /** 状态 */ + status?: number; + /** 达到该人数,才能砍到低价 */ + helpMaxCount?: number; + /** 最大帮砍次数 */ + bargainCount?: number; + /** 最大购买次数 */ + totalLimitCount?: number; + /** 商品 SPU 编号 */ + spuId: number; + /** 商品 SKU 编号 */ + skuId: number; + /** 砍价起始价格,单位分 */ + bargainFirstPrice: number; + /** 砍价底价 */ + bargainMinPrice: number; + /** 活动库存 */ + stock: number; + /** 用户每次砍价的最小金额,单位:分 */ + randomMinPrice?: number; + /** 用户每次砍价的最大金额,单位:分 */ + randomMaxPrice?: number; + } + + /** 砍价活动所需属性。选择的商品和属性的时候使用方便使用活动的通用封装 */ + export interface BargainProduct { + /** 商品 SPU 编号 */ + spuId: number; + /** 商品 SKU 编号 */ + skuId: number; + /** 砍价起始价格,单位分 */ + bargainFirstPrice: number; + /** 砍价底价 */ + bargainMinPrice: number; + /** 活动库存 */ + stock: number; + } + + /** 扩展 SKU 配置 */ + export type SkuExtension = { + /** 砍价活动配置 */ + productConfig: BargainProduct; + } & MallSpuApi.Sku; + + /** 扩展 SPU 配置 */ + export interface SpuExtension extends MallSpuApi.Spu { + /** SKU 列表 */ + skus: SkuExtension[]; + } +} + +/** 查询砍价活动列表 */ +export function getBargainActivityPage(params: PageParam) { + return requestClient.get>( + '/promotion/bargain-activity/page', + { params }, + ); +} + +/** 查询砍价活动详情 */ +export function getBargainActivity(id: number) { + return requestClient.get( + `/promotion/bargain-activity/get?id=${id}`, + ); +} + +/** 新增砍价活动 */ +export function createBargainActivity( + data: MallBargainActivityApi.BargainActivity, +) { + return requestClient.post('/promotion/bargain-activity/create', data); +} + +/** 修改砍价活动 */ +export function updateBargainActivity( + data: MallBargainActivityApi.BargainActivity, +) { + return requestClient.put('/promotion/bargain-activity/update', data); +} + +/** 关闭砍价活动 */ +export function closeBargainActivity(id: number) { + return requestClient.put(`/promotion/bargain-activity/close?id=${id}`); +} + +/** 删除砍价活动 */ +export function deleteBargainActivity(id: number) { + return requestClient.delete(`/promotion/bargain-activity/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/bargain/bargainHelp.ts b/apps/web-antd/src/api/mall/promotion/bargain/bargainHelp.ts new file mode 100644 index 000000000..c8916b179 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/bargain/bargainHelp.ts @@ -0,0 +1,27 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallBargainHelpApi { + /** 砍价记录 */ + export interface BargainHelp { + /** 记录编号 */ + id: number; + /** 砍价记录编号 */ + record: number; + /** 用户编号 */ + userId: number; + /** 砍掉金额 */ + reducePrice: number; + /** 结束时间 */ + endTime: Date; + } +} + +/** 查询砍价记录列表 */ +export function getBargainHelpPage(params: PageParam) { + return requestClient.get>( + '/promotion/bargain-help/page', + { params }, + ); +} diff --git a/apps/web-antd/src/api/mall/promotion/bargain/bargainRecord.ts b/apps/web-antd/src/api/mall/promotion/bargain/bargainRecord.ts new file mode 100644 index 000000000..880b9def3 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/bargain/bargainRecord.ts @@ -0,0 +1,37 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallBargainRecordApi { + /** 砍价记录 */ + export interface BargainRecord { + /** 记录编号 */ + id: number; + /** 活动编号 */ + activityId: number; + /** 用户编号 */ + userId: number; + /** 商品 SPU 编号 */ + spuId: number; + /** 商品 SKU 编号 */ + skuId: number; + /** 砍价起始价格 */ + bargainFirstPrice: number; + /** 砍价价格 */ + bargainPrice: number; + /** 状态 */ + status: number; + /** 订单编号 */ + orderId: number; + /** 结束时间 */ + endTime: Date; + } +} + +/** 查询砍价记录列表 */ +export function getBargainRecordPage(params: PageParam) { + return requestClient.get>( + '/promotion/bargain-record/page', + { params }, + ); +} diff --git a/apps/web-antd/src/api/mall/promotion/combination/combinationActivity.ts b/apps/web-antd/src/api/mall/promotion/combination/combinationActivity.ts new file mode 100644 index 000000000..c0d53d6b2 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/combination/combinationActivity.ts @@ -0,0 +1,111 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { MallSpuApi } from '#/api/mall/product/spu'; + +import { requestClient } from '#/api/request'; + +export namespace MallCombinationActivityApi { + /** 拼团活动所需属性 */ + export interface CombinationProduct { + /** 商品 SPU 编号 */ + spuId: number; + /** 商品 SKU 编号 */ + skuId: number; + /** 拼团价格 */ + combinationPrice: number; + } + /** 拼团活动 */ + export interface CombinationActivity { + /** 活动编号 */ + id?: number; + /** 活动名称 */ + name?: string; + /** 商品 SPU 编号 */ + spuId?: number; + /** 总限购数量 */ + totalLimitCount?: number; + /** 单次限购数量 */ + singleLimitCount?: number; + /** 开始时间 */ + startTime?: Date; + /** 结束时间 */ + endTime?: Date; + /** 用户数量 */ + userSize?: number; + /** 总数量 */ + totalCount?: number; + /** 成功数量 */ + successCount?: number; + /** 订单用户数量 */ + orderUserCount?: number; + /** 虚拟成团 */ + virtualGroup?: number; + /** 状态 */ + status?: number; + /** 限制时长 */ + limitDuration?: number; + /** 拼团价格 */ + combinationPrice?: number; + /** 商品列表 */ + products: CombinationProduct[]; + } + + /** 扩展 SKU 配置 */ + export type SkuExtension = { + /** 拼团活动配置 */ + productConfig: CombinationProduct; + } & MallSpuApi.Sku; + + /** 扩展 SPU 配置 */ + export interface SpuExtension extends MallSpuApi.Spu { + /** SKU 列表 */ + skus: SkuExtension[]; + } +} + +/** 查询拼团活动列表 */ +export function getCombinationActivityPage(params: PageParam) { + return requestClient.get< + PageResult + >('/promotion/combination-activity/page', { params }); +} + +/** 查询拼团活动详情 */ +export function getCombinationActivity(id: number) { + return requestClient.get( + `/promotion/combination-activity/get?id=${id}`, + ); +} + +/** 获得拼团活动列表,基于活动编号数组 */ +export function getCombinationActivityListByIds(ids: number[]) { + return requestClient.get( + `/promotion/combination-activity/list-by-ids?ids=${ids}`, + ); +} + +/** 新增拼团活动 */ +export function createCombinationActivity( + data: MallCombinationActivityApi.CombinationActivity, +) { + return requestClient.post('/promotion/combination-activity/create', data); +} + +/** 修改拼团活动 */ +export function updateCombinationActivity( + data: MallCombinationActivityApi.CombinationActivity, +) { + return requestClient.put('/promotion/combination-activity/update', data); +} + +/** 关闭拼团活动 */ +export function closeCombinationActivity(id: number) { + return requestClient.put(`/promotion/combination-activity/close?id=${id}`); +} + +/** 删除拼团活动 */ +export function deleteCombinationActivity(id: number) { + return requestClient.delete( + `/promotion/combination-activity/delete?id=${id}`, + ); +} diff --git a/apps/web-antd/src/api/mall/promotion/combination/combinationRecord.ts b/apps/web-antd/src/api/mall/promotion/combination/combinationRecord.ts new file mode 100644 index 000000000..3d2943feb --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/combination/combinationRecord.ts @@ -0,0 +1,61 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallCombinationRecordApi { + /** 拼团记录 */ + export interface CombinationRecord { + /** 拼团记录编号 */ + id: number; + /** 拼团活动编号 */ + activityId: number; + /** 用户昵称 */ + nickname: string; + /** 用户头像 */ + avatar: string; + /** 团长编号 */ + headId: number; + /** 过期时间 */ + expireTime: string; + /** 可参团人数 */ + userSize: number; + /** 已参团人数 */ + userCount: number; + /** 拼团状态 */ + status: number; + /** 商品名字 */ + spuName: string; + /** 商品图片 */ + picUrl: string; + /** 是否虚拟成团 */ + virtualGroup: boolean; + /** 开始时间 (订单付款后开始的时间) */ + startTime: string; + /** 结束时间(成团时间/失败时间) */ + endTime: string; + } + + /** 拼团记录概要信息 */ + export interface RecordSummary { + /** 待成团数量 */ + pendingCount: number; + /** 已成团数量 */ + successCount: number; + /** 已失败数量 */ + failCount: number; + } +} + +/** 查询拼团记录列表 */ +export function getCombinationRecordPage(params: PageParam) { + return requestClient.get< + PageResult + >('/promotion/combination-record/page', { params }); +} + +/** 获得拼团记录的概要信息 */ +export function getCombinationRecordSummary() { + return requestClient.get( + '/promotion/combination-record/get-summary', + ); +} diff --git a/apps/web-antd/src/api/mall/promotion/coupon/coupon.ts b/apps/web-antd/src/api/mall/promotion/coupon/coupon.ts new file mode 100644 index 000000000..6cba23c16 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/coupon/coupon.ts @@ -0,0 +1,67 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallCouponApi { + /** 优惠券 */ + export interface Coupon { + /** 优惠券编号 */ + id: number; + /** 优惠券名称 */ + name: string; + /** 优惠券状态 */ + status: number; + /** 优惠券类型 */ + type: number; + /** 优惠券金额 */ + price: number; + /** 使用门槛 */ + usePrice: number; + /** 商品范围 */ + productScope: number; + /** 商品编号数组 */ + productSpuIds: number[]; + /** 有效期类型 */ + validityType: number; + /** 固定日期-生效开始时间 */ + validStartTime: Date; + /** 固定日期-生效结束时间 */ + validEndTime: Date; + /** 领取日期-开始天数 */ + fixedStartTerm: number; + /** 领取日期-结束天数 */ + fixedEndTerm: number; + /** 每人限领个数 */ + takeLimitCount: number; + /** 是否设置满多少金额可用 */ + usePriceEnabled: boolean; + /** 商品分类编号数组 */ + productCategoryIds: number[]; + } + + /** 发送优惠券 */ + export interface SendCoupon { + /** 优惠券编号 */ + couponId: number; + /** 用户编号数组 */ + userIds: number[]; + } +} + +/** 删除优惠劵 */ +export function deleteCoupon(id: number) { + return requestClient.delete(`/promotion/coupon/delete?id=${id}`); +} + +/** 获得优惠劵分页 */ +export function getCouponPage(params: PageParam) { + return requestClient.get>( + '/promotion/coupon/page', + { params }, + ); +} + +/** 发送优惠券 */ +export function sendCoupon(data: MallCouponApi.SendCoupon) { + return requestClient.post('/promotion/coupon/send', data); +} diff --git a/apps/web-antd/src/api/mall/promotion/coupon/couponTemplate.ts b/apps/web-antd/src/api/mall/promotion/coupon/couponTemplate.ts new file mode 100644 index 000000000..f09455a1c --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/coupon/couponTemplate.ts @@ -0,0 +1,112 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallCouponTemplateApi { + /** 优惠券模板 */ + export interface CouponTemplate { + /** 模板编号 */ + id: number; + /** 模板名称 */ + name: string; + /** 状态 */ + status: number; + /** 发放数量 */ + totalCount: number; + /** 每人限领个数 */ + takeLimitCount: number; + /** 领取方式 */ + takeType: number; + /** 使用门槛 */ + usePrice: number; + /** 商品范围 */ + productScope: number; + /** 商品范围值 */ + productScopeValues: number[]; + /** 有效期类型 */ + validityType: number; + /** 固定日期-生效开始时间 */ + validStartTime: Date; + /** 固定日期-生效结束时间 */ + validEndTime: Date; + /** 领取日期-开始天数 */ + fixedStartTerm: number; + /** 领取日期-结束天数 */ + fixedEndTerm: number; + /** 优惠类型 */ + discountType: number; + /** 折扣百分比 */ + discountPercent: number; + /** 优惠金额 */ + discountPrice: number; + /** 折扣上限 */ + discountLimitPrice: number; + /** 已领取数量 */ + takeCount: number; + /** 已使用数量 */ + useCount: number; + } + + /** 优惠券模板状态更新 */ + export interface StatusUpdate { + /** 模板编号 */ + id: number; + /** 状态 */ + status: 0 | 1; + } +} + +/** 创建优惠劵模板 */ +export function createCouponTemplate( + data: MallCouponTemplateApi.CouponTemplate, +) { + return requestClient.post('/promotion/coupon-template/create', data); +} + +/** 更新优惠劵模板 */ +export function updateCouponTemplate( + data: MallCouponTemplateApi.CouponTemplate, +) { + return requestClient.put('/promotion/coupon-template/update', data); +} + +/** 更新优惠劵模板的状态 */ +export function updateCouponTemplateStatus(id: number, status: 0 | 1) { + const data: MallCouponTemplateApi.StatusUpdate = { id, status }; + return requestClient.put('/promotion/coupon-template/update-status', data); +} + +/** 删除优惠劵模板 */ +export function deleteCouponTemplate(id: number) { + return requestClient.delete(`/promotion/coupon-template/delete?id=${id}`); +} + +/** 获得优惠劵模板 */ +export function getCouponTemplate(id: number) { + return requestClient.get( + `/promotion/coupon-template/get?id=${id}`, + ); +} + +/** 获得优惠劵模板分页 */ +export function getCouponTemplatePage(params: PageParam) { + return requestClient.get>( + '/promotion/coupon-template/page', + { params }, + ); +} + +/** 获得优惠劵模板列表 */ +export function getCouponTemplateList(ids: number[]) { + return requestClient.get( + `/promotion/coupon-template/list?ids=${ids}`, + ); +} + +/** 导出优惠劵模板 Excel */ +export function exportCouponTemplateExcel(params: PageParam) { + return requestClient.get('/promotion/coupon-template/export-excel', { + params, + responseType: 'blob', + }); +} diff --git a/apps/web-antd/src/api/mall/promotion/discount/discountActivity.ts b/apps/web-antd/src/api/mall/promotion/discount/discountActivity.ts new file mode 100644 index 000000000..f1e34ef74 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/discount/discountActivity.ts @@ -0,0 +1,91 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { MallSpuApi } from '#/api/mall/product/spu'; + +import { requestClient } from '#/api/request'; + +export namespace MallDiscountActivityApi { + /** 限时折扣相关属性 */ + export interface DiscountProduct { + /** 商品 SPU 编号 */ + spuId: number; + /** 商品 SKU 编号 */ + skuId: number; + /** 折扣类型 */ + discountType: number; + /** 折扣百分比 */ + discountPercent: number; + /** 折扣价格 */ + discountPrice: number; + } + + /** 限时折扣活动 */ + export interface DiscountActivity { + /** 活动编号 */ + id?: number; + /** 商品 SPU 编号 */ + spuId?: number; + /** 活动名称 */ + name?: string; + /** 状态 */ + status?: number; + /** 备注 */ + remark?: string; + /** 开始时间 */ + startTime?: Date; + /** 结束时间 */ + endTime?: Date; + /** 商品列表 */ + products?: DiscountProduct[]; + } + + /** 扩展 SKU 配置 */ + export type SkuExtension = { + /** 限时折扣配置 */ + productConfig: DiscountProduct; + } & MallSpuApi.Sku; + + /** 扩展 SPU 配置 */ + export interface SpuExtension extends MallSpuApi.Spu { + /** SKU 列表 */ + skus: SkuExtension[]; + } +} + +/** 查询限时折扣活动列表 */ +export function getDiscountActivityPage(params: PageParam) { + return requestClient.get< + PageResult + >('/promotion/discount-activity/page', { params }); +} + +/** 查询限时折扣活动详情 */ +export function getDiscountActivity(id: number) { + return requestClient.get( + `/promotion/discount-activity/get?id=${id}`, + ); +} + +/** 新增限时折扣活动 */ +export function createDiscountActivity( + data: MallDiscountActivityApi.DiscountActivity, +) { + return requestClient.post('/promotion/discount-activity/create', data); +} + +/** 修改限时折扣活动 */ +export function updateDiscountActivity( + data: MallDiscountActivityApi.DiscountActivity, +) { + return requestClient.put('/promotion/discount-activity/update', data); +} + +/** 关闭限时折扣活动 */ +export function closeDiscountActivity(id: number) { + return requestClient.put(`/promotion/discount-activity/close?id=${id}`); +} + +/** 删除限时折扣活动 */ +export function deleteDiscountActivity(id: number) { + return requestClient.delete(`/promotion/discount-activity/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/diy/page.ts b/apps/web-antd/src/api/mall/promotion/diy/page.ts new file mode 100644 index 000000000..daa5e4b06 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/diy/page.ts @@ -0,0 +1,61 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallDiyPageApi { + /** 装修页面 */ + export interface DiyPage { + /** 页面编号 */ + id?: number; + /** 模板编号 */ + templateId?: number; + /** 页面名称 */ + name: string; + /** 备注 */ + remark: string; + /** 预览图片地址数组 */ + previewPicUrls: string[]; + /** 页面属性 */ + property: string; + } +} + +/** 查询装修页面列表 */ +export function getDiyPagePage(params: PageParam) { + return requestClient.get>( + '/promotion/diy-page/page', + { params }, + ); +} + +/** 查询装修页面详情 */ +export function getDiyPage(id: number) { + return requestClient.get( + `/promotion/diy-page/get?id=${id}`, + ); +} + +/** 新增装修页面 */ +export function createDiyPage(data: MallDiyPageApi.DiyPage) { + return requestClient.post('/promotion/diy-page/create', data); +} + +/** 修改装修页面 */ +export function updateDiyPage(data: MallDiyPageApi.DiyPage) { + return requestClient.put('/promotion/diy-page/update', data); +} + +/** 删除装修页面 */ +export function deleteDiyPage(id: number) { + return requestClient.delete(`/promotion/diy-page/delete?id=${id}`); +} + +/** 获得装修页面属性 */ +export function getDiyPageProperty(id: number) { + return requestClient.get(`/promotion/diy-page/get-property?id=${id}`); +} + +/** 更新装修页面属性 */ +export function updateDiyPageProperty(data: MallDiyPageApi.DiyPage) { + return requestClient.put('/promotion/diy-page/update-property', data); +} diff --git a/apps/web-antd/src/api/mall/promotion/diy/template.ts b/apps/web-antd/src/api/mall/promotion/diy/template.ts new file mode 100644 index 000000000..f7d82d352 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/diy/template.ts @@ -0,0 +1,80 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { MallDiyPageApi } from './page'; + +import { requestClient } from '#/api/request'; + +export namespace MallDiyTemplateApi { + /** 装修模板 */ + export interface DiyTemplate { + /** 模板编号 */ + id?: number; + /** 模板名称 */ + name: string; + /** 是否使用 */ + used: boolean; + /** 使用时间 */ + usedTime?: Date; + /** 备注 */ + remark: string; + /** 预览图片地址数组 */ + previewPicUrls: string[]; + /** 模板属性 */ + property: string; + } + + /** 装修模板属性(包含页面列表) */ + export interface DiyTemplateProperty extends DiyTemplate { + /** 页面列表 */ + pages: MallDiyPageApi.DiyPage[]; + } +} + +/** 查询装修模板列表 */ +export function getDiyTemplatePage(params: PageParam) { + return requestClient.get>( + '/promotion/diy-template/page', + { params }, + ); +} + +/** 查询装修模板详情 */ +export function getDiyTemplate(id: number) { + return requestClient.get( + `/promotion/diy-template/get?id=${id}`, + ); +} + +/** 新增装修模板 */ +export function createDiyTemplate(data: MallDiyTemplateApi.DiyTemplate) { + return requestClient.post('/promotion/diy-template/create', data); +} + +/** 修改装修模板 */ +export function updateDiyTemplate(data: MallDiyTemplateApi.DiyTemplate) { + return requestClient.put('/promotion/diy-template/update', data); +} + +/** 删除装修模板 */ +export function deleteDiyTemplate(id: number) { + return requestClient.delete(`/promotion/diy-template/delete?id=${id}`); +} + +/** 使用装修模板 */ +export function useDiyTemplate(id: number) { + return requestClient.put(`/promotion/diy-template/use?id=${id}`); +} + +/** 获得装修模板属性 */ +export function getDiyTemplateProperty(id: number) { + return requestClient.get( + `/promotion/diy-template/get-property?id=${id}`, + ); +} + +/** 更新装修模板属性 */ +export function updateDiyTemplateProperty( + data: MallDiyTemplateApi.DiyTemplate, +) { + return requestClient.put('/promotion/diy-template/update-property', data); +} diff --git a/apps/web-antd/src/api/mall/promotion/kefu/conversation/index.ts b/apps/web-antd/src/api/mall/promotion/kefu/conversation/index.ts new file mode 100644 index 000000000..c2cdaf255 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/kefu/conversation/index.ts @@ -0,0 +1,70 @@ +import type { PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallKefuConversationApi { + /** 客服会话 */ + export interface Conversation { + /** 编号 */ + id: number; + /** 会话所属用户 */ + userId: number; + /** 会话所属用户头像 */ + userAvatar: string; + /** 会话所属用户昵称 */ + userNickname: string; + /** 最后聊天时间 */ + lastMessageTime: Date; + /** 最后聊天内容 */ + lastMessageContent: string; + /** 最后发送的消息类型 */ + lastMessageContentType: number; + /** 管理端置顶 */ + adminPinned: boolean; + /** 用户是否可见 */ + userDeleted: boolean; + /** 管理员是否可见 */ + adminDeleted: boolean; + /** 管理员未读消息数 */ + adminUnreadMessageCount: number; + /** 创建时间 */ + createTime?: string; + } + + /** 会话置顶请求 */ + export interface ConversationPinnedUpdate { + /** 会话编号 */ + id: number; + /** 是否置顶 */ + pinned: boolean; + } +} + +/** 获得客服会话列表 */ +export function getConversationList() { + return requestClient.get>( + '/promotion/kefu-conversation/list', + ); +} + +/** 获得客服会话 */ +export function getConversation(id: number) { + return requestClient.get( + `/promotion/kefu-conversation/get?id=${id}`, + ); +} + +/** 客服会话置顶 */ +export function updateConversationPinned( + data: MallKefuConversationApi.ConversationPinnedUpdate, +) { + return requestClient.put( + '/promotion/kefu-conversation/update-conversation-pinned', + data, + ); +} + +/** 删除客服会话 */ +export function deleteConversation(id: number) { + return requestClient.delete(`/promotion/kefu-conversation/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/kefu/message/index.ts b/apps/web-antd/src/api/mall/promotion/kefu/message/index.ts new file mode 100644 index 000000000..4bf08306e --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/kefu/message/index.ts @@ -0,0 +1,67 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallKefuMessageApi { + /** 客服消息 */ + export interface Message { + /** 编号 */ + id: number; + /** 会话编号 */ + conversationId: number; + /** 发送人编号 */ + senderId: number; + /** 发送人头像 */ + senderAvatar: string; + /** 发送人类型 */ + senderType: number; + /** 接收人编号 */ + receiverId: number; + /** 接收人类型 */ + receiverType: number; + /** 消息类型 */ + contentType: number; + /** 消息内容 */ + content: string; + /** 是否已读 */ + readStatus: boolean; + /** 创建时间 */ + createTime: Date; + } + + /** 发送消息请求 */ + export interface MessageSend { + /** 会话编号 */ + conversationId: number; + /** 消息类型 */ + contentType: number; + /** 消息内容 */ + content: string; + } + + /** 消息列表查询参数 */ + export interface MessageQuery extends PageParam { + /** 会话编号 */ + conversationId: number; + } +} + +/** 发送客服消息 */ +export function sendKeFuMessage(data: MallKefuMessageApi.MessageSend) { + return requestClient.post('/promotion/kefu-message/send', data); +} + +/** 更新客服消息已读状态 */ +export function updateKeFuMessageReadStatus(conversationId: number) { + return requestClient.put( + `/promotion/kefu-message/update-read-status?conversationId=${conversationId}`, + ); +} + +/** 获得消息列表(流式加载) */ +export function getKeFuMessageList(params: MallKefuMessageApi.MessageQuery) { + return requestClient.get>( + '/promotion/kefu-message/list', + { params }, + ); +} diff --git a/apps/web-antd/src/api/mall/promotion/point/index.ts b/apps/web-antd/src/api/mall/promotion/point/index.ts new file mode 100644 index 000000000..dcde0f21d --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/point/index.ts @@ -0,0 +1,127 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { MallSpuApi } from '#/api/mall/product/spu'; + +import { requestClient } from '#/api/request'; + +export namespace MallPointActivityApi { + /** 积分商城商品 */ + export interface PointProduct { + /** 积分商城商品编号 */ + id?: number; + /** 积分商城活动 id */ + activityId?: number; + /** 商品 SPU 编号 */ + spuId?: number; + /** 商品 SKU 编号 */ + skuId: number; + /** 可兑换数量 */ + count: number; + /** 兑换积分 */ + point: number; + /** 兑换金额,单位:分 */ + price: number; + /** 积分商城商品库存 */ + stock: number; + /** 积分商城商品状态 */ + activityStatus?: number; + } + + /** 积分商城活动 */ + export interface PointActivity { + /** 积分商城活动编号 */ + id: number; + /** 积分商城活动商品 */ + spuId: number; + /** 活动状态 */ + status: number; + /** 积分商城活动库存 */ + stock: number; + /** 积分商城活动总库存 */ + totalStock: number; + /** 备注 */ + remark?: string; + /** 排序 */ + sort: number; + /** 创建时间 */ + createTime: string; + /** 积分商城商品 */ + products: PointProduct[]; + /** 商品名称 */ + spuName: string; + /** 商品主图 */ + picUrl: string; + /** 商品市场价,单位:分 */ + marketPrice: number; + /** 兑换积分 */ + point: number; + /** 兑换金额,单位:分 */ + price: number; + } + + /** 扩展 SKU 配置 */ + export type SkuExtension = { + /** 积分商城商品配置 */ + productConfig: PointProduct; + } & MallSpuApi.Sku; + + /** 扩展 SPU 配置 */ + export interface SpuExtension extends MallSpuApi.Spu { + /** SKU 列表 */ + skus: SkuExtension[]; + } + + /** 扩展 SPU 配置(带积分信息) */ + export interface SpuExtensionWithPoint extends MallSpuApi.Spu { + /** 积分商城活动库存 */ + pointStock: number; + /** 积分商城活动总库存 */ + pointTotalStock: number; + /** 兑换积分 */ + point: number; + /** 兑换金额,单位:分 */ + pointPrice: number; + } +} + +/** 查询积分商城活动分页 */ +export function getPointActivityPage(params: PageParam) { + return requestClient.get>( + '/promotion/point-activity/page', + { params }, + ); +} + +/** 查询积分商城活动详情 */ +export function getPointActivity(id: number) { + return requestClient.get( + `/promotion/point-activity/get?id=${id}`, + ); +} + +/** 查询积分商城活动列表,基于活动编号数组 */ +export function getPointActivityListByIds(ids: number[]) { + return requestClient.get( + `/promotion/point-activity/list-by-ids?ids=${ids}`, + ); +} + +/** 新增积分商城活动 */ +export function createPointActivity(data: MallPointActivityApi.PointActivity) { + return requestClient.post('/promotion/point-activity/create', data); +} + +/** 修改积分商城活动 */ +export function updatePointActivity(data: MallPointActivityApi.PointActivity) { + return requestClient.put('/promotion/point-activity/update', data); +} + +/** 删除积分商城活动 */ +export function deletePointActivity(id: number) { + return requestClient.delete(`/promotion/point-activity/delete?id=${id}`); +} + +/** 关闭积分商城活动 */ +export function closePointActivity(id: number) { + return requestClient.put(`/promotion/point-activity/close?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/reward/rewardActivity.ts b/apps/web-antd/src/api/mall/promotion/reward/rewardActivity.ts new file mode 100644 index 000000000..e972daf2e --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/reward/rewardActivity.ts @@ -0,0 +1,88 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallRewardActivityApi { + /** 优惠规则 */ + export interface RewardRule { + /** 满足金额 */ + limit?: number; + /** 优惠金额 */ + discountPrice?: number; + /** 是否包邮 */ + freeDelivery?: boolean; + /** 赠送积分 */ + point: number; + /** 赠送优惠券数量 */ + giveCouponTemplateCounts?: { + [key: number]: number; + }; + } + + /** 满减送活动 */ + export interface RewardActivity { + /** 活动编号 */ + id?: number; + /** 活动名称 */ + name?: string; + /** 开始时间 */ + startTime?: Date; + /** 结束时间 */ + endTime?: Date; + /** 开始和结束时间(仅前端使用) */ + startAndEndTime?: Date[]; + /** 备注 */ + remark?: string; + /** 条件类型 */ + conditionType?: number; + /** 商品范围 */ + productScope?: number; + /** 优惠规则列表 */ + rules: RewardRule[]; + /** 商品范围值(仅表单使用):值为品类编号列表、商品编号列表 */ + productScopeValues?: number[]; + /** 商品分类编号列表(仅表单使用) */ + productCategoryIds?: number[]; + /** 商品 SPU 编号列表(仅表单使用) */ + productSpuIds?: number[]; + } +} + +/** 新增满减送活动 */ +export function createRewardActivity( + data: MallRewardActivityApi.RewardActivity, +) { + return requestClient.post('/promotion/reward-activity/create', data); +} + +/** 更新满减送活动 */ +export function updateRewardActivity( + data: MallRewardActivityApi.RewardActivity, +) { + return requestClient.put('/promotion/reward-activity/update', data); +} + +/** 查询满减送活动列表 */ +export function getRewardActivityPage(params: PageParam) { + return requestClient.get>( + '/promotion/reward-activity/page', + { params }, + ); +} + +/** 查询满减送活动详情 */ +export function getReward(id: number) { + return requestClient.get( + `/promotion/reward-activity/get?id=${id}`, + ); +} + +/** 删除满减送活动 */ +export function deleteRewardActivity(id: number) { + return requestClient.delete(`/promotion/reward-activity/delete?id=${id}`); +} + +/** 关闭满减送活动 */ +export function closeRewardActivity(id: number) { + return requestClient.put(`/promotion/reward-activity/close?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/seckill/seckillActivity.ts b/apps/web-antd/src/api/mall/promotion/seckill/seckillActivity.ts new file mode 100644 index 000000000..5159c90e1 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/seckill/seckillActivity.ts @@ -0,0 +1,117 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { MallSpuApi } from '#/api/mall/product/spu'; + +import { requestClient } from '#/api/request'; + +export namespace MallSeckillActivityApi { + /** 秒杀商品 */ + export interface SeckillProduct { + /** 商品 SKU 编号 */ + skuId: number; + /** 商品 SPU 编号 */ + spuId: number; + /** 秒杀价格 */ + seckillPrice: number; + /** 秒杀库存 */ + stock: number; + } + + /** 秒杀活动 */ + export interface SeckillActivity { + /** 活动编号 */ + id?: number; + /** 商品 SPU 编号 */ + spuId?: number; + /** 活动名称 */ + name?: string; + /** 活动状态 */ + status?: number; + /** 备注 */ + remark?: string; + /** 开始时间 */ + startTime?: Date; + /** 结束时间 */ + endTime?: Date; + /** 排序 */ + sort?: number; + /** 配置编号 */ + configIds?: string; + /** 订单数量 */ + orderCount?: number; + /** 用户数量 */ + userCount?: number; + /** 总金额 */ + totalPrice?: number; + /** 总限购数量 */ + totalLimitCount?: number; + /** 单次限购数量 */ + singleLimitCount?: number; + /** 秒杀库存 */ + stock?: number; + /** 秒杀总库存 */ + totalStock?: number; + /** 秒杀价格 */ + seckillPrice?: number; + /** 秒杀商品列表 */ + products?: SeckillProduct[]; + } + + /** 扩展 SKU 配置 */ + export type SkuExtension = { + /** 秒杀商品配置 */ + productConfig: SeckillProduct; + } & MallSpuApi.Sku; + + /** 扩展 SPU 配置 */ + export interface SpuExtension extends MallSpuApi.Spu { + /** SKU 列表 */ + skus: SkuExtension[]; + } +} + +/** 查询秒杀活动列表 */ +export function getSeckillActivityPage(params: PageParam) { + return requestClient.get>( + '/promotion/seckill-activity/page', + { params }, + ); +} + +/** 查询秒杀活动列表,基于活动编号数组 */ +export function getSeckillActivityListByIds(ids: number[]) { + return requestClient.get( + `/promotion/seckill-activity/list-by-ids?ids=${ids}`, + ); +} + +/** 查询秒杀活动详情 */ +export function getSeckillActivity(id: number) { + return requestClient.get( + `/promotion/seckill-activity/get?id=${id}`, + ); +} + +/** 新增秒杀活动 */ +export function createSeckillActivity( + data: MallSeckillActivityApi.SeckillActivity, +) { + return requestClient.post('/promotion/seckill-activity/create', data); +} + +/** 修改秒杀活动 */ +export function updateSeckillActivity( + data: MallSeckillActivityApi.SeckillActivity, +) { + return requestClient.put('/promotion/seckill-activity/update', data); +} + +/** 关闭秒杀活动 */ +export function closeSeckillActivity(id: number) { + return requestClient.put(`/promotion/seckill-activity/close?id=${id}`); +} + +/** 删除秒杀活动 */ +export function deleteSeckillActivity(id: number) { + return requestClient.delete(`/promotion/seckill-activity/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/promotion/seckill/seckillConfig.ts b/apps/web-antd/src/api/mall/promotion/seckill/seckillConfig.ts new file mode 100644 index 000000000..39be3012e --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/seckill/seckillConfig.ts @@ -0,0 +1,74 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallSeckillConfigApi { + /** 秒杀时段 */ + export interface SeckillConfig { + /** 编号 */ + id: number; + /** 秒杀时段名称 */ + name: string; + /** 开始时间点 */ + startTime: string; + /** 结束时间点 */ + endTime: string; + /** 秒杀轮播图 */ + sliderPicUrls: string[]; + /** 活动状态 */ + status: number; + } + + /** 时段配置状态更新 */ + export interface StatusUpdate { + /** 编号 */ + id: number; + /** 状态 */ + status: number; + } +} + +/** 查询秒杀时段分页 */ +export function getSeckillConfigPage(params: PageParam) { + return requestClient.get>( + '/promotion/seckill-config/page', + { params }, + ); +} + +/** 查询秒杀时段列表 */ +export function getSimpleSeckillConfigList() { + return requestClient.get( + '/promotion/seckill-config/list', + ); +} + +/** 查询秒杀时段详情 */ +export function getSeckillConfig(id: number) { + return requestClient.get( + `/promotion/seckill-config/get?id=${id}`, + ); +} + +/** 新增秒杀时段 */ +export function createSeckillConfig(data: MallSeckillConfigApi.SeckillConfig) { + return requestClient.post('/promotion/seckill-config/create', data); +} + +/** 修改秒杀时段 */ +export function updateSeckillConfig(data: MallSeckillConfigApi.SeckillConfig) { + return requestClient.put('/promotion/seckill-config/update', data); +} + +/** 删除秒杀时段 */ +export function deleteSeckillConfig(id: number) { + return requestClient.delete(`/promotion/seckill-config/delete?id=${id}`); +} + +/** 修改时段配置状态 */ +export function updateSeckillConfigStatus(id: number, status: number) { + return requestClient.put('/promotion/seckill-config/update-status', { + id, + status, + }); +} diff --git a/apps/web-antd/src/api/mall/statistics/common.ts b/apps/web-antd/src/api/mall/statistics/common.ts new file mode 100644 index 000000000..871457086 --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/common.ts @@ -0,0 +1,5 @@ +/** 数据对照 Response VO */ +export interface MallDataComparisonRespVO { + value: T; + reference: T; +} diff --git a/apps/web-antd/src/api/mall/statistics/member.ts b/apps/web-antd/src/api/mall/statistics/member.ts new file mode 100644 index 000000000..c839d5fe2 --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/member.ts @@ -0,0 +1,131 @@ +import type { MallDataComparisonRespVO } from './common'; + +import { formatDate } from '@vben/utils'; + +import { requestClient } from '#/api/request'; + +export namespace MallMemberStatisticsApi { + /** 会员分析 Request VO */ + export interface AnalyseReq { + times: Date[]; + } + + /** 会员分析对照数据 Response VO */ + export interface AnalyseComparison { + registerUserCount: number; + visitUserCount: number; + rechargeUserCount: number; + } + + /** 会员分析 Response VO */ + export interface Analyse { + visitUserCount: number; + orderUserCount: number; + payUserCount: number; + atv: number; + comparison: MallDataComparisonRespVO; + } + + /** 会员地区统计 Response VO */ + export interface AreaStatistics { + areaId: number; + areaName: string; + userCount: number; + orderCreateUserCount: number; + orderPayUserCount: number; + orderPayPrice: number; + } + + /** 会员性别统计 Response VO */ + export interface SexStatistics { + sex: number; + userCount: number; + } + + /** 会员统计 Response VO */ + export interface Summary { + userCount: number; + rechargeUserCount: number; + rechargePrice: number; + expensePrice: number; + } + + /** 会员终端统计 Response VO */ + export interface TerminalStatistics { + terminal: number; + userCount: number; + } + + /** 会员数量统计 Response VO */ + export interface Count { + /** 用户访问量 */ + visitUserCount: string; + /** 注册用户数量 */ + registerUserCount: number; + } + + /** 会员注册数量 Response VO */ + export interface RegisterCount { + date: string; + count: number; + } +} + +/** 查询会员统计 */ +export function getMemberSummary() { + return requestClient.get( + '/statistics/member/summary', + ); +} + +/** 查询会员分析数据 */ +export function getMemberAnalyse(params: MallMemberStatisticsApi.AnalyseReq) { + return requestClient.get( + '/statistics/member/analyse', + { + params: { + times: [formatDate(params.times[0]), formatDate(params.times[1])], + }, + }, + ); +} + +/** 按照省份,查询会员统计列表 */ +export function getMemberAreaStatisticsList() { + return requestClient.get( + '/statistics/member/area-statistics-list', + ); +} + +/** 按照性别,查询会员统计列表 */ +export function getMemberSexStatisticsList() { + return requestClient.get( + '/statistics/member/sex-statistics-list', + ); +} + +/** 按照终端,查询会员统计列表 */ +export function getMemberTerminalStatisticsList() { + return requestClient.get( + '/statistics/member/terminal-statistics-list', + ); +} + +/** 获得用户数量量对照 */ +export function getUserCountComparison() { + return requestClient.get< + MallDataComparisonRespVO + >('/statistics/member/user-count-comparison'); +} + +/** 获得会员注册数量列表 */ +export function getMemberRegisterCountList(beginTime: Date, endTime: Date) { + return requestClient.get( + '/statistics/member/register-count-list', + { + params: { + times: [formatDate(beginTime), formatDate(endTime)], + }, + }, + ); +} diff --git a/apps/web-antd/src/api/mall/statistics/pay.ts b/apps/web-antd/src/api/mall/statistics/pay.ts new file mode 100644 index 000000000..958bfa8b0 --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/pay.ts @@ -0,0 +1,16 @@ +import { requestClient } from '#/api/request'; + +export namespace MallPayStatisticsApi { + /** 支付统计 */ + export interface PaySummaryRespVO { + /** 充值金额,单位分 */ + rechargePrice: number; + } +} + +/** 获取钱包充值金额 */ +export function getWalletRechargePrice() { + return requestClient.get( + '/statistics/pay/summary', + ); +} diff --git a/apps/web-antd/src/api/mall/statistics/product.ts b/apps/web-antd/src/api/mall/statistics/product.ts new file mode 100644 index 000000000..4b0ee9938 --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/product.ts @@ -0,0 +1,68 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import type { MallDataComparisonRespVO } from './common'; + +import { requestClient } from '#/api/request'; + +export namespace MallProductStatisticsApi { + /** 商品统计数据 */ + export interface ProductStatistics { + /** 编号 */ + id: number; + /** 统计日期 */ + day: string; + /** 商品 SPU 编号 */ + spuId: number; + /** 商品 SPU 名称 */ + spuName: string; + /** 商品 SPU 图片 */ + spuPicUrl: string; + /** 浏览次数 */ + browseCount: number; + /** 浏览人数 */ + browseUserCount: number; + /** 收藏次数 */ + favoriteCount: number; + /** 加购次数 */ + cartCount: number; + /** 下单次数 */ + orderCount: number; + /** 支付次数 */ + orderPayCount: number; + /** 支付金额 */ + orderPayPrice: number; + /** 售后次数 */ + afterSaleCount: number; + /** 退款金额 */ + afterSaleRefundPrice: number; + /** 浏览转化率 */ + browseConvertPercent: number; + } +} + +/** 获得商品统计分析 */ +export function getProductStatisticsAnalyse(params: PageParam) { + return requestClient.get< + MallDataComparisonRespVO + >('/statistics/product/analyse', { params }); +} + +/** 获得商品状况明细 */ +export function getProductStatisticsList(params: PageParam) { + return requestClient.get( + '/statistics/product/list', + { params }, + ); +} + +/** 导出获得商品状况明细 Excel */ +export function exportProductStatisticsExcel(params: PageParam) { + return requestClient.download('/statistics/product/export-excel', { params }); +} + +/** 获得商品排行榜分页 */ +export function getProductStatisticsRankPage(params: PageParam) { + return requestClient.get< + PageResult + >('/statistics/product/rank-page', { params }); +} diff --git a/apps/web-antd/src/api/mall/statistics/trade.ts b/apps/web-antd/src/api/mall/statistics/trade.ts new file mode 100644 index 000000000..b4b0195e3 --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/trade.ts @@ -0,0 +1,135 @@ +import type { MallDataComparisonRespVO } from './common'; + +import { formatDate } from '@vben/utils'; + +import { requestClient } from '#/api/request'; + +export namespace MallTradeStatisticsApi { + /** 交易统计 Response VO */ + export interface TradeSummary { + yesterdayOrderCount: number; + monthOrderCount: number; + yesterdayPayPrice: number; + monthPayPrice: number; + } + + /** 交易状况 Request VO */ + export interface TradeTrendReq { + times: [Date, Date]; + } + + /** 交易状况统计 Response VO */ + export interface TradeTrendSummary { + time: string; + turnoverPrice: number; + orderPayPrice: number; + rechargePrice: number; + expensePrice: number; + walletPayPrice: number; + brokerageSettlementPrice: number; + afterSaleRefundPrice: number; + } + + /** 交易订单数量 Response VO */ + export interface TradeOrderCount { + /** 待发货 */ + undelivered?: number; + /** 待核销 */ + pickUp?: number; + /** 退款中 */ + afterSaleApply?: number; + /** 提现待审核 */ + auditingWithdraw?: number; + } + + /** 交易订单统计 Response VO */ + export interface TradeOrderSummary { + /** 支付订单商品数 */ + orderPayCount?: number; + /** 总支付金额,单位:分 */ + orderPayPrice?: number; + } + + /** 订单量趋势统计 Response VO */ + export interface TradeOrderTrend { + /** 日期 */ + date: string; + /** 订单数量 */ + orderPayCount: number; + /** 订单支付金额 */ + orderPayPrice: number; + } +} + +/** 时间参数需要格式化, 确保接口能识别 */ +const formatDateParam = (params: MallTradeStatisticsApi.TradeTrendReq) => { + return { + times: [formatDate(params.times[0]), formatDate(params.times[1])], + } as MallTradeStatisticsApi.TradeTrendReq; +}; + +/** 查询交易统计 */ +export function getTradeStatisticsSummary() { + return requestClient.get< + MallDataComparisonRespVO + >('/statistics/trade/summary'); +} + +/** 获得交易状况统计 */ +export function getTradeStatisticsAnalyse( + params: MallTradeStatisticsApi.TradeTrendReq, +) { + return requestClient.get< + MallDataComparisonRespVO + >('/statistics/trade/analyse', { params: formatDateParam(params) }); +} + +/** 获得交易状况明细 */ +export function getTradeStatisticsList( + params: MallTradeStatisticsApi.TradeTrendReq, +) { + return requestClient.get( + '/statistics/trade/list', + { params: formatDateParam(params) }, + ); +} + +/** 导出交易状况明细 */ +export function exportTradeStatisticsExcel( + params: MallTradeStatisticsApi.TradeTrendReq, +) { + return requestClient.download('/statistics/trade/export-excel', { + params: formatDateParam(params), + }); +} + +/** 获得交易订单数量 */ +export function getOrderCount() { + return requestClient.get( + '/statistics/trade/order-count', + ); +} + +/** 获得交易订单数量对照 */ +export function getOrderComparison() { + return requestClient.get< + MallDataComparisonRespVO + >('/statistics/trade/order-comparison'); +} + +/** 获得订单量趋势统计 */ +export function getOrderCountTrendComparison( + type: number, + beginTime: Date, + endTime: Date, +) { + return requestClient.get< + MallDataComparisonRespVO[] + >('/statistics/trade/order-count-trend', { + params: { + type, + beginTime: formatDate(beginTime), + endTime: formatDate(endTime), + }, + }); +} diff --git a/apps/web-antd/src/api/mall/trade/afterSale/index.ts b/apps/web-antd/src/api/mall/trade/afterSale/index.ts new file mode 100644 index 000000000..95326af01 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/afterSale/index.ts @@ -0,0 +1,127 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallAfterSaleApi { + /** 商品属性 */ + export interface ProductProperty { + /** 属性的编号 */ + propertyId?: null | number; + /** 属性的名称 */ + propertyName?: string; + /** 属性值的编号 */ + valueId?: null | number; + /** 属性值的名称 */ + valueName?: string; + } + + /** 交易售后 */ + export interface AfterSale { + /** 售后编号,主键自增 */ + id?: null | number; + /** 售后单号 */ + no?: string; + /** 退款状态 */ + status?: null | number; + /** 售后方式 */ + way?: null | number; + /** 售后类型 */ + type?: null | number; + /** 用户编号 */ + userId?: null | number; + /** 申请原因 */ + applyReason?: string; + /** 补充描述 */ + applyDescription?: string; + /** 补充凭证图片 */ + applyPicUrls?: string[]; + /** 交易订单编号 */ + orderId?: null | number; + /** 订单流水号 */ + orderNo?: string; + /** 交易订单项编号 */ + orderItemId?: null | number; + /** 商品 SPU 编号 */ + spuId?: null | number; + /** 商品 SPU 名称 */ + spuName?: string; + /** 商品 SKU 编号 */ + skuId?: null | number; + /** 属性数组 */ + properties?: ProductProperty[]; + /** 商品图片 */ + picUrl?: string; + /** 退货商品数量 */ + count?: null | number; + /** 审批时间 */ + auditTime?: Date; + /** 审批人 */ + auditUserId?: null | number; + /** 审批备注 */ + auditReason?: string; + /** 退款金额,单位:分 */ + refundPrice?: null | number; + /** 支付退款编号 */ + payRefundId?: null | number; + /** 退款时间 */ + refundTime?: Date; + /** 退货物流公司编号 */ + logisticsId?: null | number; + /** 退货物流单号 */ + logisticsNo?: string; + /** 退货时间 */ + deliveryTime?: Date; + /** 收货时间 */ + receiveTime?: Date; + /** 收货备注 */ + receiveReason?: string; + } + + /** 拒绝售后请求 */ + export interface DisagreeRequest { + /** 售后编号 */ + id: number; + /** 拒绝原因 */ + reason: string; + } +} + +/** 获得交易售后分页 */ +export function getAfterSalePage(params: PageParam) { + return requestClient.get>( + '/trade/after-sale/page', + { params }, + ); +} + +/** 获得交易售后详情 */ +export function getAfterSale(id: number) { + return requestClient.get( + `/trade/after-sale/get-detail?id=${id}`, + ); +} + +/** 同意售后 */ +export function agree(id: number) { + return requestClient.put(`/trade/after-sale/agree?id=${id}`); +} + +/** 拒绝售后 */ +export function disagree(data: MallAfterSaleApi.DisagreeRequest) { + return requestClient.put('/trade/after-sale/disagree', data); +} + +/** 确认收货 */ +export function receive(id: number) { + return requestClient.put(`/trade/after-sale/receive?id=${id}`); +} + +/** 拒绝收货 */ +export function refuse(id: number) { + return requestClient.put(`/trade/after-sale/refuse?id=${id}`); +} + +/** 确认退款 */ +export function refund(id: number) { + return requestClient.put(`/trade/after-sale/refund?id=${id}`); +} diff --git a/apps/web-antd/src/api/mall/trade/brokerage/record/index.ts b/apps/web-antd/src/api/mall/trade/brokerage/record/index.ts new file mode 100644 index 000000000..86ce41baf --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/brokerage/record/index.ts @@ -0,0 +1,46 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallBrokerageRecordApi { + /** 佣金记录 */ + export interface BrokerageRecord { + /** 编号 */ + id: number; + /** 用户编号 */ + userId: number; + /** 用户昵称 */ + userNickname: string; + /** 用户头像 */ + userAvatar: string; + /** 佣金金额,单位:分 */ + price: number; + /** 佣金类型 */ + type: number; + /** 关联订单编号 */ + orderId: number; + /** 关联订单号 */ + orderNo: string; + /** 创建时间 */ + createTime: Date; + /** 状态 */ + status: number; + /** 结算时间 */ + settlementTime: Date; + } +} + +/** 查询佣金记录列表 */ +export function getBrokerageRecordPage(params: PageParam) { + return requestClient.get>( + '/trade/brokerage-record/page', + { params }, + ); +} + +/** 查询佣金记录详情 */ +export function getBrokerageRecord(id: number) { + return requestClient.get( + `/trade/brokerage-record/get?id=${id}`, + ); +} diff --git a/apps/web-antd/src/api/mall/trade/brokerage/user/index.ts b/apps/web-antd/src/api/mall/trade/brokerage/user/index.ts new file mode 100644 index 000000000..d523f1d6e --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/brokerage/user/index.ts @@ -0,0 +1,97 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallBrokerageUserApi { + /** 分销用户 */ + export interface BrokerageUser { + /** 编号 */ + id: number; + /** 推广员编号 */ + bindUserId: number; + /** 推广员绑定时间 */ + bindUserTime: Date; + /** 是否启用分销 */ + brokerageEnabled: boolean; + /** 分销资格时间 */ + brokerageTime: Date; + /** 可提现金额,单位:分 */ + price: number; + /** 冻结金额,单位:分 */ + frozenPrice: number; + /** 用户昵称 */ + nickname: string; + /** 用户头像 */ + avatar: string; + } + + /** 创建分销用户请求 */ + export interface CreateRequest { + /** 用户编号 */ + userId: number; + } + + /** 修改推广员请求 */ + export interface UpdateBindUserRequest { + /** 用户编号 */ + userId: number; + /** 推广员编号 */ + bindUserId: number; + } + + /** 清除推广员请求 */ + export interface ClearBindUserRequest { + /** 用户编号 */ + userId: number; + } + + /** 修改推广资格请求 */ + export interface UpdateBrokerageEnabledRequest { + /** 用户编号 */ + userId: number; + /** 是否启用分销 */ + brokerageEnabled: boolean; + } +} + +/** 创建分销用户 */ +export function createBrokerageUser(data: MallBrokerageUserApi.CreateRequest) { + return requestClient.post('/trade/brokerage-user/create', data); +} + +/** 查询分销用户列表 */ +export function getBrokerageUserPage(params: PageParam) { + return requestClient.get>( + '/trade/brokerage-user/page', + { params }, + ); +} + +/** 查询分销用户详情 */ +export function getBrokerageUser(id: number) { + return requestClient.get( + `/trade/brokerage-user/get?id=${id}`, + ); +} + +/** 修改推广员 */ +export function updateBindUser( + data: MallBrokerageUserApi.UpdateBindUserRequest, +) { + return requestClient.put('/trade/brokerage-user/update-bind-user', data); +} + +/** 清除推广员 */ +export function clearBindUser(data: MallBrokerageUserApi.ClearBindUserRequest) { + return requestClient.put('/trade/brokerage-user/clear-bind-user', data); +} + +/** 修改推广资格 */ +export function updateBrokerageEnabled( + data: MallBrokerageUserApi.UpdateBrokerageEnabledRequest, +) { + return requestClient.put( + '/trade/brokerage-user/update-brokerage-enable', + data, + ); +} diff --git a/apps/web-antd/src/api/mall/trade/brokerage/withdraw/index.ts b/apps/web-antd/src/api/mall/trade/brokerage/withdraw/index.ts new file mode 100644 index 000000000..08acdb4fc --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/brokerage/withdraw/index.ts @@ -0,0 +1,81 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallBrokerageWithdrawApi { + /** 佣金提现 */ + export interface BrokerageWithdraw { + /** 编号 */ + id: number; + /** 用户编号 */ + userId: number; + /** 提现金额,单位:分 */ + price: number; + /** 手续费,单位:分 */ + feePrice: number; + /** 总金额,单位:分 */ + totalPrice: number; + /** 提现类型 */ + type: number; + /** 用户名称 */ + userName: string; + /** 用户账号 */ + userAccount: string; + /** 银行名称 */ + bankName: string; + /** 银行地址 */ + bankAddress: string; + /** 收款码地址 */ + qrCodeUrl: string; + /** 状态 */ + status: number; + /** 审核备注 */ + auditReason: string; + /** 审核时间 */ + auditTime: Date; + /** 备注 */ + remark: string; + /** 支付转账编号 */ + payTransferId?: number; + /** 转账渠道编码 */ + transferChannelCode?: string; + /** 转账时间 */ + transferTime?: Date; + /** 转账错误信息 */ + transferErrorMsg?: string; + } + + /** 驳回申请请求 */ + export interface RejectRequest { + /** 编号 */ + id: number; + /** 驳回原因 */ + auditReason: string; + } +} + +/** 查询佣金提现列表 */ +export function getBrokerageWithdrawPage(params: PageParam) { + return requestClient.get< + PageResult + >('/trade/brokerage-withdraw/page', { params }); +} + +/** 查询佣金提现详情 */ +export function getBrokerageWithdraw(id: number) { + return requestClient.get( + `/trade/brokerage-withdraw/get?id=${id}`, + ); +} + +/** 佣金提现 - 通过申请 */ +export function approveBrokerageWithdraw(id: number) { + return requestClient.put(`/trade/brokerage-withdraw/approve?id=${id}`); +} + +/** 审核佣金提现 - 驳回申请 */ +export function rejectBrokerageWithdraw( + data: MallBrokerageWithdrawApi.RejectRequest, +) { + return requestClient.put('/trade/brokerage-withdraw/reject', data); +} diff --git a/apps/web-antd/src/api/mall/trade/config/index.ts b/apps/web-antd/src/api/mall/trade/config/index.ts new file mode 100644 index 000000000..de419d290 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/config/index.ts @@ -0,0 +1,33 @@ +import { requestClient } from '#/api/request'; + +export namespace MallTradeConfigApi { + /** 交易中心配置 */ + export interface Config { + id?: number; + afterSaleRefundReasons?: string[]; + afterSaleReturnReasons?: string[]; + deliveryExpressFreeEnabled?: boolean; + deliveryExpressFreePrice?: number; + deliveryPickUpEnabled?: boolean; + brokerageEnabled?: boolean; + brokerageEnabledCondition?: number; + brokerageBindMode?: number; + brokeragePosterUrls?: string; + brokerageFirstPercent?: number; + brokerageSecondPercent?: number; + brokerageWithdrawMinPrice?: number; + brokerageFrozenDays?: number; + brokerageWithdrawTypes?: string; + tencentLbsKey?: string; + } +} + +/** 查询交易中心配置详情 */ +export function getTradeConfig() { + return requestClient.get('/trade/config/get'); +} + +/** 保存交易中心配置 */ +export function saveTradeConfig(data: MallTradeConfigApi.Config) { + return requestClient.put('/trade/config/save', data); +} diff --git a/apps/web-antd/src/api/mall/trade/delivery/express/index.ts b/apps/web-antd/src/api/mall/trade/delivery/express/index.ts new file mode 100644 index 000000000..071dd2f16 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/delivery/express/index.ts @@ -0,0 +1,79 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallDeliveryExpressApi { + /** 快递公司 */ + export interface DeliveryExpress { + /** 编号 */ + id: number; + /** 快递公司编码 */ + code: string; + /** 快递公司名称 */ + name: string; + /** 快递公司 logo */ + logo: string; + /** 排序 */ + sort: number; + /** 状态 */ + status: number; + } + + /** 快递公司精简信息 */ + export interface SimpleDeliveryExpress { + /** 编号 */ + id: number; + /** 快递公司编码 */ + code: string; + /** 快递公司名称 */ + name: string; + } +} + +/** 查询快递公司列表 */ +export function getDeliveryExpressPage(params: PageParam) { + return requestClient.get>( + '/trade/delivery/express/page', + { params }, + ); +} + +/** 查询快递公司详情 */ +export function getDeliveryExpress(id: number) { + return requestClient.get( + `/trade/delivery/express/get?id=${id}`, + ); +} + +/** 获得快递公司精简信息列表 */ +export function getSimpleDeliveryExpressList() { + return requestClient.get( + '/trade/delivery/express/list-all-simple', + ); +} + +/** 新增快递公司 */ +export function createDeliveryExpress( + data: MallDeliveryExpressApi.DeliveryExpress, +) { + return requestClient.post('/trade/delivery/express/create', data); +} + +/** 修改快递公司 */ +export function updateDeliveryExpress( + data: MallDeliveryExpressApi.DeliveryExpress, +) { + return requestClient.put('/trade/delivery/express/update', data); +} + +/** 删除快递公司 */ +export function deleteDeliveryExpress(id: number) { + return requestClient.delete(`/trade/delivery/express/delete?id=${id}`); +} + +/** 导出快递公司 Excel */ +export function exportDeliveryExpress(params: PageParam) { + return requestClient.download('/trade/delivery/express/export-excel', { + params, + }); +} diff --git a/apps/web-antd/src/api/mall/trade/delivery/expressTemplate/index.ts b/apps/web-antd/src/api/mall/trade/delivery/expressTemplate/index.ts new file mode 100644 index 000000000..fa81b169b --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/delivery/expressTemplate/index.ts @@ -0,0 +1,95 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallDeliveryExpressTemplateApi { + /** 运费模板计费 */ + export interface TemplateCharge { + /** 区域编号列表 */ + areaIds: number[]; + /** 首件数量 */ + startCount: number; + /** 首件价格,单位:分 */ + startPrice: number; + /** 续件数量 */ + extraCount: number; + /** 续件价格,单位:分 */ + extraPrice: number; + } + + /** 运费模板包邮 */ + export interface TemplateFree { + /** 区域编号列表 */ + areaIds: number[]; + /** 包邮件数 */ + freeCount: number; + /** 包邮金额,单位:分 */ + freePrice: number; + } + + /** 快递运费模板 */ + export interface ExpressTemplate { + /** 编号 */ + id: number; + /** 模板名称 */ + name: string; + /** 计费方式 */ + chargeMode: number; + /** 排序 */ + sort: number; + /** 计费区域列表 */ + templateCharge: TemplateCharge[]; + /** 包邮区域列表 */ + templateFree: TemplateFree[]; + } + + /** 运费模板精简信息 */ + export interface SimpleTemplate { + /** 编号 */ + id: number; + /** 模板名称 */ + name: string; + } +} + +/** 查询快递运费模板列表 */ +export function getDeliveryExpressTemplatePage(params: PageParam) { + return requestClient.get< + PageResult + >('/trade/delivery/express-template/page', { params }); +} + +/** 查询快递运费模板详情 */ +export function getDeliveryExpressTemplate(id: number) { + return requestClient.get( + `/trade/delivery/express-template/get?id=${id}`, + ); +} + +/** 查询快递运费模板详情 */ +export function getSimpleTemplateList() { + return requestClient.get( + '/trade/delivery/express-template/list-all-simple', + ); +} + +/** 新增快递运费模板 */ +export function createDeliveryExpressTemplate( + data: MallDeliveryExpressTemplateApi.ExpressTemplate, +) { + return requestClient.post('/trade/delivery/express-template/create', data); +} + +/** 修改快递运费模板 */ +export function updateDeliveryExpressTemplate( + data: MallDeliveryExpressTemplateApi.ExpressTemplate, +) { + return requestClient.put('/trade/delivery/express-template/update', data); +} + +/** 删除快递运费模板 */ +export function deleteDeliveryExpressTemplate(id: number) { + return requestClient.delete( + `/trade/delivery/express-template/delete?id=${id}`, + ); +} diff --git a/apps/web-antd/src/api/mall/trade/delivery/pickUpStore/index.ts b/apps/web-antd/src/api/mall/trade/delivery/pickUpStore/index.ts new file mode 100644 index 000000000..fe1d9d395 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/delivery/pickUpStore/index.ts @@ -0,0 +1,94 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallDeliveryPickUpStoreApi { + /** 自提门店 */ + export interface PickUpStore { + /** 编号 */ + id: number; + /** 门店名称 */ + name: string; + /** 门店简介 */ + introduction: string; + /** 联系电话 */ + phone: string; + /** 区域编号 */ + areaId: number; + /** 详细地址 */ + detailAddress: string; + /** 门店 logo */ + logo: string; + /** 营业开始时间 */ + openingTime: string; + /** 营业结束时间 */ + closingTime: string; + /** 纬度 */ + latitude: number; + /** 经度 */ + longitude: number; + /** 状态 */ + status: number; + /** 绑定用户编号组数 */ + verifyUserIds: number[]; + } + + /** 绑定自提店员请求 */ + export interface BindStaffRequest { + id?: number; + /** 门店名称 */ + name: string; + /** 门店编号 */ + storeId: number; + /** 用户编号列表 */ + userIds: number[]; + } +} + +/** 查询自提门店列表 */ +export function getDeliveryPickUpStorePage(params: PageParam) { + return requestClient.get>( + '/trade/delivery/pick-up-store/page', + { params }, + ); +} + +/** 查询自提门店详情 */ +export function getDeliveryPickUpStore(id: number) { + return requestClient.get( + `/trade/delivery/pick-up-store/get?id=${id}`, + ); +} + +/** 查询自提门店精简列表 */ +export function getSimpleDeliveryPickUpStoreList() { + return requestClient.get( + '/trade/delivery/pick-up-store/simple-list', + ); +} + +/** 新增自提门店 */ +export function createDeliveryPickUpStore( + data: MallDeliveryPickUpStoreApi.PickUpStore, +) { + return requestClient.post('/trade/delivery/pick-up-store/create', data); +} + +/** 修改自提门店 */ +export function updateDeliveryPickUpStore( + data: MallDeliveryPickUpStoreApi.PickUpStore, +) { + return requestClient.put('/trade/delivery/pick-up-store/update', data); +} + +/** 删除自提门店 */ +export function deleteDeliveryPickUpStore(id: number) { + return requestClient.delete(`/trade/delivery/pick-up-store/delete?id=${id}`); +} + +/** 绑定自提店员 */ +export function bindStoreStaffId( + data: MallDeliveryPickUpStoreApi.BindStaffRequest, +) { + return requestClient.post('/trade/delivery/pick-up-store/bind', data); +} diff --git a/apps/web-antd/src/api/mall/trade/order/index.ts b/apps/web-antd/src/api/mall/trade/order/index.ts new file mode 100644 index 000000000..6017fa5f5 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/order/index.ts @@ -0,0 +1,298 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MallOrderApi { + /** 商品属性 */ + export interface ProductProperty { + /** 属性的编号 */ + propertyId?: null | number; + /** 属性的名称 */ + propertyName?: string; + /** 属性值的编号 */ + valueId?: null | number; + /** 属性值的名称 */ + valueName?: string; + } + + /** 订单项 */ + export interface OrderItem { + /** 编号 */ + id?: null | number; + /** 用户编号 */ + userId?: null | number; + /** 订单编号 */ + orderId?: null | number; + /** 商品 SPU 编号 */ + spuId?: null | number; + /** 商品 SPU 名称 */ + spuName?: string; + /** 商品 SKU 编号 */ + skuId?: null | number; + /** 商品图片 */ + picUrl?: string; + /** 购买数量 */ + count?: null | number; + /** 商品原价(总) */ + originalPrice?: null | number; + /** 商品原价(单) */ + originalUnitPrice?: null | number; + /** 商品优惠(总) */ + discountPrice?: null | number; + /** 商品实付金额(总) */ + payPrice?: null | number; + /** 子订单分摊金额(总) */ + orderPartPrice?: null | number; + /** 分摊后子订单实付金额(总) */ + orderDividePrice?: null | number; + /** 售后状态 */ + afterSaleStatus?: null | number; + /** 属性数组 */ + properties?: ProductProperty[]; + } + + /** 订单日志 */ + export interface OrderLog { + /** 日志内容 */ + content?: string; + /** 创建时间 */ + createTime?: Date; + /** 用户类型 */ + userType?: number; + } + + /** 订单 */ + export interface Order { + /** 订单编号 */ + id?: null | number; + /** 订单流水号 */ + no?: string; + /** 下单时间 */ + createTime?: Date | null; + /** 订单类型 */ + type?: null | number; + /** 订单来源 */ + terminal?: null | number; + /** 用户编号 */ + userId?: null | number; + /** 用户 IP */ + userIp?: string; + /** 用户备注 */ + userRemark?: string; + /** 订单状态 */ + status?: null | number; + /** 购买的商品数量 */ + productCount?: null | number; + /** 订单完成时间 */ + finishTime?: Date | null; + /** 订单取消时间 */ + cancelTime?: Date | null; + /** 取消类型 */ + cancelType?: null | number; + /** 商家备注 */ + remark?: string; + /** 支付订单编号 */ + payOrderId?: null | number; + /** 是否已支付 */ + payStatus?: boolean; + /** 付款时间 */ + payTime?: Date | null; + /** 支付渠道 */ + payChannelCode?: string; + /** 商品原价(总) */ + totalPrice?: null | number; + /** 订单优惠(总) */ + discountPrice?: null | number; + /** 运费金额 */ + deliveryPrice?: null | number; + /** 订单调价(总) */ + adjustPrice?: null | number; + /** 应付金额(总) */ + payPrice?: null | number; + /** 发货方式 */ + deliveryType?: null | number; + /** 自提门店编号 */ + pickUpStoreId?: number; + /** 自提核销码 */ + pickUpVerifyCode?: string; + /** 配送模板编号 */ + deliveryTemplateId?: null | number; + /** 发货物流公司编号 */ + logisticsId?: null | number; + /** 发货物流单号 */ + logisticsNo?: string; + /** 发货时间 */ + deliveryTime?: Date | null; + /** 收货时间 */ + receiveTime?: Date | null; + /** 收件人名称 */ + receiverName?: string; + /** 收件人手机 */ + receiverMobile?: string; + /** 收件人邮编 */ + receiverPostCode?: null | number; + /** 收件人地区编号 */ + receiverAreaId?: null | number; + /** 收件人地区名字 */ + receiverAreaName?: string; + /** 收件人详细地址 */ + receiverDetailAddress?: string; + /** 售后状态 */ + afterSaleStatus?: null | number; + /** 退款金额 */ + refundPrice?: null | number; + /** 优惠劵编号 */ + couponId?: null | number; + /** 优惠劵减免金额 */ + couponPrice?: null | number; + /** 积分抵扣的金额 */ + pointPrice?: null | number; + /** VIP 减免金额 */ + vipPrice?: null | number; + /** 订单项列表 */ + items?: OrderItem[]; + /** 下单用户信息 */ + user?: { + /** 用户头像 */ + avatar?: string; + /** 用户编号 */ + id?: null | number; + /** 用户昵称 */ + nickname?: string; + }; + /** 推广用户信息 */ + brokerageUser?: { + /** 用户头像 */ + avatar?: string; + /** 用户编号 */ + id?: null | number; + /** 用户昵称 */ + nickname?: string; + }; + /** 订单操作日志 */ + logs?: OrderLog[]; + } + + /** 交易订单统计 */ + export interface OrderSummary { + /** 订单数量 */ + orderCount: number; + /** 订单金额 */ + orderPayPrice: number; + /** 退款单数 */ + afterSaleCount: number; + /** 退款金额 */ + afterSalePrice: number; + } + + /** 订单发货请求 */ + export interface DeliveryRequest { + /** 订单编号 */ + id?: number; + /** 发货方式 */ + expressType: string; + /** 物流公司编号 */ + logisticsId: null | number; + /** 物流编号 */ + logisticsNo: string; + } + + /** 订单备注请求 */ + export interface RemarkRequest { + /** 订单编号 */ + id: number; + /** 备注 */ + remark: string; + } + + /** 订单调价请求 */ + export interface PriceRequest { + /** 订单编号 */ + id: number; + /** 调整金额,单位:分 */ + adjustPrice: number; + } + + /** 订单地址请求 */ + export interface AddressRequest { + /** 订单编号 */ + id: number; + /** 收件人名称 */ + receiverName: string; + /** 收件人手机 */ + receiverMobile: string; + /** 收件人地区编号 */ + receiverAreaId: number; + /** 收件人详细地址 */ + receiverDetailAddress: string; + } +} + +/** 查询交易订单列表 */ +export function getOrderPage(params: PageParam) { + return requestClient.get>( + '/trade/order/page', + { + params, + }, + ); +} + +/** 查询交易订单统计 */ +export function getOrderSummary(params: PageParam) { + return requestClient.get('/trade/order/summary', { + params, + }); +} + +/** 查询交易订单详情 */ +export function getOrder(id: number) { + return requestClient.get( + `/trade/order/get-detail?id=${id}`, + ); +} + +/** 查询交易订单物流详情 */ +export function getExpressTrackList(id: number) { + return requestClient.get(`/trade/order/get-express-track-list?id=${id}`); +} + +/** 订单发货 */ +export function deliveryOrder(data: MallOrderApi.DeliveryRequest) { + return requestClient.put('/trade/order/delivery', data); +} + +/** 订单备注 */ +export function updateOrderRemark(data: MallOrderApi.RemarkRequest) { + return requestClient.put('/trade/order/update-remark', data); +} + +/** 订单调价 */ +export function updateOrderPrice(data: MallOrderApi.PriceRequest) { + return requestClient.put('/trade/order/update-price', data); +} + +/** 修改订单地址 */ +export function updateOrderAddress(data: MallOrderApi.AddressRequest) { + return requestClient.put('/trade/order/update-address', data); +} + +/** 订单核销 */ +export function pickUpOrder(id: number) { + return requestClient.put(`/trade/order/pick-up-by-id?id=${id}`); +} + +/** 订单核销 */ +export function pickUpOrderByVerifyCode(pickUpVerifyCode: string) { + return requestClient.put('/trade/order/pick-up-by-verify-code', { + params: { pickUpVerifyCode }, + }); +} + +/** 查询核销码对应的订单 */ +export function getOrderByPickUpVerifyCode(pickUpVerifyCode: string) { + return requestClient.get( + '/trade/order/get-by-pick-up-verify-code', + { params: { pickUpVerifyCode } }, + ); +} diff --git a/apps/web-antd/src/components/doc-alert/doc-alert.vue b/apps/web-antd/src/components/doc-alert/doc-alert.vue deleted file mode 100644 index 8df454546..000000000 --- a/apps/web-antd/src/components/doc-alert/doc-alert.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/apps/web-antd/src/components/doc-alert/index.ts b/apps/web-antd/src/components/doc-alert/index.ts deleted file mode 100644 index 213351536..000000000 --- a/apps/web-antd/src/components/doc-alert/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DocAlert } from './doc-alert.vue'; diff --git a/apps/web-antd/src/components/select-modal/dept-select-modal.vue b/apps/web-antd/src/components/select-modal/dept-select-modal.vue index 8fc25665e..d3f469f58 100644 --- a/apps/web-antd/src/components/select-modal/dept-select-modal.vue +++ b/apps/web-antd/src/components/select-modal/dept-select-modal.vue @@ -9,7 +9,7 @@ import { ref } from 'vue'; import { useVbenModal } from '@vben/common-ui'; import { handleTree } from '@vben/utils'; -import { Button, Card, Col, Row, Tree } from 'ant-design-vue'; +import { Card, Col, Row, Tree } from 'ant-design-vue'; import { getSimpleDeptList } from '#/api/system/dept'; @@ -41,24 +41,6 @@ const emit = defineEmits<{ confirm: [deptList: SystemDeptApi.Dept[]]; }>(); -// 对话框配置 -const [Modal, modalApi] = useVbenModal({ - title: props.title, - async onOpenChange(isOpen: boolean) { - if (!isOpen) { - resetData(); - return; - } - modalApi.setState({ loading: true }); - try { - deptData.value = await getSimpleDeptList(); - deptTree.value = handleTree(deptData.value) as DataNode[]; - } finally { - modalApi.setState({ loading: false }); - } - }, - destroyOnClose: true, -}); type checkedKeys = number[] | { checked: number[]; halfChecked: number[] }; // 部门树形结构 const deptTree = ref([]); @@ -67,25 +49,56 @@ const selectedDeptIds = ref([]); // 部门数据 const deptData = ref([]); -/** 打开对话框 */ -const open = async (selectedList?: SystemDeptApi.Dept[]) => { - modalApi.open(); - // // 设置已选择的部门 - if (selectedList?.length) { - const selectedIds = selectedList - .map((dept) => dept.id) - .filter((id): id is number => id !== undefined); - selectedDeptIds.value = props.checkStrictly - ? { - checked: selectedIds, - halfChecked: [], - } - : selectedIds; - } -}; +// 对话框配置 +const [Modal, modalApi] = useVbenModal({ + async onConfirm() { + // 获取选中的部门ID + const selectedIds: number[] = Array.isArray(selectedDeptIds.value) + ? selectedDeptIds.value + : selectedDeptIds.value.checked || []; + const deptArray = deptData.value.filter((dept) => + selectedIds.includes(dept.id!), + ); + emit('confirm', deptArray); + // 关闭并提示 + await modalApi.close(); + }, + async onOpenChange(isOpen: boolean) { + if (!isOpen) { + deptTree.value = []; + selectedDeptIds.value = []; + return; + } + // 加载数据 + const data = modalApi.getData(); + if (!data) { + return; + } + modalApi.lock(); + try { + deptData.value = await getSimpleDeptList(); + deptTree.value = handleTree(deptData.value) as DataNode[]; + // // 设置已选择的部门 + if (data.selectedList?.length) { + const selectedIds = data.selectedList + .map((dept: SystemDeptApi.Dept) => dept.id) + .filter((id: number) => id !== undefined); + selectedDeptIds.value = props.checkStrictly + ? { + checked: selectedIds, + halfChecked: [], + } + : selectedIds; + } + } finally { + modalApi.unlock(); + } + }, + destroyOnClose: true, +}); /** 处理选中状态变化 */ -const handleCheck = () => { +function handleCheck() { if (!props.multiple) { // 单选模式下,只保留最后选择的节点 if (Array.isArray(selectedDeptIds.value)) { @@ -106,37 +119,10 @@ const handleCheck = () => { } } } -}; - -/** 提交选择 */ -const handleConfirm = async () => { - // 获取选中的部门ID - const selectedIds: number[] = Array.isArray(selectedDeptIds.value) - ? selectedDeptIds.value - : selectedDeptIds.value.checked || []; - const deptArray = deptData.value.filter((dept) => - selectedIds.includes(dept.id!), - ); - // 关闭并提示 - await modalApi.close(); - emit('confirm', deptArray); -}; - -const handleCancel = () => { - modalApi.close(); -}; - -/** 重置数据 */ -const resetData = () => { - deptTree.value = []; - selectedDeptIds.value = []; -}; - -/** 提供 open 方法,用于打开对话框 */ -defineExpose({ open }); +} diff --git a/apps/web-antd/src/components/select-modal/user-select-modal.vue b/apps/web-antd/src/components/select-modal/user-select-modal.vue index e55cca14c..86d44d25f 100644 --- a/apps/web-antd/src/components/select-modal/user-select-modal.vue +++ b/apps/web-antd/src/components/select-modal/user-select-modal.vue @@ -1,5 +1,6 @@ diff --git a/apps/web-ele/src/components/table-action/typing.ts b/apps/web-ele/src/components/table-action/typing.ts new file mode 100644 index 000000000..7d41b1a23 --- /dev/null +++ b/apps/web-ele/src/components/table-action/typing.ts @@ -0,0 +1,36 @@ +import type { ButtonProps } from 'element-plus'; + +export type ButtonType = + | 'danger' + | 'default' + | 'info' + | 'primary' + | 'success' + | 'text' + | 'warning'; + +export interface PopConfirm { + title: string; + okText?: string; + cancelText?: string; + confirm: () => void; + cancel?: () => void; + icon?: string; + disabled?: boolean; +} + +export interface ActionItem extends Partial { + onClick?: () => void; + type?: ButtonType; + label?: string; + color?: 'error' | 'success' | 'warning'; + icon?: string; + popConfirm?: PopConfirm; + disabled?: boolean; + divider?: boolean; + // 权限编码控制是否显示 + auth?: string[]; + // 业务控制是否显示 + ifShow?: ((action: ActionItem) => boolean) | boolean; + tooltip?: string | { [key: string]: any; content?: string }; +} diff --git a/apps/web-ele/src/components/table-toolbar/index.ts b/apps/web-ele/src/components/table-toolbar/index.ts new file mode 100644 index 000000000..720e3224b --- /dev/null +++ b/apps/web-ele/src/components/table-toolbar/index.ts @@ -0,0 +1 @@ +export { default as TableToolbar } from './table-toolbar.vue'; diff --git a/apps/web-ele/src/components/table-toolbar/table-toolbar.vue b/apps/web-ele/src/components/table-toolbar/table-toolbar.vue new file mode 100644 index 000000000..f2f02e766 --- /dev/null +++ b/apps/web-ele/src/components/table-toolbar/table-toolbar.vue @@ -0,0 +1,75 @@ + + + + diff --git a/apps/web-ele/src/hooks/index.ts b/apps/web-ele/src/hooks/index.ts new file mode 100644 index 000000000..75f01b531 --- /dev/null +++ b/apps/web-ele/src/hooks/index.ts @@ -0,0 +1 @@ +export * from './use-table-toolbar'; diff --git a/apps/web-ele/src/hooks/use-table-toolbar.ts b/apps/web-ele/src/hooks/use-table-toolbar.ts new file mode 100644 index 000000000..c35b3a774 --- /dev/null +++ b/apps/web-ele/src/hooks/use-table-toolbar.ts @@ -0,0 +1,47 @@ +import type { VxeTableInstance, VxeToolbarInstance } from '#/adapter/vxe-table'; +import type { TableToolbar } from '#/components/table-toolbar'; + +import { ref, watch } from 'vue'; + +/** + * vxe 原生工具栏挂载封装 + * 解决每个组件使用 vxe-table 组件时都需要写一遍的问题 + */ +export function useTableToolbar() { + const hiddenSearchBar = ref(false); // 隐藏搜索栏 + const tableToolbarRef = ref>(); + const tableRef = ref(); + const isBound = ref(false); + + /** 挂载 toolbar 工具栏 */ + async function bindTableToolbar() { + const table = tableRef.value; + const tableToolbar = tableToolbarRef.value; + if (table && tableToolbar) { + // 延迟 1 秒,确保 toolbar 组件已经挂载 + setTimeout(async () => { + const toolbar = tableToolbar.getToolbarRef(); + if (!toolbar) { + console.error('[toolbar 挂载失败] Table toolbar not found'); + } + await table.connect(toolbar as VxeToolbarInstance); + isBound.value = true; + }, 1000); // 延迟挂载确保 toolbar 正确挂载 + } + } + + watch( + () => tableRef.value, + async (val) => { + if (!val || isBound.value) return; + await bindTableToolbar(); + }, + { immediate: true }, + ); + + return { + hiddenSearchBar, + tableToolbarRef, + tableRef, + }; +} diff --git a/apps/web-ele/src/locales/langs/en-US/page.json b/apps/web-ele/src/locales/langs/en-US/page.json index e889bfc10..00a8c90b2 100644 --- a/apps/web-ele/src/locales/langs/en-US/page.json +++ b/apps/web-ele/src/locales/langs/en-US/page.json @@ -23,7 +23,8 @@ "cancel": "Cancel", "confirm": "Confirm", "reset": "Reset", - "search": "Search" + "search": "Search", + "more": "More" }, "tenant": { "placeholder": "Please select tenant", diff --git a/apps/web-ele/src/locales/langs/zh-CN/page.json b/apps/web-ele/src/locales/langs/zh-CN/page.json index a7781960b..eefc4924b 100644 --- a/apps/web-ele/src/locales/langs/zh-CN/page.json +++ b/apps/web-ele/src/locales/langs/zh-CN/page.json @@ -23,7 +23,8 @@ "cancel": "取消", "confirm": "确认", "reset": "重置", - "search": "搜索" + "search": "搜索", + "more": "更多" }, "tenant": { "placeholder": "请选择租户", diff --git a/apps/web-ele/src/views/infra/apiAccessLog/index.vue b/apps/web-ele/src/views/infra/apiAccessLog/index.vue index 37ae6ec45..080200b1e 100644 --- a/apps/web-ele/src/views/infra/apiAccessLog/index.vue +++ b/apps/web-ele/src/views/infra/apiAccessLog/index.vue @@ -5,7 +5,7 @@ import type { } from '#/adapter/vxe-table'; import type { InfraApiAccessLogApi } from '#/api/infra/api-access-log'; -import { Page, useVbenModal } from '@vben/common-ui'; +import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; import { Download } from '@vben/icons'; import { downloadFileFromBlobPart } from '@vben/utils'; @@ -16,7 +16,6 @@ import { exportApiAccessLog, getApiAccessLogPage, } from '#/api/infra/api-access-log'; -import { DocAlert } from '#/components/doc-alert'; import { $t } from '#/locales'; import { useGridColumns, useGridFormSchema } from './data'; diff --git a/apps/web-ele/src/views/infra/apiErrorLog/index.vue b/apps/web-ele/src/views/infra/apiErrorLog/index.vue index 1da4d9e8e..863d4d26a 100644 --- a/apps/web-ele/src/views/infra/apiErrorLog/index.vue +++ b/apps/web-ele/src/views/infra/apiErrorLog/index.vue @@ -5,7 +5,7 @@ import type { } from '#/adapter/vxe-table'; import type { InfraApiErrorLogApi } from '#/api/infra/api-error-log'; -import { confirm, Page, useVbenModal } from '@vben/common-ui'; +import { confirm, DocAlert, Page, useVbenModal } from '@vben/common-ui'; import { Download } from '@vben/icons'; import { downloadFileFromBlobPart } from '@vben/utils'; @@ -17,7 +17,6 @@ import { getApiErrorLogPage, updateApiErrorLogStatus, } from '#/api/infra/api-error-log'; -import { DocAlert } from '#/components/doc-alert'; import { $t } from '#/locales'; import { InfraApiErrorLogProcessStatusEnum } from '#/utils'; diff --git a/apps/web-ele/src/views/infra/codegen/data.ts b/apps/web-ele/src/views/infra/codegen/data.ts index b9b354a2a..45c0adb3c 100644 --- a/apps/web-ele/src/views/infra/codegen/data.ts +++ b/apps/web-ele/src/views/infra/codegen/data.ts @@ -350,7 +350,7 @@ export function useGenerationInfoSubTableFormSchema( }, { label: '一对一', - value: 'false', + value: false, }, ], }, diff --git a/apps/web-ele/src/views/infra/codegen/edit/index.vue b/apps/web-ele/src/views/infra/codegen/edit/index.vue index e338334cd..ec090172f 100644 --- a/apps/web-ele/src/views/infra/codegen/edit/index.vue +++ b/apps/web-ele/src/views/infra/codegen/edit/index.vue @@ -131,11 +131,12 @@ getDetail(); v-for="(step, index) in steps" :key="index" :title="step.title" + class="cursor-pointer" + @click="() => (currentStep = index)" />
-
diff --git a/apps/web-ele/src/views/infra/demo/demo01/data.ts b/apps/web-ele/src/views/infra/demo/demo01/data.ts new file mode 100644 index 000000000..b621b9708 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo01/data.ts @@ -0,0 +1,149 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { Demo01ContactApi } from '#/api/infra/demo/demo01'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + rules: 'required', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + }, + { + fieldName: 'birthday', + label: '出生年', + rules: 'required', + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + { + fieldName: 'description', + label: '简介', + rules: 'required', + component: 'RichTextarea', + }, + { + fieldName: 'avatar', + label: '头像', + component: 'ImageUpload', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + placeholder: '请选择性别', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { type: 'checkbox', width: 40 }, + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'sex', + title: '性别', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.SYSTEM_USER_SEX }, + }, + }, + { + field: 'birthday', + title: '出生年', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'description', + title: '简介', + minWidth: 120, + }, + { + field: 'avatar', + title: '头像', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/infra/demo/demo01/index.vue b/apps/web-ele/src/views/infra/demo/demo01/index.vue new file mode 100644 index 000000000..552fc73a3 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo01/index.vue @@ -0,0 +1,185 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo01/modules/form.vue b/apps/web-ele/src/views/infra/demo/demo01/modules/form.vue new file mode 100644 index 000000000..943b97698 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo01/modules/form.vue @@ -0,0 +1,91 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo02/data.ts b/apps/web-ele/src/views/infra/demo/demo02/data.ts new file mode 100644 index 000000000..74430fb28 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo02/data.ts @@ -0,0 +1,120 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { Demo02CategoryApi } from '#/api/infra/demo/demo02'; + +import { handleTree } from '@vben/utils'; + +import { getDemo02CategoryList } from '#/api/infra/demo/demo02'; +import { getRangePickerDefaultProps } 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 getDemo02CategoryList({}); + data.unshift({ + id: 0, + name: '顶级示例分类', + }); + return handleTree(data); + }, + labelField: 'name', + valueField: 'id', + childrenField: 'children', + placeholder: '请选择上级示例分类', + treeDefaultExpandAll: true, + }, + rules: 'selectRequired', + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入名字', + }, + }, + { + fieldName: 'parentId', + label: '父级编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入父级编号', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + treeNode: true, + }, + { + field: 'parentId', + title: '父级编号', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 220, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/infra/demo/demo02/index.vue b/apps/web-ele/src/views/infra/demo/demo02/index.vue new file mode 100644 index 000000000..e92e9aeea --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo02/index.vue @@ -0,0 +1,176 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo02/modules/form.vue b/apps/web-ele/src/views/infra/demo/demo02/modules/form.vue new file mode 100644 index 000000000..bfabb2601 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo02/modules/form.vue @@ -0,0 +1,92 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/erp/data.ts b/apps/web-ele/src/views/infra/demo/demo03/erp/data.ts new file mode 100644 index 000000000..8f202c04b --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/erp/data.ts @@ -0,0 +1,378 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { Demo03StudentApi } from '#/api/infra/demo/demo03/erp'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + rules: 'required', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + }, + { + fieldName: 'birthday', + label: '出生日期', + rules: 'required', + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + { + fieldName: 'description', + label: '简介', + rules: 'required', + component: 'RichTextarea', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + placeholder: '请选择性别', + }, + }, + { + fieldName: 'description', + label: '简介', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入简介', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { type: 'checkbox', width: 40 }, + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'sex', + title: '性别', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.SYSTEM_USER_SEX }, + }, + }, + { + field: 'birthday', + title: '出生日期', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'description', + title: '简介', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +// ==================== 子表(学生课程) ==================== + +/** 新增/修改的表单 */ +export function useDemo03CourseFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'score', + label: '分数', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入分数', + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useDemo03CourseGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'studentId', + label: '学生编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入学生编号', + }, + }, + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入名字', + }, + }, + { + fieldName: 'score', + label: '分数', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入分数', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useDemo03CourseGridColumns(): VxeTableGridOptions['columns'] { + return [ + { type: 'checkbox', width: 40 }, + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'studentId', + title: '学生编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'score', + title: '分数', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +// ==================== 子表(学生班级) ==================== + +/** 新增/修改的表单 */ +export function useDemo03GradeFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'teacher', + label: '班主任', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入班主任', + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useDemo03GradeGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'studentId', + label: '学生编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入学生编号', + }, + }, + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入名字', + }, + }, + { + fieldName: 'teacher', + label: '班主任', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入班主任', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useDemo03GradeGridColumns(): VxeTableGridOptions['columns'] { + return [ + { type: 'checkbox', width: 40 }, + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'studentId', + title: '学生编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'teacher', + title: '班主任', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/infra/demo/demo03/erp/index.vue b/apps/web-ele/src/views/infra/demo/demo03/erp/index.vue new file mode 100644 index 000000000..a7dd4872c --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/erp/index.vue @@ -0,0 +1,207 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-course-form.vue b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-course-form.vue new file mode 100644 index 000000000..91ec7d32c --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-course-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-course-list.vue b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-course-list.vue new file mode 100644 index 000000000..e5af52f2f --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-course-list.vue @@ -0,0 +1,196 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-grade-form.vue b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-grade-form.vue new file mode 100644 index 000000000..db67f321f --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-grade-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-grade-list.vue b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-grade-list.vue new file mode 100644 index 000000000..d230be70a --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/demo03-grade-list.vue @@ -0,0 +1,196 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/erp/modules/form.vue b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/form.vue new file mode 100644 index 000000000..ae0572c6b --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/erp/modules/form.vue @@ -0,0 +1,91 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/inner/data.ts b/apps/web-ele/src/views/infra/demo/demo03/inner/data.ts new file mode 100644 index 000000000..d9d950098 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/inner/data.ts @@ -0,0 +1,272 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { Demo03StudentApi } from '#/api/infra/demo/demo03/inner'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + rules: 'required', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + }, + { + fieldName: 'birthday', + label: '出生日期', + rules: 'required', + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + { + fieldName: 'description', + label: '简介', + rules: 'required', + component: 'RichTextarea', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + placeholder: '请选择性别', + }, + }, + { + fieldName: 'description', + label: '简介', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入简介', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { type: 'checkbox', width: 40 }, + { type: 'expand', width: 80, slots: { content: 'expand_content' } }, + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'sex', + title: '性别', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.SYSTEM_USER_SEX }, + }, + }, + { + field: 'birthday', + title: '出生日期', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'description', + title: '简介', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +// ==================== 子表(学生课程) ==================== + +/** 新增/修改列表的字段 */ +export function useDemo03CourseGridEditColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '名字', + minWidth: 120, + slots: { default: 'name' }, + }, + { + field: 'score', + title: '分数', + minWidth: 120, + slots: { default: 'score' }, + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 列表的字段 */ +export function useDemo03CourseGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'studentId', + title: '学生编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'score', + title: '分数', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + ]; +} +// ==================== 子表(学生班级) ==================== + +/** 新增/修改的表单 */ +export function useDemo03GradeFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'teacher', + label: '班主任', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入班主任', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useDemo03GradeGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'studentId', + title: '学生编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'teacher', + title: '班主任', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + ]; +} diff --git a/apps/web-ele/src/views/infra/demo/demo03/inner/index.vue b/apps/web-ele/src/views/infra/demo/demo03/inner/index.vue new file mode 100644 index 000000000..961444635 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/inner/index.vue @@ -0,0 +1,201 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-course-form.vue b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-course-form.vue new file mode 100644 index 000000000..f42eb6e13 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-course-form.vue @@ -0,0 +1,116 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-course-list.vue b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-course-list.vue new file mode 100644 index 000000000..ce00569da --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-course-list.vue @@ -0,0 +1,56 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-grade-form.vue b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-grade-form.vue new file mode 100644 index 000000000..3e2854608 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-grade-form.vue @@ -0,0 +1,51 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-grade-list.vue b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-grade-list.vue new file mode 100644 index 000000000..fddce42b4 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/demo03-grade-list.vue @@ -0,0 +1,56 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/inner/modules/form.vue b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/form.vue new file mode 100644 index 000000000..c2e1d4de3 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/inner/modules/form.vue @@ -0,0 +1,119 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/normal/data.ts b/apps/web-ele/src/views/infra/demo/demo03/normal/data.ts new file mode 100644 index 000000000..3872175e0 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/normal/data.ts @@ -0,0 +1,208 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + rules: 'required', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + }, + { + fieldName: 'birthday', + label: '出生日期', + rules: 'required', + component: 'DatePicker', + componentProps: { + showTime: true, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + { + fieldName: 'description', + label: '简介', + rules: 'required', + component: 'RichTextarea', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入名字', + }, + }, + { + fieldName: 'sex', + label: '性别', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), + placeholder: '请选择性别', + }, + }, + { + fieldName: 'description', + label: '简介', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入简介', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { type: 'checkbox', width: 40 }, + { + field: 'id', + title: '编号', + minWidth: 120, + }, + { + field: 'name', + title: '名字', + minWidth: 120, + }, + { + field: 'sex', + title: '性别', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.SYSTEM_USER_SEX }, + }, + }, + { + field: 'birthday', + title: '出生日期', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + field: 'description', + title: '简介', + minWidth: 120, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 120, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +// ==================== 子表(学生课程) ==================== + +/** 新增/修改列表的字段 */ +export function useDemo03CourseGridEditColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '名字', + minWidth: 120, + slots: { default: 'name' }, + }, + { + field: 'score', + title: '分数', + minWidth: 120, + slots: { default: 'score' }, + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +// ==================== 子表(学生班级) ==================== + +/** 新增/修改的表单 */ +export function useDemo03GradeFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + }, + { + fieldName: 'teacher', + label: '班主任', + rules: 'required', + component: 'Input', + componentProps: { + placeholder: '请输入班主任', + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/infra/demo/demo03/normal/index.vue b/apps/web-ele/src/views/infra/demo/demo03/normal/index.vue new file mode 100644 index 000000000..1b2ff4045 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/normal/index.vue @@ -0,0 +1,185 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/normal/modules/demo03-course-form.vue b/apps/web-ele/src/views/infra/demo/demo03/normal/modules/demo03-course-form.vue new file mode 100644 index 000000000..c60eb281c --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/normal/modules/demo03-course-form.vue @@ -0,0 +1,116 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/normal/modules/demo03-grade-form.vue b/apps/web-ele/src/views/infra/demo/demo03/normal/modules/demo03-grade-form.vue new file mode 100644 index 000000000..5d5f396bf --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/normal/modules/demo03-grade-form.vue @@ -0,0 +1,51 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/demo03/normal/modules/form.vue b/apps/web-ele/src/views/infra/demo/demo03/normal/modules/form.vue new file mode 100644 index 000000000..fe255a158 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/demo03/normal/modules/form.vue @@ -0,0 +1,119 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo01/index.vue b/apps/web-ele/src/views/infra/demo/general/demo01/index.vue new file mode 100644 index 000000000..4e16a6292 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo01/index.vue @@ -0,0 +1,316 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo01/modules/form.vue b/apps/web-ele/src/views/infra/demo/general/demo01/modules/form.vue new file mode 100644 index 000000000..1f6aa6fc3 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo01/modules/form.vue @@ -0,0 +1,145 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo02/index.vue b/apps/web-ele/src/views/infra/demo/general/demo02/index.vue new file mode 100644 index 000000000..8fbccbf19 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo02/index.vue @@ -0,0 +1,267 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo02/modules/form.vue b/apps/web-ele/src/views/infra/demo/general/demo02/modules/form.vue new file mode 100644 index 000000000..e7743ec72 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo02/modules/form.vue @@ -0,0 +1,138 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/erp/index.vue b/apps/web-ele/src/views/infra/demo/general/demo03/erp/index.vue new file mode 100644 index 000000000..24cdd1d92 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/erp/index.vue @@ -0,0 +1,344 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-course-form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-course-form.vue new file mode 100644 index 000000000..dbabbae53 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-course-form.vue @@ -0,0 +1,114 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-course-list.vue b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-course-list.vue new file mode 100644 index 000000000..69772b7c0 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-course-list.vue @@ -0,0 +1,297 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-grade-form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-grade-form.vue new file mode 100644 index 000000000..62c5a787b --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-grade-form.vue @@ -0,0 +1,114 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-grade-list.vue b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-grade-list.vue new file mode 100644 index 000000000..a1cc8057f --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/demo03-grade-list.vue @@ -0,0 +1,297 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/form.vue new file mode 100644 index 000000000..5c2d21d38 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/erp/modules/form.vue @@ -0,0 +1,139 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/inner/index.vue b/apps/web-ele/src/views/infra/demo/general/demo03/inner/index.vue new file mode 100644 index 000000000..afaab7bc2 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/inner/index.vue @@ -0,0 +1,337 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-course-form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-course-form.vue new file mode 100644 index 000000000..06cea78e3 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-course-form.vue @@ -0,0 +1,95 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-course-list.vue b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-course-list.vue new file mode 100644 index 000000000..90e542d61 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-course-list.vue @@ -0,0 +1,59 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-grade-form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-grade-form.vue new file mode 100644 index 000000000..c399fc3a1 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-grade-form.vue @@ -0,0 +1,67 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-grade-list.vue b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-grade-list.vue new file mode 100644 index 000000000..339606350 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/demo03-grade-list.vue @@ -0,0 +1,59 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/form.vue new file mode 100644 index 000000000..62fc38d97 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/inner/modules/form.vue @@ -0,0 +1,171 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/normal/index.vue b/apps/web-ele/src/views/infra/demo/general/demo03/normal/index.vue new file mode 100644 index 000000000..3a4052163 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/normal/index.vue @@ -0,0 +1,316 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/demo03-course-form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/demo03-course-form.vue new file mode 100644 index 000000000..7547d4606 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/demo03-course-form.vue @@ -0,0 +1,95 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/demo03-grade-form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/demo03-grade-form.vue new file mode 100644 index 000000000..9357c6874 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/demo03-grade-form.vue @@ -0,0 +1,67 @@ + + + diff --git a/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/form.vue b/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/form.vue new file mode 100644 index 000000000..bc0bd8485 --- /dev/null +++ b/apps/web-ele/src/views/infra/demo/general/demo03/normal/modules/form.vue @@ -0,0 +1,171 @@ + + + diff --git a/apps/web-ele/src/views/infra/druid/index.vue b/apps/web-ele/src/views/infra/druid/index.vue index eb91f8d47..60140a5ba 100644 --- a/apps/web-ele/src/views/infra/druid/index.vue +++ b/apps/web-ele/src/views/infra/druid/index.vue @@ -1,10 +1,9 @@ - - diff --git a/apps/web-naive/src/components/doc-alert/index.ts b/apps/web-naive/src/components/doc-alert/index.ts deleted file mode 100644 index 213351536..000000000 --- a/apps/web-naive/src/components/doc-alert/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DocAlert } from './doc-alert.vue'; diff --git a/apps/web-naive/src/views/infra/apiAccessLog/index.vue b/apps/web-naive/src/views/infra/apiAccessLog/index.vue index cc08a3310..ce8937311 100644 --- a/apps/web-naive/src/views/infra/apiAccessLog/index.vue +++ b/apps/web-naive/src/views/infra/apiAccessLog/index.vue @@ -5,7 +5,7 @@ import type { } from '#/adapter/vxe-table'; import type { InfraApiAccessLogApi } from '#/api/infra/api-access-log'; -import { Page, useVbenModal } from '@vben/common-ui'; +import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; import { Download } from '@vben/icons'; import { downloadFileFromBlobPart } from '@vben/utils'; @@ -16,7 +16,6 @@ import { exportApiAccessLog, getApiAccessLogPage, } from '#/api/infra/api-access-log'; -import { DocAlert } from '#/components/doc-alert'; import { $t } from '#/locales'; import { useGridColumns, useGridFormSchema } from './data'; diff --git a/apps/web-naive/src/views/infra/apiErrorLog/index.vue b/apps/web-naive/src/views/infra/apiErrorLog/index.vue index e00ffb269..3f97554ef 100644 --- a/apps/web-naive/src/views/infra/apiErrorLog/index.vue +++ b/apps/web-naive/src/views/infra/apiErrorLog/index.vue @@ -5,7 +5,7 @@ import type { } from '#/adapter/vxe-table'; import type { InfraApiErrorLogApi } from '#/api/infra/api-error-log'; -import { confirm, Page, useVbenModal } from '@vben/common-ui'; +import { confirm, DocAlert, Page, useVbenModal } from '@vben/common-ui'; import { Download } from '@vben/icons'; import { downloadFileFromBlobPart } from '@vben/utils'; @@ -18,7 +18,6 @@ import { getApiErrorLogPage, updateApiErrorLogStatus, } from '#/api/infra/api-error-log'; -import { DocAlert } from '#/components/doc-alert'; import { $t } from '#/locales'; import { InfraApiErrorLogProcessStatusEnum } from '#/utils'; diff --git a/apps/web-naive/src/views/infra/codegen/index.vue b/apps/web-naive/src/views/infra/codegen/index.vue index c0c317274..9dab2ab70 100644 --- a/apps/web-naive/src/views/infra/codegen/index.vue +++ b/apps/web-naive/src/views/infra/codegen/index.vue @@ -10,7 +10,7 @@ import type { InfraDataSourceConfigApi } from '#/api/infra/data-source-config'; import { ref } from 'vue'; import { useRouter } from 'vue-router'; -import { Page, useVbenModal } from '@vben/common-ui'; +import { DocAlert, Page, useVbenModal } from '@vben/common-ui'; import { Plus } from '@vben/icons'; import { NButton } from 'naive-ui'; @@ -24,7 +24,6 @@ import { syncCodegenFromDB, } from '#/api/infra/codegen'; import { getDataSourceConfigList } from '#/api/infra/data-source-config'; -import { DocAlert } from '#/components/doc-alert'; import { $t } from '#/locales'; import { useGridColumns, useGridFormSchema } from './data'; diff --git a/apps/web-naive/src/views/infra/druid/index.vue b/apps/web-naive/src/views/infra/druid/index.vue index eb91f8d47..60140a5ba 100644 --- a/apps/web-naive/src/views/infra/druid/index.vue +++ b/apps/web-naive/src/views/infra/druid/index.vue @@ -1,10 +1,9 @@ + diff --git a/apps/web-ele/src/components/doc-alert/index.ts b/packages/effects/common-ui/src/components/doc-alert/index.ts similarity index 68% rename from apps/web-ele/src/components/doc-alert/index.ts rename to packages/effects/common-ui/src/components/doc-alert/index.ts index 213351536..9f90d3d49 100644 --- a/apps/web-ele/src/components/doc-alert/index.ts +++ b/packages/effects/common-ui/src/components/doc-alert/index.ts @@ -1 +1,2 @@ export { default as DocAlert } from './doc-alert.vue'; +export * from './types'; diff --git a/packages/effects/common-ui/src/components/doc-alert/types.ts b/packages/effects/common-ui/src/components/doc-alert/types.ts new file mode 100644 index 000000000..8ac5dfaa7 --- /dev/null +++ b/packages/effects/common-ui/src/components/doc-alert/types.ts @@ -0,0 +1,4 @@ +export interface DocAlertProps { + title: string; + url: string; +} diff --git a/packages/effects/common-ui/src/components/index.ts b/packages/effects/common-ui/src/components/index.ts index fc50391ed..f1609b1c8 100644 --- a/packages/effects/common-ui/src/components/index.ts +++ b/packages/effects/common-ui/src/components/index.ts @@ -2,6 +2,7 @@ export * from './api-component'; export * from './captcha'; export * from './col-page'; export * from './count-to'; +export * from './doc-alert'; export * from './ellipsis-text'; export * from './icon-picker'; export * from './json-viewer'; diff --git a/packages/effects/common-ui/src/components/page/page.vue b/packages/effects/common-ui/src/components/page/page.vue index 1a6ca913b..31c944ba9 100644 --- a/packages/effects/common-ui/src/components/page/page.vue +++ b/packages/effects/common-ui/src/components/page/page.vue @@ -63,7 +63,7 @@ onMounted(() => { ref="docRef" :class=" cn( - 'bg-card border-border relative flex items-end rounded-md border-b p-4', + 'bg-card border-border relative flex items-start rounded-md border-b p-1', ) " > diff --git a/packages/effects/hooks/src/use-hover-toggle.ts b/packages/effects/hooks/src/use-hover-toggle.ts index 491b1f587..8b1addeb9 100644 --- a/packages/effects/hooks/src/use-hover-toggle.ts +++ b/packages/effects/hooks/src/use-hover-toggle.ts @@ -8,19 +8,40 @@ import { isFunction } from '@vben/utils'; import { useElementHover } from '@vueuse/core'; +interface HoverDelayOptions { + /** 鼠标进入延迟时间 */ + enterDelay?: (() => number) | number; + /** 鼠标离开延迟时间 */ + leaveDelay?: (() => number) | number; +} + +const DEFAULT_LEAVE_DELAY = 500; // 鼠标离开延迟时间,默认为 500ms +const DEFAULT_ENTER_DELAY = 0; // 鼠标进入延迟时间,默认为 0(立即响应) + /** * 监测鼠标是否在元素内部,如果在元素内部则返回 true,否则返回 false * @param refElement 所有需要检测的元素。如果提供了一个数组,那么鼠标在任何一个元素内部都会返回 true - * @param delay 延迟更新状态的时间 + * @param delay 延迟更新状态的时间,可以是数字或包含进入/离开延迟的配置对象 * @returns 返回一个数组,第一个元素是一个 ref,表示鼠标是否在元素内部,第二个元素是一个控制器,可以通过 enable 和 disable 方法来控制监听器的启用和禁用 */ export function useHoverToggle( refElement: Arrayable, - delay: (() => number) | number = 500, + delay: (() => number) | HoverDelayOptions | number = DEFAULT_LEAVE_DELAY, ) { + // 兼容旧版本API + const normalizedOptions: HoverDelayOptions = + typeof delay === 'number' || isFunction(delay) + ? { enterDelay: DEFAULT_ENTER_DELAY, leaveDelay: delay } + : { + enterDelay: DEFAULT_ENTER_DELAY, + leaveDelay: DEFAULT_LEAVE_DELAY, + ...delay, + }; + const isHovers: Array> = []; const value = ref(false); - const timer = ref | undefined>(); + const enterTimer = ref | undefined>(); + const leaveTimer = ref | undefined>(); const refs = Array.isArray(refElement) ? refElement : [refElement]; refs.forEach((refEle) => { const eleRef = computed(() => { @@ -32,15 +53,47 @@ export function useHoverToggle( }); const isOutsideAll = computed(() => isHovers.every((v) => !v.value)); + function clearTimers() { + if (enterTimer.value) { + clearTimeout(enterTimer.value); + enterTimer.value = undefined; + } + if (leaveTimer.value) { + clearTimeout(leaveTimer.value); + leaveTimer.value = undefined; + } + } + function setValueDelay(val: boolean) { - timer.value && clearTimeout(timer.value); - timer.value = setTimeout( - () => { - value.value = val; - timer.value = undefined; - }, - isFunction(delay) ? delay() : delay, - ); + clearTimers(); + + if (val) { + // 鼠标进入 + const enterDelay = normalizedOptions.enterDelay ?? DEFAULT_ENTER_DELAY; + const delayTime = isFunction(enterDelay) ? enterDelay() : enterDelay; + + if (delayTime <= 0) { + value.value = true; + } else { + enterTimer.value = setTimeout(() => { + value.value = true; + enterTimer.value = undefined; + }, delayTime); + } + } else { + // 鼠标离开 + const leaveDelay = normalizedOptions.leaveDelay ?? DEFAULT_LEAVE_DELAY; + const delayTime = isFunction(leaveDelay) ? leaveDelay() : leaveDelay; + + if (delayTime <= 0) { + value.value = false; + } else { + leaveTimer.value = setTimeout(() => { + value.value = false; + leaveTimer.value = undefined; + }, delayTime); + } + } } const watcher = watch( @@ -61,7 +114,7 @@ export function useHoverToggle( }; onUnmounted(() => { - timer.value && clearTimeout(timer.value); + clearTimers(); }); return [value, controller] as [typeof value, typeof controller]; diff --git a/packages/effects/plugins/src/vxe-table/api.ts b/packages/effects/plugins/src/vxe-table/api.ts index 50879b674..2b60d602e 100644 --- a/packages/effects/plugins/src/vxe-table/api.ts +++ b/packages/effects/plugins/src/vxe-table/api.ts @@ -26,14 +26,14 @@ function getDefaultState(): VxeGridProps { }; } -export class VxeGridApi { +export class VxeGridApi = any> { public formApi = {} as ExtendedFormApi; // private prevState: null | VxeGridProps = null; - public grid = {} as VxeGridInstance; - public state: null | VxeGridProps = null; + public grid = {} as VxeGridInstance; + public state: null | VxeGridProps = null; - public store: Store; + public store: Store>; private isMounted = false; @@ -99,8 +99,8 @@ export class VxeGridApi { setState( stateOrFn: - | ((prev: VxeGridProps) => Partial) - | Partial, + | ((prev: VxeGridProps) => Partial>) + | Partial>, ) { if (isFunction(stateOrFn)) { this.store.setState((prev) => { diff --git a/packages/effects/plugins/src/vxe-table/types.ts b/packages/effects/plugins/src/vxe-table/types.ts index da8a014c0..8b9aea47d 100644 --- a/packages/effects/plugins/src/vxe-table/types.ts +++ b/packages/effects/plugins/src/vxe-table/types.ts @@ -9,7 +9,7 @@ import type { Ref } from 'vue'; import type { ClassType, DeepPartial } from '@vben/types'; -import type { VbenFormProps } from '@vben-core/form-ui'; +import type { BaseFormComponentType, VbenFormProps } from '@vben-core/form-ui'; import type { VxeGridApi } from './api'; @@ -35,7 +35,11 @@ export interface SeparatorOptions { show?: boolean; backgroundColor?: string; } -export interface VxeGridProps { + +export interface VxeGridProps< + T extends Record = any, + D extends BaseFormComponentType = BaseFormComponentType, +> { /** * 标题 */ @@ -55,15 +59,15 @@ export interface VxeGridProps { /** * vxe-grid 配置 */ - gridOptions?: DeepPartial; + gridOptions?: DeepPartial>; /** * vxe-grid 事件 */ - gridEvents?: DeepPartial; + gridEvents?: DeepPartial>; /** * 表单配置 */ - formOptions?: VbenFormProps; + formOptions?: VbenFormProps; /** * 显示搜索表单 */ @@ -74,9 +78,12 @@ export interface VxeGridProps { separator?: boolean | SeparatorOptions; } -export type ExtendedVxeGridApi = VxeGridApi & { - useStore: >( - selector?: (state: NoInfer) => T, +export type ExtendedVxeGridApi< + D extends Record = any, + F extends BaseFormComponentType = BaseFormComponentType, +> = VxeGridApi & { + useStore: >>( + selector?: (state: NoInfer>) => T, ) => Readonly>; }; diff --git a/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts b/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts index b15435ed1..e69ae35b5 100644 --- a/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts +++ b/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts @@ -1,3 +1,5 @@ +import type { BaseFormComponentType } from '@vben-core/form-ui'; + import type { ExtendedVxeGridApi, VxeGridProps } from './types'; import { defineComponent, h, onBeforeUnmount } from 'vue'; @@ -7,16 +9,19 @@ import { useStore } from '@vben-core/shared/store'; import { VxeGridApi } from './api'; import VxeGrid from './use-vxe-grid.vue'; -export function useVbenVxeGrid(options: VxeGridProps) { +export function useVbenVxeGrid< + T extends Record = any, + D extends BaseFormComponentType = BaseFormComponentType, +>(options: VxeGridProps) { // const IS_REACTIVE = isReactive(options); const api = new VxeGridApi(options); - const extendedApi: ExtendedVxeGridApi = api as ExtendedVxeGridApi; + const extendedApi: ExtendedVxeGridApi = api as ExtendedVxeGridApi; extendedApi.useStore = (selector) => { return useStore(api.store, selector); }; const Grid = defineComponent( - (props: VxeGridProps, { attrs, slots }) => { + (props: VxeGridProps, { attrs, slots }) => { onBeforeUnmount(() => { api.unmount(); }); diff --git a/packages/effects/request/src/request-client/modules/uploader.ts b/packages/effects/request/src/request-client/modules/uploader.ts index de251ca8c..1353222ab 100644 --- a/packages/effects/request/src/request-client/modules/uploader.ts +++ b/packages/effects/request/src/request-client/modules/uploader.ts @@ -1,6 +1,8 @@ import type { RequestClient } from '../request-client'; import type { RequestClientConfig } from '../types'; +import { isUndefined } from '@vben/utils'; + class FileUploader { private client: RequestClient; @@ -18,10 +20,10 @@ class FileUploader { Object.entries(data).forEach(([key, value]) => { if (Array.isArray(value)) { value.forEach((item, index) => { - formData.append(`${key}[${index}]`, item); + !isUndefined(item) && formData.append(`${key}[${index}]`, item); }); } else { - formData.append(key, value); + !isUndefined(value) && formData.append(key, value); } }); diff --git a/packages/utils/src/helpers/get-popup-container.ts b/packages/utils/src/helpers/get-popup-container.ts index 589f6ede2..5ebb6f207 100644 --- a/packages/utils/src/helpers/get-popup-container.ts +++ b/packages/utils/src/helpers/get-popup-container.ts @@ -9,6 +9,7 @@ export function getPopupContainer(node?: HTMLElement): HTMLElement { ); } +// TODO @xingyu:这个需要 pr 给 vben 官方么?体感上,这个是全局性的哈; /** * VxeTable专用弹窗层 * 解决问题: https://gitee.com/dapppp/ruoyi-plus-vben5/issues/IB1DM3 diff --git a/playground/src/adapter/vxe-table.ts b/playground/src/adapter/vxe-table.ts index 71a0ecb49..24dfd4cdc 100644 --- a/playground/src/adapter/vxe-table.ts +++ b/playground/src/adapter/vxe-table.ts @@ -1,10 +1,16 @@ +import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { Recordable } from '@vben/types'; +import type { ComponentType } from './component'; + import { h } from 'vue'; import { IconifyIcon } from '@vben/icons'; import { $te } from '@vben/locales'; -import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; +import { + setupVbenVxeTable, + useVbenVxeGrid as useGrid, +} from '@vben/plugins/vxe-table'; import { get, isFunction, isString } from '@vben/utils'; import { objectOmit } from '@vueuse/core'; @@ -42,7 +48,7 @@ setupVbenVxeTable({ round: true, showOverflow: true, size: 'small', - }, + } as VxeTableGridOptions, }); /** @@ -277,7 +283,10 @@ setupVbenVxeTable({ useVbenForm, }); -export { useVbenVxeGrid }; +export const useVbenVxeGrid = >( + ...rest: Parameters> +) => useGrid(...rest); + export type OnActionClickParams> = { code: string; row: T; diff --git a/playground/src/views/examples/vxe-table/basic.vue b/playground/src/views/examples/vxe-table/basic.vue index 1216468d4..d20472461 100644 --- a/playground/src/views/examples/vxe-table/basic.vue +++ b/playground/src/views/examples/vxe-table/basic.vue @@ -43,7 +43,22 @@ const gridEvents: VxeGridListeners = { }, }; -const [Grid, gridApi] = useVbenVxeGrid({ gridEvents, gridOptions }); +const [Grid, gridApi] = useVbenVxeGrid({ + // 放开注释查看表单组件的类型 + // formOptions: { + // schema: [ + // { + // component: 'Switch', + // fieldName: 'name', + // }, + // ], + // }, + gridEvents, + gridOptions, +}); + +// 放开注释查看当前表格实例的类型 +// gridApi.grid const showBorder = gridApi.useStore((state) => state.gridOptions?.border); const showStripe = gridApi.useStore((state) => state.gridOptions?.stripe); diff --git a/playground/src/views/system/menu/modules/form.vue b/playground/src/views/system/menu/modules/form.vue index 6701a2e59..3cf40e356 100644 --- a/playground/src/views/system/menu/modules/form.vue +++ b/playground/src/views/system/menu/modules/form.vue @@ -241,10 +241,10 @@ const schema: VbenFormSchema[] = [ component: 'Input', dependencies: { rules: (values) => { - return values.type === 'action' ? 'required' : null; + return values.type === 'button' ? 'required' : null; }, show: (values) => { - return ['action', 'catalog', 'embedded', 'menu'].includes(values.type); + return ['button', 'catalog', 'embedded', 'menu'].includes(values.type); }, triggerFields: ['type'], }, @@ -277,7 +277,7 @@ const schema: VbenFormSchema[] = [ }, dependencies: { show: (values) => { - return values.type !== 'action'; + return values.type !== 'button'; }, triggerFields: ['type'], }, @@ -295,7 +295,7 @@ const schema: VbenFormSchema[] = [ }, dependencies: { show: (values) => { - return values.type !== 'action'; + return values.type !== 'button'; }, triggerFields: ['type'], }, @@ -314,7 +314,7 @@ const schema: VbenFormSchema[] = [ }, dependencies: { show: (values) => { - return values.type !== 'action'; + return values.type !== 'button'; }, triggerFields: ['type'], }, @@ -325,7 +325,7 @@ const schema: VbenFormSchema[] = [ component: 'Divider', dependencies: { show: (values) => { - return !['action', 'link'].includes(values.type); + return !['button', 'link'].includes(values.type); }, triggerFields: ['type'], }, @@ -372,7 +372,7 @@ const schema: VbenFormSchema[] = [ component: 'Checkbox', dependencies: { show: (values) => { - return !['action'].includes(values.type); + return !['button'].includes(values.type); }, triggerFields: ['type'], }, @@ -402,7 +402,7 @@ const schema: VbenFormSchema[] = [ component: 'Checkbox', dependencies: { show: (values) => { - return !['action', 'link'].includes(values.type); + return !['button', 'link'].includes(values.type); }, triggerFields: ['type'], }, @@ -417,7 +417,7 @@ const schema: VbenFormSchema[] = [ component: 'Checkbox', dependencies: { show: (values) => { - return !['action', 'link'].includes(values.type); + return !['button', 'link'].includes(values.type); }, triggerFields: ['type'], },