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 00000000..362a649d --- /dev/null +++ b/apps/web-antd/src/api/mall/market/banner/index.ts @@ -0,0 +1,49 @@ + + +import { requestClient } from '#/api/request'; +import {PageParam} from "#/api/types"; +import {PageResult} from "#/api/common"; + +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 00000000..d4c25b96 --- /dev/null +++ b/apps/web-antd/src/api/mall/product/brand.ts @@ -0,0 +1,58 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..f30d6c6b --- /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 00000000..90605dea --- /dev/null +++ b/apps/web-antd/src/api/mall/product/comment.ts @@ -0,0 +1,81 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..cc8d2f0b --- /dev/null +++ b/apps/web-antd/src/api/mall/product/favorite.ts @@ -0,0 +1,23 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..28b5766a --- /dev/null +++ b/apps/web-antd/src/api/mall/product/history.ts @@ -0,0 +1,29 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..ec0d89bc --- /dev/null +++ b/apps/web-antd/src/api/mall/product/property.ts @@ -0,0 +1,111 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..5ddb390c --- /dev/null +++ b/apps/web-antd/src/api/mall/product/spu.ts @@ -0,0 +1,177 @@ +import type { PageParam, PageResult } from '../../../types'; + +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-excel', { 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 00000000..74b6fd47 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/article/index.ts @@ -0,0 +1,65 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..68e8e86a --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/articleCategory/index.ts @@ -0,0 +1,60 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..75a433bc --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/bargain/bargainActivity.ts @@ -0,0 +1,106 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..30685912 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/bargain/bargainHelp.ts @@ -0,0 +1,27 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..d7759c32 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/bargain/bargainRecord.ts @@ -0,0 +1,37 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..4b81116e --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/combination/combinationActivity.ts @@ -0,0 +1,111 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..6d89780c --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/combination/combinationRecord.ts @@ -0,0 +1,61 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..164f4d71 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/coupon/coupon.ts @@ -0,0 +1,67 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..c96ce635 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/coupon/couponTemplate.ts @@ -0,0 +1,112 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..75fd5568 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/discount/discountActivity.ts @@ -0,0 +1,91 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..a781505b --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/diy/page.ts @@ -0,0 +1,61 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..3c155463 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/diy/template.ts @@ -0,0 +1,80 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..c2cdaf25 --- /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 00000000..02db10cb --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/kefu/message/index.ts @@ -0,0 +1,67 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..10f493e5 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/point/index.ts @@ -0,0 +1,127 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..e3a7c7aa --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/reward/rewardActivity.ts @@ -0,0 +1,88 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..6e82bf7d --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/seckill/seckillActivity.ts @@ -0,0 +1,117 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..23b6c1d9 --- /dev/null +++ b/apps/web-antd/src/api/mall/promotion/seckill/seckillConfig.ts @@ -0,0 +1,74 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..bb474b5c --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/common.ts @@ -0,0 +1,5 @@ +/** 数据对照 Response */ +export interface MallDataComparisonResp { + 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 00000000..fb7a6b01 --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/member.ts @@ -0,0 +1,131 @@ +import type { MallDataComparisonResp } from './common'; + +import { formatDate } from '@vben/utils'; + +import { requestClient } from '#/api/request'; + +export namespace MallMemberStatisticsApi { + /** 会员分析 Request */ + export interface AnalyseReq { + times: Date[]; + } + + /** 会员分析对照数据 Response */ + export interface AnalyseComparison { + registerUserCount: number; + visitUserCount: number; + rechargeUserCount: number; + } + + /** 会员分析 Response */ + export interface Analyse { + visitUserCount: number; + orderUserCount: number; + payUserCount: number; + atv: number; + comparison: MallDataComparisonResp; + } + + /** 会员地区统计 Response */ + export interface AreaStatistics { + areaId: number; + areaName: string; + userCount: number; + orderCreateUserCount: number; + orderPayUserCount: number; + orderPayPrice: number; + } + + /** 会员性别统计 Response */ + export interface SexStatistics { + sex: number; + userCount: number; + } + + /** 会员统计 Response */ + export interface Summary { + userCount: number; + rechargeUserCount: number; + rechargePrice: number; + expensePrice: number; + } + + /** 会员终端统计 Response */ + export interface TerminalStatistics { + terminal: number; + userCount: number; + } + + /** 会员数量统计 Response */ + export interface Count { + /** 用户访问量 */ + visitUserCount: string; + /** 注册用户数量 */ + registerUserCount: number; + } + + /** 会员注册数量 Response */ + 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< + MallDataComparisonResp + >('/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 00000000..d78ea034 --- /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 PaySummaryResp { + /** 充值金额,单位分 */ + 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 00000000..ee9a800e --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/product.ts @@ -0,0 +1,68 @@ +import type { PageParam, PageResult } from '../../../types'; + +import type { MallDataComparisonResp } 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< + MallDataComparisonResp + >('/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 00000000..1f866c63 --- /dev/null +++ b/apps/web-antd/src/api/mall/statistics/trade.ts @@ -0,0 +1,135 @@ +import type { MallDataComparisonResp } from './common'; + +import { formatDate } from '@vben/utils'; + +import { requestClient } from '#/api/request'; + +export namespace MallTradeStatisticsApi { + /** 交易统计 Response */ + export interface TradeSummary { + yesterdayOrderCount: number; + monthOrderCount: number; + yesterdayPayPrice: number; + monthPayPrice: number; + } + + /** 交易状况 Request */ + export interface TradeTrendReq { + times: [Date, Date]; + } + + /** 交易状况统计 Response */ + export interface TradeTrendSummary { + time: string; + turnoverPrice: number; + orderPayPrice: number; + rechargePrice: number; + expensePrice: number; + walletPayPrice: number; + brokerageSettlementPrice: number; + afterSaleRefundPrice: number; + } + + /** 交易订单数量 Response */ + export interface TradeOrderCount { + /** 待发货 */ + undelivered?: number; + /** 待核销 */ + pickUp?: number; + /** 退款中 */ + afterSaleApply?: number; + /** 提现待审核 */ + auditingWithdraw?: number; + } + + /** 交易订单统计 Response */ + export interface TradeOrderSummary { + /** 支付订单商品数 */ + orderPayCount?: number; + /** 总支付金额,单位:分 */ + orderPayPrice?: number; + } + + /** 订单量趋势统计 Response */ + 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< + MallDataComparisonResp + >('/statistics/trade/summary'); +} + +/** 获得交易状况统计 */ +export function getTradeStatisticsAnalyse( + params: MallTradeStatisticsApi.TradeTrendReq, +) { + return requestClient.get< + MallDataComparisonResp + >('/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< + MallDataComparisonResp + >('/statistics/trade/order-comparison'); +} + +/** 获得订单量趋势统计 */ +export function getOrderCountTrendComparison( + type: number, + beginTime: Date, + endTime: Date, +) { + return requestClient.get< + MallDataComparisonResp[] + >('/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 00000000..9882ef51 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/afterSale/index.ts @@ -0,0 +1,127 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..2fc85e81 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/brokerage/record/index.ts @@ -0,0 +1,46 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..98a5bc6f --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/brokerage/user/index.ts @@ -0,0 +1,99 @@ +import type { PageParam, PageResult } from '../../../types'; + +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; + /** 推广员编号 */ + bindUserId: number; + } + + /** 修改推广员请求 */ + export interface UpdateBindUserRequest { + /** 用户编号 */ + id: number; + /** 推广员编号 */ + bindUserId: number; + } + + /** 清除推广员请求 */ + export interface ClearBindUserRequest { + /** 用户编号 */ + id: number; + } + + /** 修改推广资格请求 */ + export interface UpdateBrokerageEnabledRequest { + /** 用户编号 */ + id: number; + /** 是否启用分销 */ + enabled: 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 00000000..0ec41107 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/brokerage/withdraw/index.ts @@ -0,0 +1,81 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..de419d29 --- /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 00000000..44950f4b --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/delivery/express/index.ts @@ -0,0 +1,79 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..96dc93d1 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/delivery/expressTemplate/index.ts @@ -0,0 +1,95 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..07e37354 --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/delivery/pickUpStore/index.ts @@ -0,0 +1,94 @@ +import type { PageParam, PageResult } from '../../../types'; + +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 00000000..cc5695be --- /dev/null +++ b/apps/web-antd/src/api/mall/trade/order/index.ts @@ -0,0 +1,298 @@ +import type { PageParam, PageResult } from '../../../types'; + +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/api/types.ts b/apps/web-antd/src/api/types.ts new file mode 100644 index 00000000..291b50d4 --- /dev/null +++ b/apps/web-antd/src/api/types.ts @@ -0,0 +1,15 @@ +interface PageParam { + [key: string]: any; + pageNo: number; + pageSize: number; +} + +interface PageResult { + list: T[]; + total: number; +} + +export type { + PageParam, + PageResult +}; diff --git a/apps/web-antd/src/utils/utils/constants.ts b/apps/web-antd/src/utils/utils/constants.ts new file mode 100644 index 00000000..ac3c6128 --- /dev/null +++ b/apps/web-antd/src/utils/utils/constants.ts @@ -0,0 +1,1190 @@ +// todo @芋艿:要不要共享 +/** + * Created by 芋道源码 + * + * 枚举类 + */ + +/** + * AI 平台的枚举 + */ +export const AiPlatformEnum = { + TONG_YI: 'TongYi', // 阿里 + YI_YAN: 'YiYan', // 百度 + DEEP_SEEK: 'DeepSeek', // DeepSeek + ZHI_PU: 'ZhiPu', // 智谱 AI + XING_HUO: 'XingHuo', // 讯飞 + SiliconFlow: 'SiliconFlow', // 硅基流动 + OPENAI: 'OpenAI', + Ollama: 'Ollama', + STABLE_DIFFUSION: 'StableDiffusion', // Stability AI + MIDJOURNEY: 'Midjourney', // Midjourney + SUNO: 'Suno', // Suno AI +}; + +export const AiModelTypeEnum = { + CHAT: 1, // 聊天 + IMAGE: 2, // 图像 + VOICE: 3, // 音频 + VIDEO: 4, // 视频 + EMBEDDING: 5, // 向量 + RERANK: 6, // 重排 +}; +export interface ImageModel { + key: string; + name: string; + image?: string; +} +export const OtherPlatformEnum: ImageModel[] = [ + { + key: AiPlatformEnum.TONG_YI, + name: '通义万相', + }, + { + key: AiPlatformEnum.YI_YAN, + name: '百度千帆', + }, + { + key: AiPlatformEnum.ZHI_PU, + name: '智谱 AI', + }, + { + key: AiPlatformEnum.SiliconFlow, + name: '硅基流动', + }, +]; +/** + * AI 图像生成状态的枚举 + */ +export const AiImageStatusEnum = { + IN_PROGRESS: 10, // 进行中 + SUCCESS: 20, // 已完成 + FAIL: 30, // 已失败 +}; +/** + * AI 音乐生成状态的枚举 + */ +export const AiMusicStatusEnum = { + IN_PROGRESS: 10, // 进行中 + SUCCESS: 20, // 已完成 + FAIL: 30, // 已失败 +}; + +/** + * AI 写作类型的枚举 + */ +export enum AiWriteTypeEnum { + WRITING = 1, // 撰写 + REPLY, // 回复 +} + +// ========== 【图片 UI】相关的枚举 ========== + +export const ImageHotWords = [ + '中国旗袍', + '古装美女', + '卡通头像', + '机甲战士', + '童话小屋', + '中国长城', +]; // 图片热词 + +export const ImageHotEnglishWords = [ + 'Chinese Cheongsam', + 'Ancient Beauty', + 'Cartoon Avatar', + 'Mech Warrior', + 'Fairy Tale Cottage', + 'The Great Wall of China', +]; // 图片热词(英文) + +export const StableDiffusionSamplers: ImageModel[] = [ + { + key: 'DDIM', + name: 'DDIM', + }, + { + key: 'DDPM', + name: 'DDPM', + }, + { + key: 'K_DPMPP_2M', + name: 'K_DPMPP_2M', + }, + { + key: 'K_DPMPP_2S_ANCESTRAL', + name: 'K_DPMPP_2S_ANCESTRAL', + }, + { + key: 'K_DPM_2', + name: 'K_DPM_2', + }, + { + key: 'K_DPM_2_ANCESTRAL', + name: 'K_DPM_2_ANCESTRAL', + }, + { + key: 'K_EULER', + name: 'K_EULER', + }, + { + key: 'K_EULER_ANCESTRAL', + name: 'K_EULER_ANCESTRAL', + }, + { + key: 'K_HEUN', + name: 'K_HEUN', + }, + { + key: 'K_LMS', + name: 'K_LMS', + }, +]; + +export const StableDiffusionStylePresets: ImageModel[] = [ + { + key: '3d-model', + name: '3d-model', + }, + { + key: 'analog-film', + name: 'analog-film', + }, + { + key: 'anime', + name: 'anime', + }, + { + key: 'cinematic', + name: 'cinematic', + }, + { + key: 'comic-book', + name: 'comic-book', + }, + { + key: 'digital-art', + name: 'digital-art', + }, + { + key: 'enhance', + name: 'enhance', + }, + { + key: 'fantasy-art', + name: 'fantasy-art', + }, + { + key: 'isometric', + name: 'isometric', + }, + { + key: 'line-art', + name: 'line-art', + }, + { + key: 'low-poly', + name: 'low-poly', + }, + { + key: 'modeling-compound', + name: 'modeling-compound', + }, + // neon-punk origami photographic pixel-art tile-texture + { + key: 'neon-punk', + name: 'neon-punk', + }, + { + key: 'origami', + name: 'origami', + }, + { + key: 'photographic', + name: 'photographic', + }, + { + key: 'pixel-art', + name: 'pixel-art', + }, + { + key: 'tile-texture', + name: 'tile-texture', + }, +]; + +export const StableDiffusionClipGuidancePresets: ImageModel[] = [ + { + key: 'NONE', + name: 'NONE', + }, + { + key: 'FAST_BLUE', + name: 'FAST_BLUE', + }, + { + key: 'FAST_GREEN', + name: 'FAST_GREEN', + }, + { + key: 'SIMPLE', + name: 'SIMPLE', + }, + { + key: 'SLOW', + name: 'SLOW', + }, + { + key: 'SLOWER', + name: 'SLOWER', + }, + { + key: 'SLOWEST', + name: 'SLOWEST', + }, +]; +// ========== COMMON 模块 ========== +// 全局通用状态枚举 +export const CommonStatusEnum = { + ENABLE: 0, // 开启 + DISABLE: 1, // 禁用 +}; + +// 全局用户类型枚举 +export const UserTypeEnum = { + MEMBER: 1, // 会员 + ADMIN: 2, // 管理员 +}; + +// ========== SYSTEM 模块 ========== +/** + * 菜单的类型枚举 + */ +export const SystemMenuTypeEnum = { + DIR: 1, // 目录 + MENU: 2, // 菜单 + BUTTON: 3, // 按钮 +}; + +/** + * 角色的类型枚举 + */ +export const SystemRoleTypeEnum = { + SYSTEM: 1, // 内置角色 + CUSTOM: 2, // 自定义角色 +}; + +/** + * 数据权限的范围枚举 + */ +export const SystemDataScopeEnum = { + ALL: 1, // 全部数据权限 + DEPT_CUSTOM: 2, // 指定部门数据权限 + DEPT_ONLY: 3, // 部门数据权限 + DEPT_AND_CHILD: 4, // 部门及以下数据权限 + DEPT_SELF: 5, // 仅本人数据权限 +}; + +/** + * 用户的社交平台的类型枚举 + */ +export const SystemUserSocialTypeEnum = { + DINGTALK: { + title: '钉钉', + type: 20, + source: 'dingtalk', + img: 'https://s1.ax1x.com/2022/05/22/OzMDRs.png', + }, + WECHAT_ENTERPRISE: { + title: '企业微信', + type: 30, + source: 'wechat_enterprise', + img: 'https://s1.ax1x.com/2022/05/22/OzMrzn.png', + }, +}; + +// ========== INFRA 模块 ========== +/** + * 代码生成模板类型 + */ +export const InfraCodegenTemplateTypeEnum = { + CRUD: 1, // 基础 CRUD + TREE: 2, // 树形 CRUD + SUB: 15, // 主子表 CRUD +}; + +/** + * 任务状态的枚举 + */ +export const InfraJobStatusEnum = { + INIT: 0, // 初始化中 + NORMAL: 1, // 运行中 + STOP: 2, // 暂停运行 +}; + +/** + * API 异常数据的处理状态 + */ +export const InfraApiErrorLogProcessStatusEnum = { + INIT: 0, // 未处理 + DONE: 1, // 已处理 + IGNORE: 2, // 已忽略 +}; +export interface ImageSize { + key: string; + name?: string; + style: string; + width: string; + height: string; +} +export const Dall3SizeList: ImageSize[] = [ + { + key: '1024x1024', + name: '1:1', + width: '1024', + height: '1024', + style: 'width: 30px; height: 30px;background-color: #dcdcdc;', + }, + { + key: '1024x1792', + name: '3:5', + width: '1024', + height: '1792', + style: 'width: 30px; height: 50px;background-color: #dcdcdc;', + }, + { + key: '1792x1024', + name: '5:3', + width: '1792', + height: '1024', + style: 'width: 50px; height: 30px;background-color: #dcdcdc;', + }, +]; + +export const Dall3Models: ImageModel[] = [ + { + key: 'dall-e-3', + name: 'DALL·E 3', + image: `/static/imgs/ai/dall2.jpg`, + }, + { + key: 'dall-e-2', + name: 'DALL·E 2', + image: `/static/imgs/ai/dall3.jpg`, + }, +]; + +export const Dall3StyleList: ImageModel[] = [ + { + key: 'vivid', + name: '清晰', + image: `/static/imgs/ai/qingxi.jpg`, + }, + { + key: 'natural', + name: '自然', + image: `/static/imgs/ai/ziran.jpg`, + }, +]; +export const MidjourneyModels: ImageModel[] = [ + { + key: 'midjourney', + name: 'MJ', + image: 'https://bigpt8.com/pc/_nuxt/mj.34a61377.png', + }, + { + key: 'niji', + name: 'NIJI', + image: 'https://bigpt8.com/pc/_nuxt/nj.ca79b143.png', + }, +]; +export const MidjourneyVersions = [ + { + value: '6.0', + label: 'v6.0', + }, + { + value: '5.2', + label: 'v5.2', + }, + { + value: '5.1', + label: 'v5.1', + }, + { + value: '5.0', + label: 'v5.0', + }, + { + value: '4.0', + label: 'v4.0', + }, +]; + +export const NijiVersionList = [ + { + value: '5', + label: 'v5', + }, +]; + +export const MidjourneySizeList: ImageSize[] = [ + { + key: '1:1', + width: '1', + height: '1', + style: 'width: 30px; height: 30px;background-color: #dcdcdc;', + }, + { + key: '3:4', + width: '3', + height: '4', + style: 'width: 30px; height: 40px;background-color: #dcdcdc;', + }, + { + key: '4:3', + width: '4', + height: '3', + style: 'width: 40px; height: 30px;background-color: #dcdcdc;', + }, + { + key: '9:16', + width: '9', + height: '16', + style: 'width: 30px; height: 50px;background-color: #dcdcdc;', + }, + { + key: '16:9', + width: '16', + height: '9', + style: 'width: 50px; height: 30px;background-color: #dcdcdc;', + }, +]; +// ========== PAY 模块 ========== +/** + * 支付渠道枚举 + */ +export const PayChannelEnum = { + WX_PUB: { + code: 'wx_pub', + name: '微信 JSAPI 支付', + }, + WX_LITE: { + code: 'wx_lite', + name: '微信小程序支付', + }, + WX_APP: { + code: 'wx_app', + name: '微信 APP 支付', + }, + WX_NATIVE: { + code: 'wx_native', + name: '微信 Native 支付', + }, + WX_WAP: { + code: 'wx_wap', + name: '微信 WAP 网站支付', + }, + WX_BAR: { + code: 'wx_bar', + name: '微信条码支付', + }, + ALIPAY_PC: { + code: 'alipay_pc', + name: '支付宝 PC 网站支付', + }, + ALIPAY_WAP: { + code: 'alipay_wap', + name: '支付宝 WAP 网站支付', + }, + ALIPAY_APP: { + code: 'alipay_app', + name: '支付宝 APP 支付', + }, + ALIPAY_QR: { + code: 'alipay_qr', + name: '支付宝扫码支付', + }, + ALIPAY_BAR: { + code: 'alipay_bar', + name: '支付宝条码支付', + }, + WALLET: { + code: 'wallet', + name: '钱包支付', + }, + MOCK: { + code: 'mock', + name: '模拟支付', + }, +}; + +/** + * 支付的展示模式每局 + */ +export const PayDisplayModeEnum = { + URL: { + mode: 'url', + }, + IFRAME: { + mode: 'iframe', + }, + FORM: { + mode: 'form', + }, + QR_CODE: { + mode: 'qr_code', + }, + APP: { + mode: 'app', + }, +}; + +/** + * 支付类型枚举 + */ +export const PayType = { + WECHAT: 'WECHAT', + ALIPAY: 'ALIPAY', + MOCK: 'MOCK', +}; + +/** + * 支付订单状态枚举 + */ +export const PayOrderStatusEnum = { + WAITING: { + status: 0, + name: '未支付', + }, + SUCCESS: { + status: 10, + name: '已支付', + }, + CLOSED: { + status: 20, + name: '未支付', + }, +}; + +// ========== MALL - 商品模块 ========== +/** + * 商品 SPU 状态 + */ +export const ProductSpuStatusEnum = { + RECYCLE: { + status: -1, + name: '回收站', + }, + DISABLE: { + status: 0, + name: '下架', + }, + ENABLE: { + status: 1, + name: '上架', + }, +}; + +// ========== MALL - 营销模块 ========== +/** + * 优惠劵模板的有限期类型的枚举 + */ +export const CouponTemplateValidityTypeEnum = { + DATE: { + type: 1, + name: '固定日期可用', + }, + TERM: { + type: 2, + name: '领取之后可用', + }, +}; + +/** + * 优惠劵模板的领取方式的枚举 + */ +export const CouponTemplateTakeTypeEnum = { + USER: { + type: 1, + name: '直接领取', + }, + ADMIN: { + type: 2, + name: '指定发放', + }, + REGISTER: { + type: 3, + name: '新人券', + }, +}; + +/** + * 营销的商品范围枚举 + */ +export const PromotionProductScopeEnum = { + ALL: { + scope: 1, + name: '通用劵', + }, + SPU: { + scope: 2, + name: '商品劵', + }, + CATEGORY: { + scope: 3, + name: '品类劵', + }, +}; + +/** + * 营销的条件类型枚举 + */ +export const PromotionConditionTypeEnum = { + PRICE: { + type: 10, + name: '满 N 元', + }, + COUNT: { + type: 20, + name: '满 N 件', + }, +}; + +/** + * 优惠类型枚举 + */ +export const PromotionDiscountTypeEnum = { + PRICE: { + type: 1, + name: '满减', + }, + PERCENT: { + type: 2, + name: '折扣', + }, +}; + +// ========== MALL - 交易模块 ========== +/** + * 分销关系绑定模式枚举 + */ +export const BrokerageBindModeEnum = { + ANYTIME: { + mode: 1, + name: '首次绑定', + }, + REGISTER: { + mode: 2, + name: '注册绑定', + }, + OVERRIDE: { + mode: 3, + name: '覆盖绑定', + }, +}; +/** + * 分佣模式枚举 + */ +export const BrokerageEnabledConditionEnum = { + ALL: { + condition: 1, + name: '人人分销', + }, + ADMIN: { + condition: 2, + name: '指定分销', + }, +}; +/** + * 佣金记录业务类型枚举 + */ +export const BrokerageRecordBizTypeEnum = { + ORDER: { + type: 1, + name: '获得推广佣金', + }, + WITHDRAW: { + type: 2, + name: '提现申请', + }, +}; +/** + * 佣金提现状态枚举 + */ +export const BrokerageWithdrawStatusEnum = { + AUDITING: { + status: 0, + name: '审核中', + }, + AUDIT_SUCCESS: { + status: 10, + name: '审核通过', + }, + AUDIT_FAIL: { + status: 20, + name: '审核不通过', + }, + WITHDRAW_SUCCESS: { + status: 11, + name: '提现成功', + }, + WITHDRAW_FAIL: { + status: 21, + name: '提现失败', + }, +}; +/** + * 佣金提现类型枚举 + */ +export const BrokerageWithdrawTypeEnum = { + WALLET: { + type: 1, + name: '钱包', + }, + BANK: { + type: 2, + name: '银行卡', + }, + WECHAT: { + type: 3, + name: '微信', + }, + ALIPAY: { + type: 4, + name: '支付宝', + }, +}; + +/** + * 配送方式枚举 + */ +export const DeliveryTypeEnum = { + EXPRESS: { + type: 1, + name: '快递发货', + }, + PICK_UP: { + type: 2, + name: '到店自提', + }, +}; +/** + * 交易订单 - 状态 + */ +export const TradeOrderStatusEnum = { + UNPAID: { + status: 0, + name: '待支付', + }, + UNDELIVERED: { + status: 10, + name: '待发货', + }, + DELIVERED: { + status: 20, + name: '已发货', + }, + COMPLETED: { + status: 30, + name: '已完成', + }, + CANCELED: { + status: 40, + name: '已取消', + }, +}; + +// ========== ERP - 企业资源计划 ========== + +export const ErpBizType = { + PURCHASE_ORDER: 10, + PURCHASE_IN: 11, + PURCHASE_RETURN: 12, + SALE_ORDER: 20, + SALE_OUT: 21, + SALE_RETURN: 22, +}; + +// ========== BPM 模块 ========== + +// 候选人策略枚举 ( 用于审批节点。抄送节点 ) +export enum BpmCandidateStrategyEnum { + /** + * 审批人自选 + */ + APPROVE_USER_SELECT = 34, + /** + * 部门的负责人 + */ + DEPT_LEADER = 21, + /** + * 部门成员 + */ + DEPT_MEMBER = 20, + /** + * 流程表达式 + */ + EXPRESSION = 60, + /** + * 表单内部门负责人 + */ + FORM_DEPT_LEADER = 51, + /** + * 表单内用户字段 + */ + FORM_USER = 50, + /** + * 连续多级部门的负责人 + */ + MULTI_LEVEL_DEPT_LEADER = 23, + /** + * 指定岗位 + */ + POST = 22, + /** + * 指定角色 + */ + ROLE = 10, + /** + * 发起人自己 + */ + START_USER = 36, + /** + * 发起人部门负责人 + */ + START_USER_DEPT_LEADER = 37, + /** + * 发起人连续多级部门的负责人 + */ + START_USER_MULTI_LEVEL_DEPT_LEADER = 38, + /** + * 发起人自选 + */ + START_USER_SELECT = 35, + /** + * 指定用户 + */ + USER = 30, + /** + * 指定用户组 + */ + USER_GROUP = 40, +} + +/** + * 节点类型 + */ +export enum BpmNodeTypeEnum { + /** + * 子流程节点 + */ + CHILD_PROCESS_NODE = 20, + /** + * 条件分支节点 (对应排他网关) + */ + CONDITION_BRANCH_NODE = 51, + /** + * 条件节点 + */ + CONDITION_NODE = 50, + + /** + * 抄送人节点 + */ + COPY_TASK_NODE = 12, + + /** + * 延迟器节点 + */ + DELAY_TIMER_NODE = 14, + + /** + * 结束节点 + */ + END_EVENT_NODE = 1, + + /** + * 包容分支节点 (对应包容网关) + */ + INCLUSIVE_BRANCH_NODE = 53, + + /** + * 并行分支节点 (对应并行网关) + */ + PARALLEL_BRANCH_NODE = 52, + + /** + * 路由分支节点 + */ + ROUTER_BRANCH_NODE = 54, + /** + * 发起人节点 + */ + START_USER_NODE = 10, + /** + * 办理人节点 + */ + TRANSACTOR_NODE = 13, + + /** + * 触发器节点 + */ + TRIGGER_NODE = 15, + /** + * 审批人节点 + */ + USER_TASK_NODE = 11, +} + +/** + * 流程任务操作按钮 + */ +export enum BpmTaskOperationButtonTypeEnum { + /** + * 加签 + */ + ADD_SIGN = 5, + /** + * 通过 + */ + APPROVE = 1, + /** + * 抄送 + */ + COPY = 7, + /** + * 委派 + */ + DELEGATE = 4, + /** + * 拒绝 + */ + REJECT = 2, + /** + * 退回 + */ + RETURN = 6, + /** + * 转办 + */ + TRANSFER = 3, +} + +/** + * 任务状态枚举 + */ +export enum BpmTaskStatusEnum { + /** + * 审批通过 + */ + APPROVE = 2, + + /** + * 审批通过中 + */ + APPROVING = 7, + /** + * 已取消 + */ + CANCEL = 4, + /** + * 未开始 + */ + NOT_START = -1, + + /** + * 审批不通过 + */ + REJECT = 3, + + /** + * 已退回 + */ + RETURN = 5, + /** + * 审批中 + */ + RUNNING = 1, + /** + * 待审批 + */ + WAIT = 0, +} + +/** + * 节点 Id 枚举 + */ +export enum BpmNodeIdEnum { + /** + * 发起人节点 Id + */ + END_EVENT_NODE_ID = 'EndEvent', + + /** + * 发起人节点 Id + */ + START_USER_NODE_ID = 'StartUserNode', +} + +/** + * 表单权限的枚举 + */ +export enum BpmFieldPermissionType { + /** + * 隐藏 + */ + NONE = '3', + /** + * 只读 + */ + READ = '1', + /** + * 编辑 + */ + WRITE = '2', +} + +/** + * 流程模型类型 + */ +export const BpmModelType = { + BPMN: 10, // BPMN 设计器 + SIMPLE: 20, // 简易设计器 +}; + +/** + * 流程模型表单类型 + */ +export const BpmModelFormType = { + NORMAL: 10, // 流程表单 + CUSTOM: 20, // 业务表单 +}; + +/** + * 流程实例状态 + */ +export const BpmProcessInstanceStatus = { + NOT_START: -1, // 未开始 + RUNNING: 1, // 审批中 + APPROVE: 2, // 审批通过 + REJECT: 3, // 审批不通过 + CANCEL: 4, // 已取消 +}; + +/** + * 自动审批类型 + */ +export const BpmAutoApproveType = { + NONE: 0, // 不自动通过 + APPROVE_ALL: 1, // 仅审批一次,后续重复的审批节点均自动通过 + APPROVE_SEQUENT: 2, // 仅针对连续审批的节点自动通过 +}; + +/** + * 审批操作按钮名称 + */ +export const OPERATION_BUTTON_NAME = new Map(); +OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.APPROVE, '通过'); +OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.REJECT, '拒绝'); +OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.TRANSFER, '转办'); +OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.DELEGATE, '委派'); +OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.ADD_SIGN, '加签'); +OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.RETURN, '退回'); +OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.COPY, '抄送'); + +/** + * 流程实例的变量枚举 + */ +export enum ProcessVariableEnum { + /** + * 流程定义名称 + */ + PROCESS_DEFINITION_NAME = 'PROCESS_DEFINITION_NAME', + /** + * 发起时间 + */ + START_TIME = 'PROCESS_START_TIME', + /** + * 发起用户 ID + */ + START_USER_ID = 'PROCESS_START_USER_ID', +} +// ========== 【写作 UI】相关的枚举 ========== + +/** 写作点击示例时的数据 */ +export const WriteExample = { + write: { + prompt: 'vue', + data: 'Vue.js 是一种用于构建用户界面的渐进式 JavaScript 框架。它的核心库只关注视图层,易于上手,同时也便于与其他库或已有项目整合。\n\nVue.js 的特点包括:\n- 响应式的数据绑定:Vue.js 会自动将数据与 DOM 同步,使得状态管理变得更加简单。\n- 组件化:Vue.js 允许开发者通过小型、独立和通常可复用的组件构建大型应用。\n- 虚拟 DOM:Vue.js 使用虚拟 DOM 实现快速渲染,提高了性能。\n\n在 Vue.js 中,一个典型的应用结构可能包括:\n1. 根实例:每个 Vue 应用都需要一个根实例作为入口点。\n2. 组件系统:可以创建自定义的可复用组件。\n3. 指令:特殊的带有前缀 v- 的属性,为 DOM 元素提供特殊的行为。\n4. 插值:用于文本内容,将数据动态地插入到 HTML。\n5. 计算属性和侦听器:用于处理数据的复杂逻辑和响应数据变化。\n6. 条件渲染:根据条件决定元素的渲染。\n7. 列表渲染:用于显示列表数据。\n8. 事件处理:响应用户交互。\n9. 表单输入绑定:处理表单输入和验证。\n10. 组件生命周期钩子:在组件的不同阶段执行特定的函数。\n\nVue.js 还提供了官方的路由器 Vue Router 和状态管理库 Vuex,以支持构建复杂的单页应用(SPA)。\n\n在开发过程中,开发者通常会使用 Vue CLI,这是一个强大的命令行工具,用于快速生成 Vue 项目脚手架,集成了诸如 Babel、Webpack 等现代前端工具,以及热重载、代码检测等开发体验优化功能。\n\nVue.js 的生态系统还包括大量的第三方库和插件,如 Vuetify(UI 组件库)、Vue Test Utils(测试工具)等,这些都极大地丰富了 Vue.js 的开发生态。\n\n总的来说,Vue.js 是一个灵活、高效的前端框架,适合从小型项目到大型企业级应用的开发。它的易用性、灵活性和强大的社区支持使其成为许多开发者的首选框架之一。', + }, + reply: { + originalContent: '领导,我想请假', + prompt: '不批', + data: '您的请假申请已收悉,经核实和考虑,暂时无法批准您的请假申请。\n\n如有特殊情况或紧急事务,请及时与我联系。\n\n祝工作顺利。\n\n谢谢。', + }, +}; + +// ========== 【思维导图 UI】相关的枚举 ========== + +/** 思维导图已有内容生成示例 */ +export const MindMapContentExample = `# Java 技术栈 + +## 核心技术 +### Java SE +### Java EE + +## 框架 +### Spring +#### Spring Boot +#### Spring MVC +#### Spring Data +### Hibernate +### MyBatis + +## 构建工具 +### Maven +### Gradle + +## 版本控制 +### Git +### SVN + +## 测试工具 +### JUnit +### Mockito +### Selenium + +## 应用服务器 +### Tomcat +### Jetty +### WildFly + +## 数据库 +### MySQL +### PostgreSQL +### Oracle +### MongoDB + +## 消息队列 +### Kafka +### RabbitMQ +### ActiveMQ + +## 微服务 +### Spring Cloud +### Dubbo + +## 容器化 +### Docker +### Kubernetes + +## 云服务 +### AWS +### Azure +### Google Cloud + +## 开发工具 +### IntelliJ IDEA +### Eclipse +### Visual Studio Code`; diff --git a/apps/web-antd/src/utils/utils/dict.ts b/apps/web-antd/src/utils/utils/dict.ts new file mode 100644 index 00000000..bcfc9e21 --- /dev/null +++ b/apps/web-antd/src/utils/utils/dict.ts @@ -0,0 +1,327 @@ +// TODO @芋艿:后续再优化 +// TODO @芋艿:可以共享么? + +import type { DictItem } from '#/store'; + +import { isObject } from '@vben/utils'; + +import { useDictStore } from '#/store'; + +// TODO @dhb52:top-level 调用 导致:"getActivePinia()" was called but there was no active Pinia +// 先临时移入到方法中 +// const dictStore = useDictStore(); + +/** AntD 组件的颜色类型 */ +type ColorType = 'error' | 'info' | 'success' | 'warning'; + +/** 字典值类型 */ +type DictValueType = 'boolean' | 'number' | 'string'; + +/** 基础字典数据类型 */ +export interface DictDataType { + dictType?: string; + label: string; + value: boolean | number | string; + colorType?: string; + cssClass?: string; +} + +/** 数字类型字典数据 */ +export interface NumberDictDataType extends DictDataType { + value: number; +} + +/** 字符串类型字典数据 */ +export interface StringDictDataType extends DictDataType { + value: string; +} + +/** 布尔类型字典数据 */ +export interface BooleanDictDataType extends DictDataType { + value: boolean; +} + +/** 字典缓存管理器 */ +class DictCacheManager { + private cache = new Map(); + private maxCacheSize = 100; // 最大缓存数量 + + /** 清空缓存 */ + clear(): void { + this.cache.clear(); + } + + /** 删除指定字典类型的缓存 */ + delete(dictType: string): void { + const keysToDelete = []; + for (const key of this.cache.keys()) { + if (key.startsWith(`${dictType}:`)) { + keysToDelete.push(key); + } + } + keysToDelete.forEach((key) => this.cache.delete(key)); + } + + /** 获取缓存数据 */ + get(dictType: string, valueType: DictValueType): DictDataType[] | undefined { + return this.cache.get(this.getCacheKey(dictType, valueType)); + } + + /** 设置缓存数据 */ + set(dictType: string, valueType: DictValueType, data: DictDataType[]): void { + const key = this.getCacheKey(dictType, valueType); + + // 如果缓存数量超过限制,删除最早的缓存 + if (this.cache.size >= this.maxCacheSize) { + const firstKey = this.cache.keys().next().value; + if (firstKey) { + this.cache.delete(firstKey); + } + } + + this.cache.set(key, data); + } + + /** 获取缓存键 */ + private getCacheKey(dictType: string, valueType: DictValueType): string { + return `${dictType}:${valueType}`; + } +} + +/** 字典缓存实例 */ +const dictCache = new DictCacheManager(); + +/** 值转换器映射 */ +const valueConverters: Record< + DictValueType, + (value: any) => boolean | number | string +> = { + boolean: (value: any) => `${value}` === 'true', + number: (value: any) => Number.parseInt(`${value}`, 10), + string: (value: any) => `${value}`, +}; + +/** + * 获取字典标签 + * @param dictType 字典类型 + * @param value 字典值 + * @returns 字典标签 + */ +function getDictLabel(dictType: string, value: any): string { + const dictStore = useDictStore(); + const dictObj = dictStore.getDictData(dictType, value); + return isObject(dictObj) ? dictObj.label : ''; +} + +/** + * 获取字典对象 + * @param dictType 字典类型 + * @param value 字典值 + * @returns 字典对象 + */ +function getDictObj(dictType: string, value: any): DictItem | null { + const dictStore = useDictStore(); + const dictObj = dictStore.getDictData(dictType, value); + return isObject(dictObj) ? dictObj : null; +} + +/** + * 获取字典数组 - 优化版本,支持缓存和泛型 + * @param dictType 字典类型 + * @param valueType 字典值类型,默认 string 类型 + * @returns 字典数组 + */ +function getDictOptions( + dictType: string, + valueType: T = 'string' as T, +): T extends 'number' + ? NumberDictDataType[] + : T extends 'boolean' + ? BooleanDictDataType[] + : StringDictDataType[] { + // 检查缓存 + const cachedData = dictCache.get(dictType, valueType); + if (cachedData) { + return cachedData as any; + } + + const dictStore = useDictStore(); + const dictOpts = dictStore.getDictOptions(dictType); + + if (dictOpts.length === 0) { + return [] as any; + } + + const converter = valueConverters[valueType]; + const dictOptions: DictDataType[] = dictOpts.map((d: DictItem) => ({ + value: converter(d.value), + label: d.label, + colorType: d.colorType, + cssClass: d.cssClass, + })); + + // 缓存结果 + dictCache.set(dictType, valueType, dictOptions); + + return dictOptions as any; +} + +/** + * 清空字典缓存 + */ +export const clearDictCache = (): void => { + dictCache.clear(); +}; + +/** + * 删除指定字典类型的缓存 + * @param dictType 字典类型 + */ +export const deleteDictCache = (dictType: string): void => { + dictCache.delete(dictType); +}; + +/** 字典类型枚举 - 按模块分组和排序 */ +enum DICT_TYPE { + AI_GENERATE_MODE = 'ai_generate_mode', // AI 生成模式 + AI_IMAGE_STATUS = 'ai_image_status', // AI 图片状态 + AI_MODEL_TYPE = 'ai_model_type', // AI 模型类型 + AI_MUSIC_STATUS = 'ai_music_status', // AI 音乐状态 + // ========== AI - 人工智能模块 ========== + AI_PLATFORM = 'ai_platform', // AI 平台 + AI_WRITE_FORMAT = 'ai_write_format', // AI 写作格式 + AI_WRITE_LANGUAGE = 'ai_write_language', // AI 写作语言 + AI_WRITE_LENGTH = 'ai_write_length', // AI 写作长度 + AI_WRITE_TONE = 'ai_write_tone', // AI 写作语气 + AI_WRITE_TYPE = 'ai_write_type', // AI 写作类型 + BPM_MODEL_FORM_TYPE = 'bpm_model_form_type', + // ========== BPM 模块 ========== + BPM_MODEL_TYPE = 'bpm_model_type', + BPM_OA_LEAVE_TYPE = 'bpm_oa_leave_type', + BPM_PROCESS_INSTANCE_STATUS = 'bpm_process_instance_status', + BPM_PROCESS_LISTENER_TYPE = 'bpm_process_listener_type', + BPM_PROCESS_LISTENER_VALUE_TYPE = 'bpm_process_listener_value_type', + BPM_TASK_CANDIDATE_STRATEGY = 'bpm_task_candidate_strategy', + BPM_TASK_STATUS = 'bpm_task_status', + BROKERAGE_BANK_NAME = 'brokerage_bank_name', // 佣金提现银行 + BROKERAGE_BIND_MODE = 'brokerage_bind_mode', // 分销关系绑定模式 + + BROKERAGE_ENABLED_CONDITION = 'brokerage_enabled_condition', // 分佣模式 + BROKERAGE_RECORD_BIZ_TYPE = 'brokerage_record_biz_type', // 佣金业务类型 + BROKERAGE_RECORD_STATUS = 'brokerage_record_status', // 佣金状态 + BROKERAGE_WITHDRAW_STATUS = 'brokerage_withdraw_status', // 佣金提现状态 + BROKERAGE_WITHDRAW_TYPE = 'brokerage_withdraw_type', // 佣金提现类型 + COMMON_STATUS = 'common_status', + // ========== CRM - 客户管理模块 ========== + CRM_AUDIT_STATUS = 'crm_audit_status', // CRM 审批状态 + CRM_BIZ_TYPE = 'crm_biz_type', // CRM 业务类型 + CRM_BUSINESS_END_STATUS_TYPE = 'crm_business_end_status_type', // CRM 商机结束状态类型 + CRM_CUSTOMER_INDUSTRY = 'crm_customer_industry', // CRM 客户所属行业 + + CRM_CUSTOMER_LEVEL = 'crm_customer_level', // CRM 客户级别 + CRM_CUSTOMER_SOURCE = 'crm_customer_source', // CRM 客户来源 + CRM_FOLLOW_UP_TYPE = 'crm_follow_up_type', // CRM 跟进方式 + CRM_PERMISSION_LEVEL = 'crm_permission_level', // CRM 数据权限的级别 + CRM_PRODUCT_STATUS = 'crm_product_status', // CRM 商品状态 + CRM_PRODUCT_UNIT = 'crm_product_unit', // CRM 产品单位 + CRM_RECEIVABLE_RETURN_TYPE = 'crm_receivable_return_type', // CRM 回款的还款方式 + DATE_INTERVAL = 'date_interval', // 数据间隔 + + // ========== ERP - 企业资源计划模块 ========== + ERP_AUDIT_STATUS = 'erp_audit_status', // ERP 审批状态 + ERP_STOCK_RECORD_BIZ_TYPE = 'erp_stock_record_biz_type', // 库存明细的业务类型 + // ========== MALL - 交易模块 ========== + EXPRESS_CHARGE_MODE = 'trade_delivery_express_charge_mode', // 快递的计费方式 + INFRA_API_ERROR_LOG_PROCESS_STATUS = 'infra_api_error_log_process_status', + // ========== INFRA 模块 ========== + INFRA_BOOLEAN_STRING = 'infra_boolean_string', + INFRA_CODEGEN_FRONT_TYPE = 'infra_codegen_front_type', + INFRA_CODEGEN_SCENE = 'infra_codegen_scene', + + INFRA_CODEGEN_TEMPLATE_TYPE = 'infra_codegen_template_type', + INFRA_CONFIG_TYPE = 'infra_config_type', + + INFRA_FILE_STORAGE = 'infra_file_storage', + INFRA_JOB_LOG_STATUS = 'infra_job_log_status', + + INFRA_JOB_STATUS = 'infra_job_status', + + INFRA_OPERATE_TYPE = 'infra_operate_type', + IOT_DATA_FORMAT = 'iot_data_format', // IOT 数据格式 + IOT_DATA_TYPE = 'iot_data_type', // IOT 数据类型 + IOT_DEVICE_STATUS = 'iot_device_status', // IOT 设备状态 + // ========== IOT - 物联网模块 ========== + IOT_NET_TYPE = 'iot_net_type', // IOT 联网方式 + IOT_PRODUCT_DEVICE_TYPE = 'iot_product_device_type', // IOT 产品设备类型 + IOT_PRODUCT_FUNCTION_TYPE = 'iot_product_function_type', // IOT 产品功能类型 + IOT_PRODUCT_STATUS = 'iot_product_status', // IOT 产品状态 + IOT_PROTOCOL_TYPE = 'iot_protocol_type', // IOT 接入网关协议 + IOT_RW_TYPE = 'iot_rw_type', // IOT 读写类型 + IOT_UNIT_TYPE = 'iot_unit_type', // IOT 单位类型 + IOT_VALIDATE_TYPE = 'iot_validate_type', // IOT 数据校验级别 + MEMBER_EXPERIENCE_BIZ_TYPE = 'member_experience_biz_type', // 会员经验业务类型 + // ========== Member 会员模块 ========== + MEMBER_POINT_BIZ_TYPE = 'member_point_biz_type', // 积分的业务类型 + // ========== MP 模块 ========== + MP_AUTO_REPLY_REQUEST_MATCH = 'mp_auto_reply_request_match', // 自动回复请求匹配类型 + + MP_MESSAGE_TYPE = 'mp_message_type', // 消息类型 + // ========== PAY 模块 ========== + PAY_CHANNEL_CODE = 'pay_channel_code', // 支付渠道编码类型 + PAY_NOTIFY_STATUS = 'pay_notify_status', // 商户支付回调状态 + PAY_NOTIFY_TYPE = 'pay_notify_type', // 商户支付回调状态 + PAY_ORDER_STATUS = 'pay_order_status', // 商户支付订单状态 + PAY_REFUND_STATUS = 'pay_refund_status', // 退款订单状态 + PAY_TRANSFER_STATUS = 'pay_transfer_status', // 转账订单状态 + PAY_TRANSFER_TYPE = 'pay_transfer_type', // 转账订单状态 + // ========== MALL - 商品模块 ========== + PRODUCT_SPU_STATUS = 'product_spu_status', // 商品状态 + + PROMOTION_BANNER_POSITION = 'promotion_banner_position', // banner 定位 + PROMOTION_BARGAIN_RECORD_STATUS = 'promotion_bargain_record_status', // 砍价记录的状态 + PROMOTION_COMBINATION_RECORD_STATUS = 'promotion_combination_record_status', // 拼团记录的状态 + PROMOTION_CONDITION_TYPE = 'promotion_condition_type', // 营销的条件类型枚举 + PROMOTION_COUPON_STATUS = 'promotion_coupon_status', // 优惠劵的状态 + PROMOTION_COUPON_TAKE_TYPE = 'promotion_coupon_take_type', // 优惠劵的领取方式 + PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE = 'promotion_coupon_template_validity_type', // 优惠劵模板的有限期类型 + // ========== MALL - 营销模块 ========== + PROMOTION_DISCOUNT_TYPE = 'promotion_discount_type', // 优惠类型 + PROMOTION_PRODUCT_SCOPE = 'promotion_product_scope', // 营销的商品范围 + SYSTEM_DATA_SCOPE = 'system_data_scope', + SYSTEM_LOGIN_RESULT = 'system_login_result', + + SYSTEM_LOGIN_TYPE = 'system_login_type', + SYSTEM_MAIL_SEND_STATUS = 'system_mail_send_status', + + SYSTEM_MENU_TYPE = 'system_menu_type', + SYSTEM_NOTICE_TYPE = 'system_notice_type', + SYSTEM_NOTIFY_TEMPLATE_TYPE = 'system_notify_template_type', + SYSTEM_OAUTH2_GRANT_TYPE = 'system_oauth2_grant_type', + SYSTEM_ROLE_TYPE = 'system_role_type', + SYSTEM_SMS_CHANNEL_CODE = 'system_sms_channel_code', + SYSTEM_SMS_RECEIVE_STATUS = 'system_sms_receive_status', + SYSTEM_SMS_SEND_STATUS = 'system_sms_send_status', + SYSTEM_SMS_TEMPLATE_TYPE = 'system_sms_template_type', + + SYSTEM_SOCIAL_TYPE = 'system_social_type', + // ========== SYSTEM 模块 ========== + SYSTEM_USER_SEX = 'system_user_sex', + TERMINAL = 'terminal', // 终端 + TRADE_AFTER_SALE_STATUS = 'trade_after_sale_status', // 售后 - 状态 + TRADE_AFTER_SALE_TYPE = 'trade_after_sale_type', // 售后 - 类型 + TRADE_AFTER_SALE_WAY = 'trade_after_sale_way', // 售后 - 方式 + TRADE_DELIVERY_TYPE = 'trade_delivery_type', // 配送方式 + TRADE_ORDER_ITEM_AFTER_SALE_STATUS = 'trade_order_item_after_sale_status', // 订单项 - 售后状态 + TRADE_ORDER_STATUS = 'trade_order_status', // 订单 - 状态 + TRADE_ORDER_TYPE = 'trade_order_type', // 订单 - 类型 + USER_TYPE = 'user_type', +} + +export { + type ColorType, + DICT_TYPE, + type DictValueType, + getDictLabel, + getDictObj, + getDictOptions, +}; diff --git a/apps/web-antd/src/utils/utils/formCreate.ts b/apps/web-antd/src/utils/utils/formCreate.ts new file mode 100644 index 00000000..a653a44b --- /dev/null +++ b/apps/web-antd/src/utils/utils/formCreate.ts @@ -0,0 +1,58 @@ +/** + * 针对 https://github.com/xaboy/form-create-designer 封装的工具类 + */ +// TODO @芋艿:后续这些 form-create 的优化;另外需要使用 form-create-helper 会好点 +import { isRef } from 'vue'; + +// 编码表单 Conf +export const encodeConf = (designerRef: any) => { + return JSON.stringify(designerRef.value.getOption()); +}; + +// 编码表单 Fields +export const encodeFields = (designerRef: any) => { + const rule = JSON.parse(designerRef.value.getJson()); + const fields: string[] = []; + rule.forEach((item: unknown) => { + fields.push(JSON.stringify(item)); + }); + return fields; +}; + +// 解码表单 Fields +export const decodeFields = (fields: string[]) => { + const rule: object[] = []; + fields.forEach((item) => { + rule.push(JSON.parse(item)); + }); + return rule; +}; + +// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景 +export const setConfAndFields = ( + designerRef: any, + conf: string, + fields: string | string[], +) => { + designerRef.value.setOption(JSON.parse(conf)); + // 处理 fields 参数类型,确保传入 decodeFields 的是 string[] 类型 + const fieldsArray = Array.isArray(fields) ? fields : [fields]; + designerRef.value.setRule(decodeFields(fieldsArray)); +}; + +// 设置表单的 Conf 和 Fields,适用 form-create 场景 +export const setConfAndFields2 = ( + detailPreview: any, + conf: string, + fields: string[], + value?: any, +) => { + if (isRef(detailPreview)) { + detailPreview = detailPreview.value; + } + detailPreview.option = JSON.parse(conf); + detailPreview.rule = decodeFields(fields); + if (value) { + detailPreview.value = value; + } +}; diff --git a/apps/web-antd/src/utils/utils/index.ts b/apps/web-antd/src/utils/utils/index.ts new file mode 100644 index 00000000..dcf28573 --- /dev/null +++ b/apps/web-antd/src/utils/utils/index.ts @@ -0,0 +1,5 @@ +export * from './constants'; +export * from './dict'; +export * from './formCreate'; +export * from './rangePickerProps'; +export * from './routerHelper'; diff --git a/apps/web-antd/src/utils/utils/rangePickerProps.ts b/apps/web-antd/src/utils/utils/rangePickerProps.ts new file mode 100644 index 00000000..245e3d81 --- /dev/null +++ b/apps/web-antd/src/utils/utils/rangePickerProps.ts @@ -0,0 +1,59 @@ +import type { Dayjs } from 'dayjs'; + +import dayjs from 'dayjs'; + +import { $t } from '#/locales'; + +/** 时间段选择器拓展 */ +export function getRangePickerDefaultProps() { + return { + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: [ + $t('utils.rangePicker.beginTime'), + $t('utils.rangePicker.endTime'), + ], + ranges: { + [$t('utils.rangePicker.today')]: () => + [dayjs().startOf('day'), dayjs().endOf('day')] as [Dayjs, Dayjs], + [$t('utils.rangePicker.last7Days')]: () => + [dayjs().subtract(7, 'day').startOf('day'), dayjs().endOf('day')] as [ + Dayjs, + Dayjs, + ], + [$t('utils.rangePicker.last30Days')]: () => + [dayjs().subtract(30, 'day').startOf('day'), dayjs().endOf('day')] as [ + Dayjs, + Dayjs, + ], + [$t('utils.rangePicker.yesterday')]: () => + [ + dayjs().subtract(1, 'day').startOf('day'), + dayjs().subtract(1, 'day').endOf('day'), + ] as [Dayjs, Dayjs], + [$t('utils.rangePicker.thisWeek')]: () => + [dayjs().startOf('week'), dayjs().endOf('day')] as [Dayjs, Dayjs], + [$t('utils.rangePicker.thisMonth')]: () => + [dayjs().startOf('month'), dayjs().endOf('day')] as [Dayjs, Dayjs], + [$t('utils.rangePicker.lastWeek')]: () => + [dayjs().subtract(1, 'week').startOf('day'), dayjs().endOf('day')] as [ + Dayjs, + Dayjs, + ], + }, + showTime: { + defaultValue: [ + dayjs('00:00:00', 'HH:mm:ss'), + dayjs('23:59:59', 'HH:mm:ss'), + ], + format: 'HH:mm:ss', + }, + transformDateFunc: (dates: any) => { + if (dates && dates.length === 2) { + // 格式化为后台支持的时间格式 + return [dates.createTime[0], dates.createTime[1]].join(','); + } + return {}; + }, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + }; +} diff --git a/apps/web-antd/src/utils/utils/routerHelper.ts b/apps/web-antd/src/utils/utils/routerHelper.ts new file mode 100644 index 00000000..7df28550 --- /dev/null +++ b/apps/web-antd/src/utils/utils/routerHelper.ts @@ -0,0 +1,16 @@ +import { defineAsyncComponent } from 'vue'; + +const modules = import.meta.glob('../views/**/*.{vue,tsx}'); + +/** + * 注册一个异步组件 + * @param componentPath 例:/bpm/oa/leave/detail + */ +export const registerComponent = (componentPath: string) => { + for (const item in modules) { + if (item.includes(componentPath)) { + // 使用异步组件的方式来动态加载组件 + return defineAsyncComponent(modules[item] as any); + } + } +}; diff --git a/apps/web-antd/src/views/mall/home/index.vue b/apps/web-antd/src/views/mall/home/index.vue new file mode 100644 index 00000000..fde1c3d3 --- /dev/null +++ b/apps/web-antd/src/views/mall/home/index.vue @@ -0,0 +1,176 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/brand/data.ts b/apps/web-antd/src/views/mall/product/brand/data.ts new file mode 100644 index 00000000..cdf64706 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/brand/data.ts @@ -0,0 +1,132 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { + CommonStatusEnum, + DICT_TYPE, + getDictOptions, + getRangePickerDefaultProps, +} from '#/utils/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '品牌名称', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'picUrl', + label: '品牌图片', + component: 'ImageUpload', + rules: 'required', + }, + { + fieldName: 'sort', + label: '品牌排序', + component: 'InputNumber', + componentProps: { + min: 0, + controlsPosition: 'right', + placeholder: '请输入品牌排序', + }, + rules: z.number().min(0).default(1), + }, + { + fieldName: 'status', + label: '品牌状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'description', + label: '品牌描述', + component: 'Textarea', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '品牌名称', + component: 'Input', + }, + { + fieldName: 'status', + label: '品牌状态', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns(): VxeGridPropTypes.Columns { + return [ + { + field: 'name', + title: '分类名称', + fixed: 'left', + }, + { + field: 'picUrl', + title: '品牌图片', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'sort', + title: '品牌排序', + }, + { + field: 'status', + title: '开启状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/product/brand/index.vue b/apps/web-antd/src/views/mall/product/brand/index.vue new file mode 100644 index 00000000..a9669af9 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/brand/index.vue @@ -0,0 +1,127 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/brand/modules/form.vue b/apps/web-antd/src/views/mall/product/brand/modules/form.vue new file mode 100644 index 00000000..436e7318 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/brand/modules/form.vue @@ -0,0 +1,83 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/category/data.ts b/apps/web-antd/src/views/mall/product/category/data.ts new file mode 100644 index 00000000..5efa27c0 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/category/data.ts @@ -0,0 +1,139 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MallCategoryApi } from '#/api/mall/product/category'; + +import { handleTree } from '@vben/utils'; + +import { z } from '#/adapter/form'; +import { getCategoryList } from '#/api/mall/product/category'; +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'parentId', + label: '上级分类', + component: 'ApiTreeSelect', + componentProps: { + allowClear: true, + api: async () => { + const data = await getCategoryList({ parentId: 0 }); + data.unshift({ + id: 0, + name: '顶级分类', + picUrl: '', + sort: 0, + status: 0, + }); + return handleTree(data); + }, + labelField: 'name', + valueField: 'id', + childrenField: 'children', + placeholder: '请选择上级分类', + treeDefaultExpandAll: true, + }, + rules: 'selectRequired', + }, + { + fieldName: 'name', + label: '分类名称', + component: 'Input', + componentProps: { + placeholder: '请输入分类名称', + }, + rules: 'required', + }, + { + fieldName: 'picUrl', + label: '移动端分类图', + component: 'ImageUpload', + rules: 'required', + }, + { + fieldName: 'sort', + label: '分类排序', + component: 'InputNumber', + componentProps: { + min: 0, + controlsPosition: 'right', + placeholder: '请输入分类排序', + }, + rules: z.number().min(0).default(1), + }, + { + fieldName: 'status', + label: '开启状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '分类名称', + component: 'Input', + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '分类名称', + align: 'left', + fixed: 'left', + treeNode: true, + }, + { + field: 'picUrl', + title: '移动端分类图', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'sort', + title: '分类排序', + }, + { + field: 'status', + title: '开启状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 300, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/product/category/index.vue b/apps/web-antd/src/views/mall/product/category/index.vue new file mode 100644 index 00000000..ebb17103 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/category/index.vue @@ -0,0 +1,187 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/category/modules/form.vue b/apps/web-antd/src/views/mall/product/category/modules/form.vue new file mode 100644 index 00000000..a8732356 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/category/modules/form.vue @@ -0,0 +1,89 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/comment/data.ts b/apps/web-antd/src/views/mall/product/comment/data.ts new file mode 100644 index 00000000..fb4d87cf --- /dev/null +++ b/apps/web-antd/src/views/mall/product/comment/data.ts @@ -0,0 +1,202 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; +import type { MallCommentApi } from '#/api/mall/product/comment'; + +import { getSpuSimpleList } from '#/api/mall/product/spu'; +import { getRangePickerDefaultProps } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'spuId', + label: '商品', + component: 'ApiSelect', + componentProps: { + api: getSpuSimpleList, + labelField: 'name', + valueField: 'id', + }, + rules: 'required', + }, + { + fieldName: 'userAvatar', + label: '用户头像', + component: 'ImageUpload', + rules: 'required', + }, + { + fieldName: 'userNickname', + label: '用户名称', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'content', + label: '评论内容', + component: 'Textarea', + rules: 'required', + }, + { + fieldName: 'descriptionScores', + label: '描述星级', + component: 'Rate', + rules: 'required', + }, + { + fieldName: 'benefitScores', + label: '服务星级', + component: 'Rate', + rules: 'required', + }, + { + fieldName: 'picUrls', + label: '评论图片', + component: 'ImageUpload', + componentProps: { + maxNumber: 9, + }, + rules: 'required', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'replyStatus', + label: '回复状态', + component: 'Select', + componentProps: { + options: [ + { label: '已回复', value: true }, + { label: '未回复', value: false }, + ], + }, + }, + { + fieldName: 'spuName', + label: '商品名称', + component: 'Input', + }, + { + fieldName: 'userNickname', + label: '用户名称', + component: 'Input', + }, + { + fieldName: 'orderId', + label: '订单编号', + component: 'Input', + }, + { + fieldName: 'createTime', + label: '评论时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns( + onStatusChange?: ( + newStatus: boolean, + row: T, + ) => PromiseLike, +): VxeGridPropTypes.Columns { + return [ + { + field: 'id', + title: '评论编号', + fixed: 'left', + }, + { + field: 'skuPicUrl', + title: '商品图片', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'spuName', + title: '商品名称', + minWidth: 200, + }, + { + field: 'skuProperties', + title: '商品属性', + minWidth: 200, + formatter: ({ cellValue }) => { + return cellValue && cellValue.length > 0 + ? cellValue + .map((item: any) => `${item.propertyName} : ${item.valueName}`) + .join('\n') + : '-'; + }, + }, + { + field: 'userNickname', + title: '用户名称', + }, + { + field: 'descriptionScores', + title: '商品评分', + }, + { + field: 'benefitScores', + title: '服务评分', + }, + { + field: 'content', + title: '评论内容', + }, + { + field: 'picUrls', + title: '评论图片', + cellRender: { + name: 'CellImages', + }, + }, + { + field: 'replyContent', + title: '回复内容', + }, + { + field: 'createTime', + title: '评论时间', + formatter: 'formatDateTime', + }, + { + field: 'visible', + title: '是否展示', + align: 'center', + cellRender: { + attrs: { beforeChange: onStatusChange }, + name: 'CellSwitch', + props: { + checkedValue: true, + unCheckedValue: false, + }, + }, + }, + { + title: '操作', + width: 80, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/product/comment/index.vue b/apps/web-antd/src/views/mall/product/comment/index.vue new file mode 100644 index 00000000..f6e58063 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/comment/index.vue @@ -0,0 +1,156 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/comment/modules/form.vue b/apps/web-antd/src/views/mall/product/comment/modules/form.vue new file mode 100644 index 00000000..ce86b1c4 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/comment/modules/form.vue @@ -0,0 +1,83 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/property/data.ts b/apps/web-antd/src/views/mall/product/property/data.ts new file mode 100644 index 00000000..733c8fdc --- /dev/null +++ b/apps/web-antd/src/views/mall/product/property/data.ts @@ -0,0 +1,176 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { getPropertySimpleList } from '#/api/mall/product/property'; + +// ============================== 属性 ============================== + +/** 类型新增/修改的表单 */ +export function usePropertyFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名称', + component: 'Input', + componentProps: { + placeholder: '请输入名称', + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + }, + }, + ]; +} + +/** 类型列表的搜索表单 */ +export function usePropertyGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名称', + component: 'Input', + componentProps: { + placeholder: '请输入名称', + clearable: true, + }, + }, + ]; +} + +/** 类型列表的字段 */ +export function usePropertyGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + }, + { + field: 'name', + title: '名称', + }, + { + field: 'remark', + title: '备注', + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +// ============================== 值数据 ============================== + +/** 数据新增/修改的表单 */ +export function useValueFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'propertyId', + label: '属性编号', + component: 'ApiSelect', + componentProps: (values) => { + return { + api: getPropertySimpleList, + labelField: 'name', + valueField: 'id', + disabled: !!values.id, + }; + }, + rules: 'required', + dependencies: { + triggerFields: [''], + }, + }, + { + fieldName: 'name', + label: '名称', + component: 'Input', + componentProps: { + placeholder: '请输入名称', + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + }, + }, + ]; +} + +/** 字典数据列表搜索表单 */ +export function useValueGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名称', + component: 'Input', + componentProps: { + clearable: true, + }, + }, + ]; +} + +/** + * 字典数据表格列 + */ +export function useValueGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + }, + { + field: 'name', + title: '属性值名称', + }, + { + field: 'remark', + title: '备注', + }, + { + title: '创建时间', + field: 'createTime', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/product/property/index.vue b/apps/web-antd/src/views/mall/product/property/index.vue new file mode 100644 index 00000000..97036c49 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/property/index.vue @@ -0,0 +1,35 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/property/modules/property-form.vue b/apps/web-antd/src/views/mall/product/property/modules/property-form.vue new file mode 100644 index 00000000..cce88878 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/property/modules/property-form.vue @@ -0,0 +1,88 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/property/modules/property-grid.vue b/apps/web-antd/src/views/mall/product/property/modules/property-grid.vue new file mode 100644 index 00000000..5be3a96b --- /dev/null +++ b/apps/web-antd/src/views/mall/product/property/modules/property-grid.vue @@ -0,0 +1,142 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/property/modules/value-form.vue b/apps/web-antd/src/views/mall/product/property/modules/value-form.vue new file mode 100644 index 00000000..394bfe14 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/property/modules/value-form.vue @@ -0,0 +1,100 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/property/modules/value-grid.vue b/apps/web-antd/src/views/mall/product/property/modules/value-grid.vue new file mode 100644 index 00000000..e34dcca5 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/property/modules/value-grid.vue @@ -0,0 +1,151 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/spu/data.ts b/apps/web-antd/src/views/mall/product/spu/data.ts new file mode 100644 index 00000000..6ceb265e --- /dev/null +++ b/apps/web-antd/src/views/mall/product/spu/data.ts @@ -0,0 +1,117 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MallSpuApi } from '#/api/mall/product/spu'; + +import { handleTree } from '@vben/utils'; + +import { getCategoryList } from '#/api/mall/product/category'; +import { getRangePickerDefaultProps } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '商品名称', + component: 'Input', + }, + { + fieldName: 'categoryId', + label: '商品分类', + component: 'ApiTreeSelect', + componentProps: { + api: async () => { + const res = await getCategoryList({}); + return handleTree(res, 'id', 'parentId', 'children'); + }, + fieldNames: { label: 'name', value: 'id', children: 'children' }, + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns( + onStatusChange?: ( + newStatus: number, + row: T, + ) => PromiseLike, +): VxeTableGridOptions['columns'] { + return [ + { + type: 'expand', + width: 80, + slots: { content: 'expand_content' }, + fixed: 'left', + }, + { + field: 'id', + title: '商品编号', + fixed: 'left', + }, + { + field: 'name', + title: '商品名称', + fixed: 'left', + minWidth: 200, + }, + { + field: 'picUrl', + title: '商品图片', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'price', + title: '价格', + formatter: 'formatAmount2', + }, + { + field: 'salesCount', + title: '销量', + }, + { + field: 'stock', + title: '库存', + }, + { + field: 'sort', + title: '排序', + }, + { + field: 'status', + title: '销售状态', + cellRender: { + attrs: { beforeChange: onStatusChange }, + name: 'CellSwitch', + props: { + checkedValue: 1, + checkedChildren: '上架', + unCheckedValue: 0, + unCheckedChildren: '下架', + }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 300, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/product/spu/index.vue b/apps/web-antd/src/views/mall/product/spu/index.vue new file mode 100644 index 00000000..aa408522 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/spu/index.vue @@ -0,0 +1,348 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/spu/modules/detail.vue b/apps/web-antd/src/views/mall/product/spu/modules/detail.vue new file mode 100644 index 00000000..c28ebc68 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/spu/modules/detail.vue @@ -0,0 +1,3 @@ + + + diff --git a/apps/web-antd/src/views/mall/product/spu/modules/form.vue b/apps/web-antd/src/views/mall/product/spu/modules/form.vue new file mode 100644 index 00000000..5b641357 --- /dev/null +++ b/apps/web-antd/src/views/mall/product/spu/modules/form.vue @@ -0,0 +1,3 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/article/category/data.ts b/apps/web-antd/src/views/mall/promotion/article/category/data.ts new file mode 100644 index 00000000..d03a5d87 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/article/category/data.ts @@ -0,0 +1,135 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '分类名称', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'picUrl', + label: '图标地址', + component: 'ImageUpload', + }, + { + fieldName: 'sort', + label: '排序', + component: 'InputNumber', + componentProps: { + min: 0, + controlsPosition: 'right', + placeholder: '请输入排序', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: 'required', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '分类名称', + component: 'Input', + componentProps: { + placeholder: '请输入分类名称', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns(): VxeGridPropTypes.Columns { + return [ + { + title: '编号', + field: 'id', + width: 100, + }, + { + title: '分类名称', + field: 'name', + minWidth: 240, + }, + { + title: '分类图片', + field: 'picUrl', + width: 80, + cellRender: { + name: 'CellImage', + }, + }, + { + title: '状态', + field: 'status', + width: 150, + cellRender: { + name: 'CellDictTag', + props: { + dictType: DICT_TYPE.COMMON_STATUS, + }, + }, + }, + { + title: '排序', + field: 'sort', + width: 150, + }, + { + title: '创建时间', + field: 'createTime', + width: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/article/category/index.vue b/apps/web-antd/src/views/mall/promotion/article/category/index.vue new file mode 100644 index 00000000..ca3c71c1 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/article/category/index.vue @@ -0,0 +1,130 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/article/category/modules/form.vue b/apps/web-antd/src/views/mall/promotion/article/category/modules/form.vue new file mode 100644 index 00000000..cfdd46f0 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/article/category/modules/form.vue @@ -0,0 +1,90 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/article/data.ts b/apps/web-antd/src/views/mall/promotion/article/data.ts new file mode 100644 index 00000000..5b03258f --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/article/data.ts @@ -0,0 +1,210 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { getSimpleArticleCategoryList } from '#/api/mall/promotion/articleCategory'; +import { + CommonStatusEnum, + DICT_TYPE, + getDictOptions, + getRangePickerDefaultProps, +} from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'title', + label: '文章标题', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'categoryId', + label: '文章分类', + component: 'ApiSelect', + componentProps: { + api: getSimpleArticleCategoryList, + labelField: 'name', + valueField: 'id', + }, + rules: 'required', + }, + { + fieldName: 'author', + label: '文章作者', + component: 'Input', + }, + { + fieldName: 'introduction', + label: '文章简介', + component: 'Input', + }, + { + fieldName: 'picUrl', + label: '文章封面', + component: 'ImageUpload', + rules: 'required', + }, + { + fieldName: 'recommendHot', + label: '是否热门', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + buttonStyle: 'solid', + optionType: 'button', + }, + }, + { + fieldName: 'recommendBanner', + label: '是否轮播图', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + buttonStyle: 'solid', + optionType: 'button', + }, + }, + { + // TODO: 商品关联 + fieldName: 'spuId', + label: '商品关联', + component: 'Input', + }, + { + fieldName: 'sort', + label: '排序', + component: 'InputNumber', + componentProps: { + min: 0, + controlsPosition: 'right', + placeholder: '请输入品牌排序', + }, + rules: z.number().min(0).default(1), + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'description', + label: '文章内容', + component: 'RichTextarea', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '文章分类', + component: 'ApiSelect', + componentProps: { + api: getSimpleArticleCategoryList, + labelField: 'name', + valueField: 'id', + }, + }, + { + fieldName: 'title', + label: '文章标题', + component: 'Input', + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns(): VxeGridPropTypes.Columns { + return [ + { + field: 'id', + title: '编号', + fixed: 'left', + }, + { + field: 'title', + title: '标题', + }, + { + field: 'picUrl', + title: '封面', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'categoryId', + title: '分类', + }, + { + field: 'browseCount', + title: '浏览量', + }, + { + field: 'author', + title: '作者', + }, + { + field: 'introduction', + title: '文章简介', + }, + { + field: 'sort', + title: '排序', + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/article/index.vue b/apps/web-antd/src/views/mall/promotion/article/index.vue new file mode 100644 index 00000000..7c035ec0 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/article/index.vue @@ -0,0 +1,127 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/article/modules/form.vue b/apps/web-antd/src/views/mall/promotion/article/modules/form.vue new file mode 100644 index 00000000..dcf648cf --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/article/modules/form.vue @@ -0,0 +1,87 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/banner/data.ts b/apps/web-antd/src/views/mall/promotion/banner/data.ts new file mode 100644 index 00000000..cdc7acbe --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/banner/data.ts @@ -0,0 +1,175 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'title', + label: 'Banner标题', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'picUrl', + label: '图片地址', + component: 'ImageUpload', + rules: 'required', + }, + { + fieldName: 'position', + label: '定位', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.PROMOTION_BANNER_POSITION, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: 'required', + }, + { + fieldName: 'url', + label: '跳转地址', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'sort', + label: '排序', + component: 'InputNumber', + componentProps: { + min: 0, + controlsPosition: 'right', + placeholder: '请输入排序', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: 'required', + }, + { + fieldName: 'memo', + label: '描述', + component: 'Textarea', + componentProps: { + rows: 4, + placeholder: '请输入描述', + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'title', + label: 'Banner标题', + component: 'Input', + componentProps: { + placeholder: '请输入Banner标题', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns(): VxeGridPropTypes.Columns { + return [ + { + title: 'Banner标题', + field: 'title', + }, + { + title: '图片', + field: 'picUrl', + width: 80, + cellRender: { + name: 'CellImage', + }, + }, + { + title: '状态', + field: 'status', + width: 150, + cellRender: { + name: 'CellDictTag', + props: { + dictType: DICT_TYPE.COMMON_STATUS, + }, + }, + }, + { + title: '定位', + field: 'position', + width: 150, + cellRender: { + name: 'CellDictTag', + props: { + dictType: DICT_TYPE.PROMOTION_BANNER_POSITION, + }, + }, + }, + { + title: '跳转地址', + field: 'url', + }, + { + title: '创建时间', + field: 'createTime', + width: 180, + formatter: 'formatDateTime', + }, + { + title: '排序', + field: 'sort', + width: 100, + }, + { + title: '描述', + field: 'memo', + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/banner/index.vue b/apps/web-antd/src/views/mall/promotion/banner/index.vue new file mode 100644 index 00000000..d5ad127c --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/banner/index.vue @@ -0,0 +1,127 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/banner/modules/form.vue b/apps/web-antd/src/views/mall/promotion/banner/modules/form.vue new file mode 100644 index 00000000..d58d2e92 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/banner/modules/form.vue @@ -0,0 +1,87 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/bargain/activity/data.ts b/apps/web-antd/src/views/mall/promotion/bargain/activity/data.ts new file mode 100644 index 00000000..80285f23 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/bargain/activity/data.ts @@ -0,0 +1,262 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { formatDate } from '@vben/utils'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + }, + rules: 'required', + }, + { + fieldName: 'startTime', + label: '开始时间', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择开始时间', + }, + rules: 'required', + }, + { + fieldName: 'endTime', + label: '结束时间', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择结束时间', + }, + rules: 'required', + }, + { + fieldName: 'bargainFirstPrice', + label: '砍价起始价格(元)', + component: 'InputNumber', + componentProps: { + min: 0, + precision: 2, + step: 0.01, + placeholder: '请输入砍价起始价格', + }, + rules: 'required', + }, + { + fieldName: 'bargainMinPrice', + label: '砍价底价(元)', + component: 'InputNumber', + componentProps: { + min: 0, + precision: 2, + step: 0.01, + placeholder: '请输入砍价底价', + }, + rules: 'required', + }, + { + fieldName: 'stock', + label: '活动库存', + component: 'InputNumber', + componentProps: { + min: 1, + placeholder: '请输入活动库存', + }, + rules: 'required', + }, + { + fieldName: 'helpMaxCount', + label: '助力人数', + component: 'InputNumber', + componentProps: { + min: 1, + placeholder: '请输入助力人数', + }, + rules: 'required', + }, + { + fieldName: 'bargainCount', + label: '砍价次数', + component: 'InputNumber', + componentProps: { + min: 1, + placeholder: '请输入砍价次数', + }, + rules: 'required', + }, + { + fieldName: 'totalLimitCount', + label: '购买限制', + component: 'InputNumber', + componentProps: { + min: 1, + placeholder: '请输入购买限制', + }, + rules: 'required', + }, + { + fieldName: 'randomMinPrice', + label: '最小砍价金额(元)', + component: 'InputNumber', + componentProps: { + min: 0, + precision: 2, + step: 0.01, + placeholder: '请输入最小砍价金额', + }, + }, + { + fieldName: 'randomMaxPrice', + label: '最大砍价金额(元)', + component: 'InputNumber', + componentProps: { + min: 0, + precision: 2, + step: 0.01, + placeholder: '请输入最大砍价金额', + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + clearable: true, + }, + }, + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '活动编号', + minWidth: 80, + }, + { + field: 'name', + title: '活动名称', + minWidth: 140, + }, + { + field: 'activityTime', + title: '活动时间', + minWidth: 210, + formatter: ({ row }) => { + if (!row.startTime || !row.endTime) return ''; + return `${formatDate(row.startTime, 'YYYY-MM-DD')} ~ ${formatDate(row.endTime, 'YYYY-MM-DD')}`; + }, + }, + { + field: 'picUrl', + title: '商品图片', + minWidth: 80, + cellRender: { + name: 'CellImage', + props: { + height: 40, + width: 40, + }, + }, + }, + { + field: 'spuName', + title: '商品标题', + minWidth: 300, + }, + { + field: 'bargainFirstPrice', + title: '起始价格', + minWidth: 100, + formatter: 'formatAmount2', + }, + { + field: 'bargainMinPrice', + title: '砍价底价', + minWidth: 100, + formatter: 'formatAmount2', + }, + { + field: 'recordUserCount', + title: '总砍价人数', + minWidth: 100, + }, + { + field: 'recordSuccessUserCount', + title: '成功砍价人数', + minWidth: 110, + }, + { + field: 'helpUserCount', + title: '助力人数', + minWidth: 100, + }, + { + field: 'status', + title: '活动状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'stock', + title: '库存', + minWidth: 80, + }, + { + field: 'totalStock', + title: '总库存', + minWidth: 80, + }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 150, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/bargain/activity/index.vue b/apps/web-antd/src/views/mall/promotion/bargain/activity/index.vue new file mode 100644 index 00000000..c6291ade --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/bargain/activity/index.vue @@ -0,0 +1,178 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/bargain/activity/modules/form.vue b/apps/web-antd/src/views/mall/promotion/bargain/activity/modules/form.vue new file mode 100644 index 00000000..bfbf6cc9 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/bargain/activity/modules/form.vue @@ -0,0 +1,92 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/bargain/record/data.ts b/apps/web-antd/src/views/mall/promotion/bargain/record/data.ts new file mode 100644 index 00000000..9bd74a66 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/bargain/record/data.ts @@ -0,0 +1,161 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'status', + label: '砍价状态', + component: 'Select', + componentProps: { + placeholder: '请选择砍价状态', + clearable: true, + options: getDictOptions( + DICT_TYPE.PROMOTION_BARGAIN_RECORD_STATUS, + 'number', + ), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 50, + }, + { + field: 'avatar', + title: '用户头像', + minWidth: 120, + cellRender: { + name: 'CellImage', + props: { + height: 40, + width: 40, + shape: 'circle', + }, + }, + }, + { + field: 'nickname', + title: '用户昵称', + minWidth: 100, + }, + { + field: 'createTime', + title: '发起时间', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'activity.name', + title: '砍价活动', + minWidth: 150, + }, + { + field: 'activity.bargainMinPrice', + title: '最低价', + minWidth: 100, + formatter: 'formatAmount2', + }, + { + field: 'bargainPrice', + title: '当前价', + minWidth: 100, + formatter: 'formatAmount2', + }, + { + field: 'activity.helpMaxCount', + title: '总砍价次数', + minWidth: 100, + }, + { + field: 'helpCount', + title: '剩余砍价次数', + minWidth: 100, + }, + { + field: 'status', + title: '砍价状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_BARGAIN_RECORD_STATUS }, + }, + }, + { + field: 'endTime', + title: '结束时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'orderId', + title: '订单编号', + minWidth: 100, + }, + { + title: '操作', + width: 100, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 助力列表表格列配置 */ +export function useHelpGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'userId', + title: '用户编号', + minWidth: 80, + }, + { + field: 'avatar', + title: '用户头像', + minWidth: 80, + cellRender: { + name: 'CellImage', + props: { + height: 40, + width: 40, + shape: 'circle', + }, + }, + }, + { + field: 'nickname', + title: '用户昵称', + minWidth: 100, + }, + { + field: 'reducePrice', + title: '砍价金额', + minWidth: 100, + formatter: 'formatAmount2', + }, + { + field: 'createTime', + title: '助力时间', + width: 180, + formatter: 'formatDateTime', + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/bargain/record/index.vue b/apps/web-antd/src/views/mall/promotion/bargain/record/index.vue new file mode 100644 index 00000000..88075484 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/bargain/record/index.vue @@ -0,0 +1,83 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/bargain/record/modules/list.vue b/apps/web-antd/src/views/mall/promotion/bargain/record/modules/list.vue new file mode 100644 index 00000000..4d584bdc --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/bargain/record/modules/list.vue @@ -0,0 +1,67 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/combination/activity/data.ts b/apps/web-antd/src/views/mall/promotion/combination/activity/data.ts new file mode 100644 index 00000000..e08dfa66 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/combination/activity/data.ts @@ -0,0 +1,238 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { formatDate } from '@vben/utils'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 表单配置 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + rules: 'required', + }, + { + fieldName: 'startTime', + label: '开始时间', + component: 'DatePicker', + componentProps: { + placeholder: '请选择开始时间', + showTime: false, + valueFormat: 'x', + format: 'YYYY-MM-DD', + }, + rules: 'required', + }, + { + fieldName: 'endTime', + label: '结束时间', + component: 'DatePicker', + componentProps: { + placeholder: '请选择结束时间', + showTime: false, + valueFormat: 'x', + format: 'YYYY-MM-DD', + }, + rules: 'required', + }, + { + fieldName: 'userSize', + label: '用户数量', + component: 'InputNumber', + componentProps: { + placeholder: '请输入用户数量', + min: 2, + }, + rules: 'required', + }, + { + fieldName: 'limitDuration', + label: '限制时长', + component: 'InputNumber', + componentProps: { + placeholder: '请输入限制时长(小时)', + min: 0, + }, + rules: 'required', + }, + { + fieldName: 'totalLimitCount', + label: '总限购数量', + component: 'InputNumber', + componentProps: { + placeholder: '请输入总限购数量', + min: 0, + }, + }, + { + fieldName: 'singleLimitCount', + label: '单次限购数量', + component: 'InputNumber', + componentProps: { + placeholder: '请输入单次限购数量', + min: 0, + }, + }, + { + fieldName: 'virtualGroup', + label: '虚拟成团', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + }, + }, + { + // TODO + fieldName: 'spuId', + label: '拼团商品', + component: 'Input', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + clearable: true, + }, + }, + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '活动编号', + minWidth: 80, + }, + { + field: 'name', + title: '活动名称', + minWidth: 140, + }, + { + field: 'activityTime', + title: '活动时间', + minWidth: 210, + formatter: ({ row }) => { + if (!row.startTime || !row.endTime) return ''; + return `${formatDate(row.startTime, 'YYYY-MM-DD')} ~ ${formatDate(row.endTime, 'YYYY-MM-DD')}`; + }, + }, + { + field: 'picUrl', + title: '商品图片', + minWidth: 80, + cellRender: { + name: 'CellImage', + props: { + height: 40, + width: 40, + }, + }, + }, + { + field: 'spuName', + title: '商品标题', + minWidth: 300, + }, + { + field: 'marketPrice', + title: '原价', + minWidth: 100, + formatter: ({ cellValue }) => { + return `¥${(cellValue / 100).toFixed(2)}`; + }, + }, + { + field: 'combinationPrice', + title: '拼团价', + minWidth: 100, + formatter: ({ row }) => { + if (!row.products || row.products.length === 0) return ''; + const combinationPrice = Math.min( + ...row.products.map((item: any) => item.combinationPrice), + ); + return `¥${(combinationPrice / 100).toFixed(2)}`; + }, + }, + { + field: 'groupCount', + title: '开团组数', + minWidth: 100, + }, + { + field: 'groupSuccessCount', + title: '成团组数', + minWidth: 100, + }, + { + field: 'recordCount', + title: '购买次数', + minWidth: 100, + }, + { + field: 'status', + title: '活动状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/combination/activity/index.vue b/apps/web-antd/src/views/mall/promotion/combination/activity/index.vue new file mode 100644 index 00000000..287071e0 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/combination/activity/index.vue @@ -0,0 +1,182 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/combination/activity/modules/form.vue b/apps/web-antd/src/views/mall/promotion/combination/activity/modules/form.vue new file mode 100644 index 00000000..15115feb --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/combination/activity/modules/form.vue @@ -0,0 +1,93 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/combination/record/data.ts b/apps/web-antd/src/views/mall/promotion/combination/record/data.ts new file mode 100644 index 00000000..3a508217 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/combination/record/data.ts @@ -0,0 +1,177 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'status', + label: '拼团状态', + component: 'Select', + componentProps: { + placeholder: '请选择拼团状态', + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + clearable: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '拼团编号', + minWidth: 80, + }, + { + field: 'avatar', + title: '头像', + minWidth: 80, + cellRender: { + name: 'CellImage', + props: { + height: 40, + width: 40, + shape: 'circle', + }, + }, + }, + { + field: 'nickname', + title: '昵称', + minWidth: 100, + }, + { + field: 'headId', + title: '开团团长', + minWidth: 100, + }, + { + field: 'picUrl', + title: '拼团商品图', + minWidth: 80, + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'spuName', + title: '拼团商品', + minWidth: 120, + }, + { + field: 'activityName', + title: '拼团活动', + minWidth: 140, + }, + { + field: 'userSize', + title: '几人团', + minWidth: 80, + }, + { + field: 'userCount', + title: '参与人数', + minWidth: 80, + }, + { + field: 'createTime', + title: '参团时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'endTime', + title: '结束时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '拼团状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + title: '操作', + width: 100, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 用户列表表格列配置 */ +export function useUserGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 80, + }, + { + field: 'avatar', + title: '用户头像', + minWidth: 80, + cellRender: { + name: 'CellImage', + props: { + height: 40, + width: 40, + shape: 'circle', + }, + }, + }, + { + field: 'nickname', + title: '用户昵称', + minWidth: 100, + }, + { + field: 'headId', + title: '开团团长', + minWidth: 100, + formatter: ({ cellValue }) => { + return cellValue === 0 ? '团长' : '团员'; + }, + }, + { + field: 'createTime', + title: '参团时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'endTime', + title: '结束时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '拼团状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/combination/record/index.vue b/apps/web-antd/src/views/mall/promotion/combination/record/index.vue new file mode 100644 index 00000000..b10a156b --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/combination/record/index.vue @@ -0,0 +1,81 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/combination/record/modules/list.vue b/apps/web-antd/src/views/mall/promotion/combination/record/modules/list.vue new file mode 100644 index 00000000..459cd34d --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/combination/record/modules/list.vue @@ -0,0 +1,63 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/coupon/data.ts b/apps/web-antd/src/views/mall/promotion/coupon/data.ts new file mode 100644 index 00000000..36c9fe71 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/coupon/data.ts @@ -0,0 +1,129 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +import { discountFormat } from './formatter'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'nickname', + label: '会员昵称', + component: 'Input', + componentProps: { + placeholder: '请输入会员昵称', + clearable: true, + }, + }, + { + fieldName: 'createTime', + label: '领取时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'nickname', + title: '会员昵称', + minWidth: 100, + }, + { + field: 'name', + title: '优惠券名称', + minWidth: 140, + }, + { + field: 'productScope', + title: '类型', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_PRODUCT_SCOPE }, + }, + }, + { + field: 'discountType', + title: '优惠', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_DISCOUNT_TYPE }, + }, + }, + { + field: 'discountPrice', + title: '优惠力度', + minWidth: 110, + formatter: ({ row }) => { + return discountFormat(row); + }, + }, + { + field: 'takeType', + title: '领取方式', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE }, + }, + }, + { + field: 'status', + title: '状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_COUPON_STATUS }, + }, + }, + { + field: 'createTime', + title: '领取时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'useTime', + title: '使用时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 100, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 获取状态选项卡配置 */ +export function getStatusTabs() { + const tabs = [ + { + label: '全部', + value: 'all', + }, + ]; + + // 添加字典状态选项 + const statusOptions = getDictOptions(DICT_TYPE.PROMOTION_COUPON_STATUS); + for (const option of statusOptions) { + tabs.push({ + label: option.label, + value: String(option.value), + }); + } + + return tabs; +} diff --git a/apps/web-antd/src/views/mall/promotion/coupon/formatter.ts b/apps/web-antd/src/views/mall/promotion/coupon/formatter.ts new file mode 100644 index 00000000..41e6ec37 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/coupon/formatter.ts @@ -0,0 +1,65 @@ +import type { MallCouponTemplateApi } from '#/api/mall/promotion/coupon/couponTemplate'; + +import { floatToFixed2, formatDate } from '@vben/utils'; + +import { + CouponTemplateValidityTypeEnum, + PromotionDiscountTypeEnum, +} from '#/utils'; + +// 格式化【优惠金额/折扣】 +export function discountFormat(row: MallCouponTemplateApi.CouponTemplate) { + if (row.discountType === PromotionDiscountTypeEnum.PRICE.type) { + return `¥${floatToFixed2(row.discountPrice)}`; + } + if (row.discountType === PromotionDiscountTypeEnum.PERCENT.type) { + return `${row.discountPercent}%`; + } + return `未知【${row.discountType}】`; +} + +// 格式化【领取上限】 +export function takeLimitCountFormat( + row: MallCouponTemplateApi.CouponTemplate, +) { + if (row.takeLimitCount) { + if (row.takeLimitCount === -1) { + return '无领取限制'; + } + return `${row.takeLimitCount} 张/人`; + } else { + return ' '; + } +} + +// 格式化【有效期限】 +export function validityTypeFormat(row: MallCouponTemplateApi.CouponTemplate) { + if (row.validityType === CouponTemplateValidityTypeEnum.DATE.type) { + return `${formatDate(row.validStartTime)} 至 ${formatDate(row.validEndTime)}`; + } + if (row.validityType === CouponTemplateValidityTypeEnum.TERM.type) { + return `领取后第 ${row.fixedStartTerm} - ${row.fixedEndTerm} 天内可用`; + } + return `未知【${row.validityType}】`; +} + +// 格式化【totalCount】 +export function totalCountFormat(row: MallCouponTemplateApi.CouponTemplate) { + if (row.totalCount === -1) { + return '不限制'; + } + return row.totalCount; +} + +// 格式化【剩余数量】 +export function remainedCountFormat(row: MallCouponTemplateApi.CouponTemplate) { + if (row.totalCount === -1) { + return '不限制'; + } + return row.totalCount - row.takeCount; +} + +// 格式化【最低消费】 +export function usePriceFormat(row: MallCouponTemplateApi.CouponTemplate) { + return `¥${floatToFixed2(row.usePrice)}`; +} diff --git a/apps/web-antd/src/views/mall/promotion/coupon/index.vue b/apps/web-antd/src/views/mall/promotion/coupon/index.vue new file mode 100644 index 00000000..27fbb2e3 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/coupon/index.vue @@ -0,0 +1,132 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/coupon/template/data.ts b/apps/web-antd/src/views/mall/promotion/coupon/template/data.ts new file mode 100644 index 00000000..e2359f2d --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/coupon/template/data.ts @@ -0,0 +1,252 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +// 格式化函数移到组件内部实现 +import { z } from '#/adapter/form'; +import { + CommonStatusEnum, + DICT_TYPE, + getDictOptions, + getRangePickerDefaultProps, +} from '#/utils'; + +import { + discountFormat, + remainedCountFormat, + takeLimitCountFormat, + totalCountFormat, + validityTypeFormat, +} from '../formatter'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '优惠券名称', + component: 'Input', + componentProps: { + placeholder: '请输入优惠券名称', + }, + rules: 'required', + }, + { + fieldName: 'description', + label: '优惠券描述', + component: 'Textarea', + }, + // TODO + { + fieldName: 'productScope', + label: '优惠类型', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.PROMOTION_PRODUCT_SCOPE, 'number'), + }, + rules: 'required', + }, + { + fieldName: 'takeType', + label: '领取方式', + component: 'Select', + componentProps: { + placeholder: '请选择领取方式', + options: getDictOptions(DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE, 'number'), + }, + rules: 'required', + }, + { + fieldName: 'validityType', + label: '有效期类型', + component: 'Select', + componentProps: { + placeholder: '请选择有效期类型', + options: getDictOptions( + DICT_TYPE.PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE, + 'number', + ), + }, + rules: 'required', + }, + { + fieldName: 'totalCount', + label: '发放数量', + component: 'InputNumber', + componentProps: { + min: 0, + placeholder: '请输入发放数量', + }, + rules: 'required', + }, + { + fieldName: 'takeLimitCount', + label: '领取上限', + component: 'InputNumber', + componentProps: { + min: 0, + placeholder: '请输入领取上限', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '优惠券状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '优惠券名称', + component: 'Input', + componentProps: { + placeholder: '请输入优惠券名称', + clearable: true, + }, + }, + { + fieldName: 'discountType', + label: '优惠类型', + component: 'Select', + componentProps: { + placeholder: '请选择优惠类型', + clearable: true, + options: getDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE, 'number'), + }, + }, + { + fieldName: 'status', + label: '优惠券状态', + component: 'Select', + componentProps: { + placeholder: '请选择优惠券状态', + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { type: 'checkbox', width: 40 }, + { + field: 'name', + title: '优惠券名称', + minWidth: 140, + }, + { + field: 'productScope', + title: '类型', + minWidth: 130, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_PRODUCT_SCOPE }, + }, + }, + { + field: 'discountType', + title: '优惠', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_DISCOUNT_TYPE }, + }, + }, + { + field: 'discountPrice', + title: '优惠力度', + minWidth: 110, + formatter: ({ row }) => { + return discountFormat(row); + }, + }, + { + field: 'takeType', + title: '领取方式', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE }, + }, + }, + { + field: 'validityType', + title: '使用时间', + minWidth: 180, + formatter: ({ row }) => { + return validityTypeFormat(row); + }, + }, + { + field: 'totalCount', + title: '发放数量', + minWidth: 100, + formatter: ({ row }) => { + return totalCountFormat(row); + }, + }, + { + field: 'remainedCount', + title: '剩余数量', + minWidth: 100, + formatter: ({ row }) => { + return remainedCountFormat(row); + }, + }, + { + field: 'takeLimitCount', + title: '领取上限', + minWidth: 100, + formatter: ({ row }) => { + return takeLimitCountFormat(row); + }, + }, + { + field: 'status', + title: '状态', + minWidth: 100, + slots: { default: 'status' }, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 120, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/coupon/template/index.vue b/apps/web-antd/src/views/mall/promotion/coupon/template/index.vue new file mode 100644 index 00000000..98529564 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/coupon/template/index.vue @@ -0,0 +1,190 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/coupon/template/modules/form.vue b/apps/web-antd/src/views/mall/promotion/coupon/template/modules/form.vue new file mode 100644 index 00000000..f6436098 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/coupon/template/modules/form.vue @@ -0,0 +1,89 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/discountActivity/data.ts b/apps/web-antd/src/views/mall/promotion/discountActivity/data.ts new file mode 100644 index 00000000..dffafe32 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/discountActivity/data.ts @@ -0,0 +1,159 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { formatDate } from '@vben/utils'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 表单配置 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + rules: 'required', + }, + { + fieldName: 'startTime', + label: '开始时间', + component: 'DatePicker', + componentProps: { + placeholder: '请选择开始时间', + showTime: false, + valueFormat: 'x', + format: 'YYYY-MM-DD', + }, + rules: 'required', + }, + { + fieldName: 'endTime', + label: '结束时间', + component: 'DatePicker', + componentProps: { + placeholder: '请选择结束时间', + showTime: false, + valueFormat: 'x', + format: 'YYYY-MM-DD', + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + rows: 4, + }, + }, + // TODO + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + clearable: true, + }, + }, + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'activeTime', + label: '活动时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + clearable: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '活动编号', + minWidth: 80, + }, + { + field: 'name', + title: '活动名称', + minWidth: 140, + }, + { + field: 'activityTime', + title: '活动时间', + minWidth: 210, + formatter: ({ row }) => { + if (!row.startTime || !row.endTime) return ''; + return `${formatDate(row.startTime, 'YYYY-MM-DD')} ~ ${formatDate(row.endTime, 'YYYY-MM-DD')}`; + }, + }, + { + field: 'status', + title: '活动状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 150, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/discountActivity/index.vue b/apps/web-antd/src/views/mall/promotion/discountActivity/index.vue new file mode 100644 index 00000000..de252278 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/discountActivity/index.vue @@ -0,0 +1,178 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/discountActivity/modules/form.vue b/apps/web-antd/src/views/mall/promotion/discountActivity/modules/form.vue new file mode 100644 index 00000000..120a7a90 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/discountActivity/modules/form.vue @@ -0,0 +1,98 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/diy/page/data.ts b/apps/web-antd/src/views/mall/promotion/diy/page/data.ts new file mode 100644 index 00000000..554f6829 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/page/data.ts @@ -0,0 +1,109 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +/** 表单配置 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '页面名称', + component: 'Input', + componentProps: { + placeholder: '请输入页面名称', + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + rows: 4, + }, + }, + { + fieldName: 'previewPicUrls', + component: 'ImageUpload', + label: '预览图', + componentProps: { + maxNumber: 10, + multiple: true, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '页面名称', + component: 'Input', + componentProps: { + placeholder: '请输入页面名称', + clearable: true, + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + clearable: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 80, + }, + { + field: 'previewPicUrls', + title: '预览图', + minWidth: 120, + cellRender: { + name: 'CellImages', + }, + }, + { + field: 'name', + title: '页面名称', + minWidth: 150, + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/diy/page/index.vue b/apps/web-antd/src/views/mall/promotion/diy/page/index.vue new file mode 100644 index 00000000..e4c8c7a7 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/page/index.vue @@ -0,0 +1,141 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/diy/page/modules/form.vue b/apps/web-antd/src/views/mall/promotion/diy/page/modules/form.vue new file mode 100644 index 00000000..7d24c171 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/page/modules/form.vue @@ -0,0 +1,92 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/diy/template/data.ts b/apps/web-antd/src/views/mall/promotion/diy/template/data.ts new file mode 100644 index 00000000..0c46faf7 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/template/data.ts @@ -0,0 +1,120 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE } from '#/utils/dict'; + +/** 表单配置 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '模板名称', + component: 'Input', + componentProps: { + placeholder: '请输入模板名称', + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + rows: 4, + }, + }, + { + fieldName: 'previewPicUrls', + component: 'ImageUpload', + label: '预览图', + componentProps: { + maxNumber: 10, + multiple: true, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '模板名称', + component: 'Input', + componentProps: { + placeholder: '请输入模板名称', + clearable: true, + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + clearable: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 80, + }, + { + field: 'previewPicUrls', + title: '预览图', + minWidth: 120, + cellRender: { + name: 'CellImages', + }, + }, + { + field: 'name', + title: '模板名称', + minWidth: 150, + }, + { + field: 'used', + title: '是否使用', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 250, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/diy/template/index.vue b/apps/web-antd/src/views/mall/promotion/diy/template/index.vue new file mode 100644 index 00000000..74e47ed0 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/template/index.vue @@ -0,0 +1,167 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/diy/template/modules/form.vue b/apps/web-antd/src/views/mall/promotion/diy/template/modules/form.vue new file mode 100644 index 00000000..7370dce3 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/diy/template/modules/form.vue @@ -0,0 +1,99 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/kefu/index.vue b/apps/web-antd/src/views/mall/promotion/kefu/index.vue new file mode 100644 index 00000000..59a7d217 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/kefu/index.vue @@ -0,0 +1,28 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/point/activity/data.ts b/apps/web-antd/src/views/mall/promotion/point/activity/data.ts new file mode 100644 index 00000000..27625475 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/point/activity/data.ts @@ -0,0 +1,140 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE } from '#/utils/dict'; + +/** 表单配置 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'spuId', + label: '积分商城活动商品', + component: 'Input', + componentProps: { + placeholder: '请选择商品', + }, + rules: 'required', + }, + { + fieldName: 'sort', + label: '排序', + component: 'InputNumber', + componentProps: { + placeholder: '请输入排序', + min: 0, + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + rows: 4, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + clearable: true, + dictType: DICT_TYPE.COMMON_STATUS, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '活动编号', + minWidth: 80, + }, + { + field: 'picUrl', + title: '商品图片', + minWidth: 80, + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'spuName', + title: '商品标题', + minWidth: 300, + }, + { + field: 'marketPrice', + title: '原价', + minWidth: 100, + formatter: 'formatAmount2', + }, + { + field: 'point', + title: '兑换积分', + minWidth: 100, + }, + { + field: 'price', + title: '兑换金额', + minWidth: 100, + formatter: 'formatAmount2', + }, + { + field: 'status', + title: '活动状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'stock', + title: '库存', + minWidth: 80, + }, + { + field: 'totalStock', + title: '总库存', + minWidth: 80, + }, + { + field: 'redeemedQuantity', + title: '已兑换数量', + minWidth: 100, + slots: { default: 'redeemedQuantity' }, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 150, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/point/activity/index.vue b/apps/web-antd/src/views/mall/promotion/point/activity/index.vue new file mode 100644 index 00000000..7e6c5c4b --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/point/activity/index.vue @@ -0,0 +1,161 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/point/activity/modules/form.vue b/apps/web-antd/src/views/mall/promotion/point/activity/modules/form.vue new file mode 100644 index 00000000..a698f812 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/point/activity/modules/form.vue @@ -0,0 +1,107 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/rewardActivity/data.ts b/apps/web-antd/src/views/mall/promotion/rewardActivity/data.ts new file mode 100644 index 00000000..c145669b --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/rewardActivity/data.ts @@ -0,0 +1,166 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 表单配置 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + }, + rules: 'required', + }, + { + fieldName: 'startTime', + label: '开始时间', + component: 'DatePicker', + componentProps: { + placeholder: '请选择开始时间', + showTime: true, + valueFormat: 'x', + format: 'YYYY-MM-DD HH:mm:ss', + }, + rules: 'required', + }, + { + fieldName: 'endTime', + label: '结束时间', + component: 'DatePicker', + componentProps: { + placeholder: '请选择结束时间', + showTime: true, + valueFormat: 'x', + format: 'YYYY-MM-DD HH:mm:ss', + }, + rules: 'required', + }, + { + fieldName: 'conditionType', + label: '条件类型', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.PROMOTION_CONDITION_TYPE, 'number'), + }, + rules: 'required', + }, + { + fieldName: 'productScope', + label: '商品范围', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.PROMOTION_PRODUCT_SCOPE, 'number'), + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + placeholder: '请输入备注', + rows: 4, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + clearable: true, + }, + }, + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '活动时间', + component: 'RangePicker', + componentProps: { + placeholder: ['活动开始日期', '活动结束日期'], + clearable: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '活动名称', + minWidth: 140, + }, + { + field: 'productScope', + title: '活动范围', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PROMOTION_PRODUCT_SCOPE }, + }, + }, + { + field: 'startTime', + title: '活动开始时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'endTime', + title: '活动结束时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/rewardActivity/index.vue b/apps/web-antd/src/views/mall/promotion/rewardActivity/index.vue new file mode 100644 index 00000000..acc5112d --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/rewardActivity/index.vue @@ -0,0 +1,178 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/rewardActivity/modules/form.vue b/apps/web-antd/src/views/mall/promotion/rewardActivity/modules/form.vue new file mode 100644 index 00000000..7e209a90 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/rewardActivity/modules/form.vue @@ -0,0 +1,105 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/seckill/activity/data.ts b/apps/web-antd/src/views/mall/promotion/seckill/activity/data.ts new file mode 100644 index 00000000..2d294e8e --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/seckill/activity/data.ts @@ -0,0 +1,126 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '活动名称', + component: 'Input', + componentProps: { + placeholder: '请输入活动名称', + clearable: true, + }, + }, + { + fieldName: 'status', + label: '活动状态', + component: 'Select', + componentProps: { + placeholder: '请选择活动状态', + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '活动编号', + minWidth: 80, + }, + { + field: 'name', + title: '活动名称', + minWidth: 140, + }, + { + field: 'configIds', + title: '秒杀时段', + minWidth: 220, + slots: { default: 'configIds' }, + }, + { + field: 'startTime', + title: '活动时间', + minWidth: 210, + slots: { default: 'timeRange' }, + }, + { + field: 'picUrl', + title: '商品图片', + minWidth: 80, + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'spuName', + title: '商品标题', + minWidth: 300, + }, + { + field: 'marketPrice', + title: '原价', + minWidth: 100, + formatter: ({ row }) => `¥${(row.marketPrice / 100).toFixed(2)}`, + }, + { + field: 'seckillPrice', + title: '秒杀价', + minWidth: 100, + formatter: ({ row }) => { + if (!(row.products || row.products.length === 0)) { + return '¥0.00'; + } + const seckillPrice = Math.min( + ...row.products.map((item: any) => item.seckillPrice), + ); + return `¥${(seckillPrice / 100).toFixed(2)}`; + }, + }, + { + field: 'status', + title: '活动状态', + align: 'center', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'stock', + title: '库存', + align: 'center', + minWidth: 80, + }, + { + field: 'totalStock', + title: '总库存', + align: 'center', + minWidth: 80, + }, + { + field: 'createTime', + title: '创建时间', + align: 'center', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + align: 'center', + width: 150, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/seckill/activity/formatter.ts b/apps/web-antd/src/views/mall/promotion/seckill/activity/formatter.ts new file mode 100644 index 00000000..db1bce54 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/seckill/activity/formatter.ts @@ -0,0 +1,34 @@ +import { formatDate } from '@vben/utils'; + +// 全局变量,用于存储配置列表 +let configList: any[] = []; + +/** 设置配置列表 */ +export function setConfigList(list: any[]) { + configList = list; +} + +/** 格式化配置名称 */ +export function formatConfigNames(configId: number): string { + const config = configList.find((item) => item.id === configId); + return config === null || config === undefined + ? '' + : `${config.name}[${config.startTime} ~ ${config.endTime}]`; +} + +/** 格式化秒杀价格 */ +export function formatSeckillPrice(products: any[]): string { + if (!products || products.length === 0) { + return '¥0.00'; + } + const seckillPrice = Math.min(...products.map((item) => item.seckillPrice)); + return `¥${(seckillPrice / 100).toFixed(2)}`; +} + +/** 格式化活动时间范围 */ +export function formatTimeRange( + startTime: Date | string, + endTime: Date | string, +): string { + return `${formatDate(startTime, 'YYYY-MM-DD')} ~ ${formatDate(endTime, 'YYYY-MM-DD')}`; +} diff --git a/apps/web-antd/src/views/mall/promotion/seckill/activity/index.vue b/apps/web-antd/src/views/mall/promotion/seckill/activity/index.vue new file mode 100644 index 00000000..0d3a6cb0 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/seckill/activity/index.vue @@ -0,0 +1,198 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/seckill/activity/modules/form.vue b/apps/web-antd/src/views/mall/promotion/seckill/activity/modules/form.vue new file mode 100644 index 00000000..99c2767d --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/seckill/activity/modules/form.vue @@ -0,0 +1,121 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/seckill/config/data.ts b/apps/web-antd/src/views/mall/promotion/seckill/config/data.ts new file mode 100644 index 00000000..845169b6 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/seckill/config/data.ts @@ -0,0 +1,151 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MallSeckillConfigApi } from '#/api/mall/promotion/seckill/seckillConfig'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '秒杀时段名称', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'startTime', + label: '开始时间点', + component: 'TimePicker', + componentProps: { + format: 'HH:mm', + valueFormat: 'HH:mm', + placeholder: '请选择开始时间点', + }, + rules: 'required', + }, + { + fieldName: 'endTime', + label: '结束时间点', + component: 'TimePicker', + componentProps: { + format: 'HH:mm', + valueFormat: 'HH:mm', + placeholder: '请选择结束时间点', + }, + rules: 'required', + }, + { + fieldName: 'sliderPicUrls', + label: '秒杀轮播图', + component: 'ImageUpload', + componentProps: { + multiple: true, + maxNumber: 5, + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: 'required', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '秒杀时段名称', + component: 'Input', + componentProps: { + placeholder: '请输入秒杀时段名称', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns( + onStatusChange?: ( + newStatus: number, + row: T, + ) => PromiseLike, +): VxeTableGridOptions['columns'] { + return [ + { + title: '秒杀时段名称', + field: 'name', + minWidth: 200, + }, + { + title: '开始时间点', + field: 'startTime', + minWidth: 120, + }, + { + title: '结束时间点', + field: 'endTime', + minWidth: 120, + }, + { + title: '秒杀轮播图', + field: 'sliderPicUrls', + minWidth: 100, + cellRender: { + name: 'CellImages', + }, + }, + { + title: '活动状态', + field: 'status', + minWidth: 100, + cellRender: { + attrs: { beforeChange: onStatusChange }, + name: 'CellSwitch', + props: { + checkedValue: 1, + checkedChildren: '启用', + unCheckedValue: 0, + unCheckedChildren: '禁用', + }, + }, + }, + { + title: '创建时间', + field: 'createTime', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/promotion/seckill/config/index.vue b/apps/web-antd/src/views/mall/promotion/seckill/config/index.vue new file mode 100644 index 00000000..c6b7a45b --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/seckill/config/index.vue @@ -0,0 +1,159 @@ + + + diff --git a/apps/web-antd/src/views/mall/promotion/seckill/config/modules/form.vue b/apps/web-antd/src/views/mall/promotion/seckill/config/modules/form.vue new file mode 100644 index 00000000..028f48d1 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/seckill/config/modules/form.vue @@ -0,0 +1,90 @@ + + + diff --git a/apps/web-antd/src/views/mall/statistics/member/index.vue b/apps/web-antd/src/views/mall/statistics/member/index.vue new file mode 100644 index 00000000..3e6a57c0 --- /dev/null +++ b/apps/web-antd/src/views/mall/statistics/member/index.vue @@ -0,0 +1,32 @@ + + + diff --git a/apps/web-antd/src/views/mall/statistics/product/index.vue b/apps/web-antd/src/views/mall/statistics/product/index.vue new file mode 100644 index 00000000..df8469a9 --- /dev/null +++ b/apps/web-antd/src/views/mall/statistics/product/index.vue @@ -0,0 +1,32 @@ + + + diff --git a/apps/web-antd/src/views/mall/statistics/trade/index.vue b/apps/web-antd/src/views/mall/statistics/trade/index.vue new file mode 100644 index 00000000..46ceb7e6 --- /dev/null +++ b/apps/web-antd/src/views/mall/statistics/trade/index.vue @@ -0,0 +1,32 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/afterSale/data.ts b/apps/web-antd/src/views/mall/trade/afterSale/data.ts new file mode 100644 index 00000000..fbe685f1 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/afterSale/data.ts @@ -0,0 +1,140 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'spuName', + label: '商品名称', + component: 'Input', + }, + { + fieldName: 'no', + label: '退款编号', + component: 'Input', + }, + { + fieldName: 'orderNo', + label: '订单编号', + component: 'Input', + }, + { + fieldName: 'status', + label: '售后状态', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.TRADE_AFTER_SALE_STATUS, 'number'), + }, + }, + { + fieldName: 'status', + label: '售后方式', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.TRADE_AFTER_SALE_WAY, 'number'), + }, + }, + { + fieldName: 'type', + label: '售后类型', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.TRADE_AFTER_SALE_TYPE, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns(): VxeGridPropTypes.Columns { + return [ + { + field: 'no', + title: '退款编号', + fixed: 'left', + }, + { + field: 'orderNo', + title: '订单编号', + fixed: 'left', + slots: { default: 'orderNo' }, + }, + { + field: 'spuName', + title: '商品名称', + align: 'left', + minWidth: 200, + }, + { + field: 'picUrl', + title: '商品图片', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'properties', + title: '商品属性', + minWidth: 200, + formatter: ({ cellValue }) => { + return cellValue && cellValue.length > 0 + ? cellValue + .map((item: any) => `${item.propertyName} : ${item.valueName}`) + .join('\n') + : '-'; + }, + }, + { + field: 'refundPrice', + title: '订单金额', + formatter: 'formatAmount2', + }, + { + field: 'user.nickname', + title: '买家', + }, + { + field: 'createTime', + title: '申请时间', + formatter: 'formatDateTime', + }, + { + field: 'content', + title: '售后状态', + cellRender: { + name: 'CellDictTag', + props: { + dictType: DICT_TYPE.TRADE_AFTER_SALE_STATUS, + }, + }, + }, + { + field: 'way', + title: '售后方式', + cellRender: { + name: 'CellDictTag', + props: { + dictType: DICT_TYPE.TRADE_AFTER_SALE_WAY, + }, + }, + }, + { + title: '操作', + width: 80, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/afterSale/index.vue b/apps/web-antd/src/views/mall/trade/afterSale/index.vue new file mode 100644 index 00000000..c9e05584 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/afterSale/index.vue @@ -0,0 +1,119 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/brokerage/record/data.ts b/apps/web-antd/src/views/mall/trade/brokerage/record/data.ts new file mode 100644 index 00000000..c5e6ae68 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/record/data.ts @@ -0,0 +1,135 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { fenToYuan } from '@vben/utils'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'userId', + label: '用户编号', + component: 'Input', + componentProps: { + placeholder: '请输入用户编号', + clearable: true, + }, + }, + { + fieldName: 'bizType', + label: '业务类型', + component: 'Select', + componentProps: { + placeholder: '请选择业务类型', + clearable: true, + options: getDictOptions(DICT_TYPE.BROKERAGE_RECORD_BIZ_TYPE, 'number'), + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + clearable: true, + options: getDictOptions(DICT_TYPE.BROKERAGE_RECORD_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 60, + }, + { + field: 'userId', + title: '用户编号', + minWidth: 80, + }, + { + field: 'userAvatar', + title: '头像', + minWidth: 70, + cellRender: { + name: 'CellImage', + props: { + height: 40, + width: 40, + shape: 'circle', + }, + }, + }, + { + field: 'userNickname', + title: '昵称', + minWidth: 80, + }, + { + field: 'bizType', + title: '业务类型', + minWidth: 85, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.BROKERAGE_RECORD_BIZ_TYPE }, + }, + }, + { + field: 'bizId', + title: '业务编号', + minWidth: 80, + }, + { + field: 'title', + title: '标题', + minWidth: 110, + }, + { + field: 'price', + title: '金额', + minWidth: 60, + formatter: ({ row }) => `¥${fenToYuan(row.price)}`, + }, + { + field: 'description', + title: '说明', + minWidth: 120, + }, + { + field: 'status', + title: '状态', + minWidth: 85, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.BROKERAGE_RECORD_STATUS }, + }, + }, + { + field: 'unfreezeTime', + title: '解冻时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/brokerage/record/index.vue b/apps/web-antd/src/views/mall/trade/brokerage/record/index.vue new file mode 100644 index 00000000..619cef76 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/record/index.vue @@ -0,0 +1,57 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/brokerage/user/data.ts b/apps/web-antd/src/views/mall/trade/brokerage/user/data.ts new file mode 100644 index 00000000..8de25b5b --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/user/data.ts @@ -0,0 +1,140 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { fenToYuan } from '@vben/utils'; + +import { getRangePickerDefaultProps } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'bindUserId', + label: '推广员编号', + component: 'Input', + componentProps: { + placeholder: '请输入推广员编号', + clearable: true, + }, + }, + { + fieldName: 'brokerageEnabled', + label: '推广资格', + component: 'Select', + componentProps: { + placeholder: '请选择推广资格', + clearable: true, + options: [ + { label: '有', value: true }, + { label: '无', value: false }, + ], + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '用户编号', + minWidth: 80, + }, + { + field: 'avatar', + title: '头像', + minWidth: 70, + cellRender: { + name: 'CellImage', + props: { + width: 24, + height: 24, + shape: 'circle', + }, + }, + }, + { + field: 'nickname', + title: '昵称', + minWidth: 80, + }, + { + field: 'brokerageUserCount', + title: '推广人数', + minWidth: 80, + }, + { + field: 'brokerageOrderCount', + title: '推广订单数量', + minWidth: 110, + }, + { + field: 'brokerageOrderPrice', + title: '推广订单金额', + minWidth: 110, + formatter: ({ row }) => `¥${fenToYuan(row.brokerageOrderPrice)}`, + }, + { + field: 'withdrawPrice', + title: '已提现金额', + minWidth: 100, + formatter: ({ row }) => `¥${fenToYuan(row.withdrawPrice)}`, + }, + { + field: 'withdrawCount', + title: '已提现次数', + minWidth: 100, + }, + { + field: 'price', + title: '未提现金额', + minWidth: 100, + formatter: ({ row }) => `¥${fenToYuan(row.price)}`, + }, + { + field: 'frozenPrice', + title: '冻结中佣金', + minWidth: 100, + formatter: ({ row }) => `¥${fenToYuan(row.frozenPrice)}`, + }, + { + field: 'brokerageEnabled', + title: '推广资格', + minWidth: 80, + slots: { default: 'brokerageEnabled' }, + }, + { + field: 'brokerageTime', + title: '成为推广员时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'bindUserId', + title: '上级推广员编号', + minWidth: 150, + }, + { + field: 'bindUserTime', + title: '推广员绑定时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 150, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/brokerage/user/index.vue b/apps/web-antd/src/views/mall/trade/brokerage/user/index.vue new file mode 100644 index 00000000..1839c52d --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/user/index.vue @@ -0,0 +1,223 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/brokerage/user/modules/order-list-modal.vue b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/order-list-modal.vue new file mode 100644 index 00000000..8706aa32 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/order-list-modal.vue @@ -0,0 +1,185 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-create-form.vue b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-create-form.vue new file mode 100644 index 00000000..4d49231c --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-create-form.vue @@ -0,0 +1,166 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-list-modal.vue b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-list-modal.vue new file mode 100644 index 00000000..d69d6b35 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-list-modal.vue @@ -0,0 +1,160 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-update-form.vue b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-update-form.vue new file mode 100644 index 00000000..4f2fe59e --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/user/modules/user-update-form.vue @@ -0,0 +1,131 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/brokerage/withdraw/data.ts b/apps/web-antd/src/views/mall/trade/brokerage/withdraw/data.ts new file mode 100644 index 00000000..f72e5281 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/withdraw/data.ts @@ -0,0 +1,145 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'userId', + label: '用户编号', + component: 'Input', + componentProps: { + placeholder: '请输入用户编号', + clearable: true, + }, + }, + { + fieldName: 'type', + label: '提现类型', + component: 'Select', + componentProps: { + placeholder: '请选择提现类型', + clearable: true, + options: getDictOptions(DICT_TYPE.BROKERAGE_WITHDRAW_TYPE, 'number'), + }, + }, + { + fieldName: 'userAccount', + label: '账号', + component: 'Input', + componentProps: { + placeholder: '请输入账号', + clearable: true, + }, + }, + { + fieldName: 'userName', + label: '真实名字', + component: 'Input', + componentProps: { + placeholder: '请输入真实名字', + clearable: true, + }, + }, + { + fieldName: 'bankName', + label: '提现银行', + component: 'Select', + componentProps: { + placeholder: '请选择提现银行', + clearable: true, + options: getDictOptions(DICT_TYPE.BROKERAGE_BANK_NAME, 'string'), + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + clearable: true, + options: getDictOptions(DICT_TYPE.BROKERAGE_WITHDRAW_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '申请时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 80, + }, + { + field: 'userId', + title: '用户编号:', + minWidth: 80, + }, + { + field: 'userNickname', + title: '用户昵称:', + minWidth: 80, + }, + { + field: 'price', + title: '提现金额', + minWidth: 80, + formatter: 'formatAmount2', + }, + { + field: 'feePrice', + title: '提现手续费', + minWidth: 80, + formatter: 'formatAmount2', + }, + { + field: 'type', + title: '提现方式', + minWidth: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.BROKERAGE_WITHDRAW_TYPE }, + }, + }, + { + title: '提现信息', + minWidth: 200, + slots: { default: 'withdraw-info' }, + }, + { + field: 'createTime', + title: '申请时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'remark', + title: '备注', + minWidth: 120, + }, + { + title: '状态', + minWidth: 200, + slots: { default: 'status-info' }, + }, + { + title: '操作', + width: 150, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/brokerage/withdraw/index.vue b/apps/web-antd/src/views/mall/trade/brokerage/withdraw/index.vue new file mode 100644 index 00000000..9d945e75 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/brokerage/withdraw/index.vue @@ -0,0 +1,195 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/config/data.ts b/apps/web-antd/src/views/mall/trade/config/data.ts new file mode 100644 index 00000000..9c35219f --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/config/data.ts @@ -0,0 +1,243 @@ +import type { VbenFormSchema } from '#/adapter/form'; + +import { DICT_TYPE, getDictOptions } from '#/utils'; + +/** 售后表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'type', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'afterSaleRefundReasons', + label: '退款理由', + component: 'Select', + componentProps: { + mode: 'tags', + placeholder: '请直接输入退款理由', + class: 'w-full', + }, + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'afterSale', + }, + }, + { + fieldName: 'afterSaleReturnReasons', + label: '退货理由', + component: 'Select', + componentProps: { + mode: 'tags', + placeholder: '请直接输入退货理由', + class: 'w-full', + }, + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'afterSale', + }, + }, + { + fieldName: 'deliveryExpressFreeEnabled', + label: '启用包邮', + component: 'Switch', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'delivery', + }, + description: '商城是否启用全场包邮', + }, + { + fieldName: 'deliveryExpressFreePrice', + label: '满额包邮', + component: 'InputNumber', + componentProps: { + min: 0, + precision: 2, + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'delivery', + }, + description: '商城商品满多少金额即可包邮,单位:元', + }, + { + fieldName: 'deliveryPickUpEnabled', + label: '启用门店自提', + component: 'Switch', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'delivery', + }, + }, + { + fieldName: 'brokerageEnabled', + label: '启用分佣', + component: 'Switch', + description: '商城是否开启分销模式', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + }, + { + fieldName: 'brokerageEnabledCondition', + label: '分佣模式', + component: 'RadioGroup', + componentProps: { + options: getDictOptions( + DICT_TYPE.BROKERAGE_ENABLED_CONDITION, + 'number', + ), + buttonStyle: 'solid', + optionType: 'button', + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: + '人人分销:每个用户都可以成为推广员 \n 单级分销:每个用户只能有一个上级推广员', + }, + { + fieldName: 'brokerageBindMode', + label: '分销关系绑定', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.BROKERAGE_BIND_MODE, 'number'), + buttonStyle: 'solid', + optionType: 'button', + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: + '首次绑定:只要用户没有推广人,随时都可以绑定推广关系 \n 注册绑定:只有新用户注册时或首次进入系统时才可以绑定推广关系', + }, + { + fieldName: 'brokeragePosterUrls', + label: '分销海报图', + component: 'ImageUpload', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: '个人中心分销海报图片,建议尺寸 600x1000', + }, + { + fieldName: 'brokerageFirstPercent', + label: '一级返佣比例', + component: 'InputNumber', + componentProps: { + min: 0, + max: 100, + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: '订单交易成功后给推广人返佣的百分比', + }, + { + fieldName: 'brokerageSecondPercent', + label: '二级返佣比例', + component: 'InputNumber', + componentProps: { + min: 0, + max: 100, + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: '订单交易成功后给推广人的推荐人返佣的百分比', + }, + { + fieldName: 'brokerageFrozenDays', + label: '佣金冻结天数', + component: 'InputNumber', + componentProps: { + min: 0, + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: + '防止用户退款,佣金被提现了,所以需要设置佣金冻结时间,单位:天', + }, + { + fieldName: 'brokerageWithdrawMinPrice', + label: '提现最低金额', + component: 'InputNumber', + componentProps: { + min: 0, + precision: 2, + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: '用户提现最低金额限制,单位:元', + }, + { + fieldName: 'brokerageWithdrawFeePercent', + label: '提现手续费', + component: 'InputNumber', + componentProps: { + min: 0, + max: 100, + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: + '提现手续费百分比,范围 0-100,0 为无提现手续费。例:设置 10,即收取 10% 手续费,提现10 元,到账 9 元,1 元手续费', + }, + { + fieldName: 'brokerageWithdrawTypes', + label: '提现方式', + component: 'CheckboxGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.BROKERAGE_WITHDRAW_TYPE, 'number'), + class: 'w-full', + }, + rules: 'required', + dependencies: { + triggerFields: ['type'], + show: (values) => values.type === 'brokerage', + }, + description: '商城开通提现的付款方式', + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/config/index.vue b/apps/web-antd/src/views/mall/trade/config/index.vue new file mode 100644 index 00000000..695b81a7 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/config/index.vue @@ -0,0 +1,98 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/express/data.ts b/apps/web-antd/src/views/mall/trade/delivery/express/data.ts new file mode 100644 index 00000000..793d86d6 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/express/data.ts @@ -0,0 +1,130 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +// import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'code', + label: '公司编码', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'name', + label: '公司名称', + rules: 'required', + }, + { + component: 'ImageUpload', + fieldName: 'logo', + label: '公司 logo', + rules: 'required', + }, + { + fieldName: 'sort', + label: '显示顺序', + component: 'InputNumber', + componentProps: { + min: 0, + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '开启状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '快递公司名称', + component: 'Input', + }, + { + fieldName: 'code', + label: '快递公司编号', + component: 'Input', + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + }, + { + field: 'code', + title: '公司编码', + }, + { + field: 'name', + title: '公司名称', + }, + { + field: 'logo', + title: '公司 logo', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'sort', + title: '显示顺序', + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/delivery/express/index.vue b/apps/web-antd/src/views/mall/trade/delivery/express/index.vue new file mode 100644 index 00000000..5a52b282 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/express/index.vue @@ -0,0 +1,145 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/express/modules/form.vue b/apps/web-antd/src/views/mall/trade/delivery/express/modules/form.vue new file mode 100644 index 00000000..85858419 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/express/modules/form.vue @@ -0,0 +1,89 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/data.ts b/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/data.ts new file mode 100644 index 00000000..b243fd88 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/data.ts @@ -0,0 +1,102 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'name', + label: '模板名称', + rules: 'required', + }, + { + fieldName: 'chargeMode', + label: '计费方式', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.EXPRESS_CHARGE_MODE, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'sort', + label: '显示顺序', + component: 'InputNumber', + componentProps: { + min: 0, + }, + rules: 'required', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '模板名称', + component: 'Input', + }, + { + fieldName: 'chargeMode', + label: '计费方式', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.EXPRESS_CHARGE_MODE, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + }, + { + field: 'name', + title: '模板名称', + }, + { + field: 'chargeMode', + title: '计费方式', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.EXPRESS_CHARGE_MODE }, + }, + }, + { + field: 'sort', + title: '显示顺序', + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/index.vue b/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/index.vue new file mode 100644 index 00000000..5235097c --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/index.vue @@ -0,0 +1,132 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/modules/form.vue b/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/modules/form.vue new file mode 100644 index 00000000..cf00e715 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/expressTemplate/modules/form.vue @@ -0,0 +1,91 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/pickUpOrder/data.ts b/apps/web-antd/src/views/mall/trade/delivery/pickUpOrder/data.ts new file mode 100644 index 00000000..f68f275f --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/pickUpOrder/data.ts @@ -0,0 +1,127 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; +import type { MallDeliveryPickUpStoreApi } from '#/api/mall/trade/delivery/pickUpStore'; + +import { ref } from 'vue'; + +import { getSimpleDeliveryPickUpStoreList } from '#/api/mall/trade/delivery/pickUpStore'; +import { + DeliveryTypeEnum, + DICT_TYPE, + getRangePickerDefaultProps, +} from '#/utils'; + +const pickUpStoreList = ref([]); + +getSimpleDeliveryPickUpStoreList().then((res) => { + pickUpStoreList.value = res; +}); + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + { + fieldName: 'pickUpStoreId', + label: '自提门店', + component: 'ApiSelect', + componentProps: { + api: getSimpleDeliveryPickUpStoreList, + fieldNames: { + label: 'name', + value: 'id', + }, + }, + dependencies: { + triggerFields: ['deliveryType'], + trigger: (values) => + values.deliveryType === DeliveryTypeEnum.PICK_UP.type, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns(): VxeGridPropTypes.Columns { + return [ + { + field: 'no', + title: '订单号', + fixed: 'left', + minWidth: 180, + }, + { + field: 'user.nickname', + title: '用户信息', + minWidth: 100, + }, + { + field: 'brokerageUser.nickname', + title: '推荐人信息', + minWidth: 100, + }, + { + field: 'spuName', + title: '商品信息', + minWidth: 100, + formatter: ({ row }) => { + if (row.items.length > 1) { + return row.items.map((item: any) => item.spuName).join(','); + } + }, + }, + { + field: 'payPrice', + title: '实付金额(元)', + formatter: 'formatAmount2', + minWidth: 180, + }, + { + field: 'storeStaffName', + title: '核销员', + minWidth: 160, + }, + { + field: 'pickUpStoreId', + title: '核销门店', + minWidth: 160, + formatter: ({ row }) => { + return pickUpStoreList.value.find( + (item) => item.id === row.pickUpStoreId, + )?.name; + }, + }, + { + field: 'payStatus', + title: '支付状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + minWidth: 80, + }, + { + field: 'status', + title: '订单状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.TRADE_ORDER_STATUS }, + }, + minWidth: 80, + }, + { + field: 'createTime', + title: '下单时间', + formatter: 'formatDateTime', + minWidth: 160, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/delivery/pickUpOrder/index.vue b/apps/web-antd/src/views/mall/trade/delivery/pickUpOrder/index.vue new file mode 100644 index 00000000..8a32abf0 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/pickUpOrder/index.vue @@ -0,0 +1,241 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/data.ts b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/data.ts new file mode 100644 index 00000000..ac3e0828 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/data.ts @@ -0,0 +1,245 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { z } from '#/adapter/form'; +import { getAreaTree } from '#/api/system/area'; +import { getSimpleUserList } from '#/api/system/user'; +import { + CommonStatusEnum, + DICT_TYPE, + getDictOptions, + getRangePickerDefaultProps, +} from '#/utils'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'ImageUpload', + fieldName: 'logo', + label: '门店logo', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'name', + label: '门店名称', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'phone', + label: '门店手机', + rules: 'mobileRequired', + }, + { + component: 'Textarea', + fieldName: 'introduction', + label: '门店简介', + }, + { + fieldName: 'areaId', + label: '地址', + component: 'ApiTreeSelect', + componentProps: { + api: () => getAreaTree(), + fieldNames: { label: 'name', value: 'id', children: 'children' }, + }, + }, + { + component: 'Input', + fieldName: 'detailAddress', + label: '详细地址', + rules: 'required', + }, + { + component: 'TimePicker', + fieldName: 'openingTime', + label: '营业开始时间', + rules: 'required', + }, + { + component: 'TimePicker', + fieldName: 'closingTime', + label: '营业结束时间', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'longitude', + label: '经度', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'latitude', + label: '纬度', + rules: 'required', + }, + { + component: 'Input', + fieldName: 'getGeo', + label: '获取经纬度', + }, + { + fieldName: 'status', + label: '门店状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 绑定店员的表单 */ +export function useBindFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'name', + label: '门店名称', + dependencies: { + triggerFields: ['id'], + disabled: true, + }, + }, + { + component: 'ApiSelect', + fieldName: 'verifyUserIds', + label: '门店店员', + rules: 'required', + componentProps: { + api: () => getSimpleUserList(), + fieldNames: { label: 'nickname', value: 'id' }, + mode: 'tags', + allowClear: true, + }, + }, + { + component: 'Select', + fieldName: 'verifyUsers', + label: '店员列表', + rules: 'required', + componentProps: { + options: [], + mode: 'tags', + }, + dependencies: { + triggerFields: ['verifyUserIds'], + trigger(values, form) { + form.setFieldValue('verifyUsers', values.verifyUserIds); + }, + disabled: true, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'phone', + label: '门店手机', + component: 'Input', + }, + { + fieldName: 'name', + label: '门店名称', + component: 'Input', + }, + { + fieldName: 'status', + label: '门店状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + }, + { + field: 'logo', + title: '门店logo', + cellRender: { + name: 'CellImage', + }, + }, + { + field: 'name', + title: '门店名称', + }, + { + field: 'phone', + title: '门店手机', + }, + { + field: 'detailAddress', + title: '地址', + }, + { + field: 'openingTime', + title: '营业时间', + formatter: ({ row }) => { + return `${row.openingTime} ~ ${row.closingTime}`; + }, + }, + { + field: 'status', + title: '开启状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'createTime', + title: '创建时间', + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/index.vue b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/index.vue new file mode 100644 index 00000000..0fec6490 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/index.vue @@ -0,0 +1,149 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/modules/bind-form.vue b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/modules/bind-form.vue new file mode 100644 index 00000000..542c68c3 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/modules/bind-form.vue @@ -0,0 +1,87 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/modules/form.vue b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/modules/form.vue new file mode 100644 index 00000000..44623e1c --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/delivery/pickUpStore/modules/form.vue @@ -0,0 +1,89 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/order/data.ts b/apps/web-antd/src/views/mall/trade/order/data.ts new file mode 100644 index 00000000..3e026532 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/order/data.ts @@ -0,0 +1,218 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeGridPropTypes } from '#/adapter/vxe-table'; +import type { MallDeliveryPickUpStoreApi } from '#/api/mall/trade/delivery/pickUpStore'; + +import { ref } from 'vue'; + +import { getSimpleDeliveryExpressList } from '#/api/mall/trade/delivery/express'; +import { getSimpleDeliveryPickUpStoreList } from '#/api/mall/trade/delivery/pickUpStore'; +import { + DeliveryTypeEnum, + DICT_TYPE, + getDictOptions, + getRangePickerDefaultProps, +} from '#/utils'; + +const pickUpStoreList = ref([]); + +getSimpleDeliveryPickUpStoreList().then((res) => { + pickUpStoreList.value = res; +}); + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'status', + label: '订单状态', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.TRADE_ORDER_STATUS, 'number'), + }, + }, + { + fieldName: 'payChannelCode', + label: '支付方式', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.PAY_CHANNEL_CODE, 'number'), + }, + }, + { + fieldName: 'name', + label: '品牌名称', + component: 'Input', + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + { + fieldName: 'terminal', + label: '订单来源', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.TERMINAL, 'number'), + }, + }, + { + fieldName: 'deliveryType', + label: '配送方式', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE, 'number'), + }, + }, + { + fieldName: 'logisticsId', + label: '快递公司', + component: 'ApiSelect', + componentProps: { + api: getSimpleDeliveryExpressList, + fieldNames: { + label: 'name', + value: 'id', + }, + }, + dependencies: { + triggerFields: ['deliveryType'], + show: (values) => values.deliveryType === DeliveryTypeEnum.EXPRESS.type, + }, + }, + { + fieldName: 'pickUpStoreId', + label: '自提门店', + component: 'ApiSelect', + componentProps: { + api: getSimpleDeliveryPickUpStoreList, + fieldNames: { + label: 'name', + value: 'id', + }, + }, + dependencies: { + triggerFields: ['deliveryType'], + show: (values) => values.deliveryType === DeliveryTypeEnum.PICK_UP.type, + }, + }, + { + fieldName: 'deliveryType', + label: '核销码', + component: 'Input', + dependencies: { + triggerFields: ['deliveryType'], + show: (values) => values.deliveryType === DeliveryTypeEnum.PICK_UP.type, + }, + }, + ]; +} + +/** 表格列配置 */ +export function useGridColumns(): VxeGridPropTypes.Columns { + return [ + { + type: 'expand', + width: 80, + slots: { content: 'expand_content' }, + fixed: 'left', + }, + { + field: 'no', + title: '订单号', + fixed: 'left', + minWidth: 180, + }, + { + field: 'createTime', + title: '下单时间', + formatter: 'formatDateTime', + minWidth: 160, + }, + { + field: 'terminal', + title: '订单来源', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.TERMINAL }, + }, + minWidth: 120, + }, + { + field: 'payChannelCode', + title: '支付方式', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.PAY_CHANNEL_CODE }, + }, + minWidth: 120, + }, + { + field: 'payTime', + title: '支付时间', + formatter: 'formatDateTime', + minWidth: 160, + }, + { + field: 'type', + title: '订单类型', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.TRADE_ORDER_TYPE }, + }, + minWidth: 80, + }, + + { + field: 'payPrice', + title: '实际支付', + formatter: 'formatAmount2', + minWidth: 180, + }, + { + field: 'user', + title: '买家/收货人', + formatter: ({ row }) => { + if (row.deliveryType === DeliveryTypeEnum.EXPRESS.type) { + return `买家:${row.user?.nickname} / 收货人: ${row.receiverName} ${row.receiverMobile}${row.receiverAreaName}${row.receiverDetailAddress}`; + } + if (row.deliveryType === DeliveryTypeEnum.PICK_UP.type) { + return `门店名称:${pickUpStoreList.value.find((item) => item.id === row.pickUpStoreId)?.name} / + 门店手机:${pickUpStoreList.value.find((item) => item.id === row.pickUpStoreId)?.phone} / + 自提门店:${pickUpStoreList.value.find((item) => item.id === row.pickUpStoreId)?.detailAddress} + `; + } + return ''; + }, + minWidth: 180, + }, + { + field: 'deliveryType', + title: '配送方式', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.TRADE_DELIVERY_TYPE }, + }, + minWidth: 80, + }, + { + field: 'status', + title: '订单状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.TRADE_ORDER_STATUS }, + }, + minWidth: 80, + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mall/trade/order/index.vue b/apps/web-antd/src/views/mall/trade/order/index.vue new file mode 100644 index 00000000..1e6a4302 --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/order/index.vue @@ -0,0 +1,178 @@ + + + diff --git a/apps/web-antd/src/views/mall/trade/order/modules/delevery-form.vue b/apps/web-antd/src/views/mall/trade/order/modules/delevery-form.vue new file mode 100644 index 00000000..5bf26abc --- /dev/null +++ b/apps/web-antd/src/views/mall/trade/order/modules/delevery-form.vue @@ -0,0 +1,131 @@ + + + diff --git a/apps/web-antd/vite.config.mts b/apps/web-antd/vite.config.mts index 6a6a60b6..27bdfd9e 100644 --- a/apps/web-antd/vite.config.mts +++ b/apps/web-antd/vite.config.mts @@ -28,7 +28,7 @@ export default defineConfig(async () => { rewrite: (path) => path.replace(/^\/api/, ''), // mock代理目标地址 // target: 'http://192.168.43.169:8080', - target: 'http://127.0.0.1:8080', + target: 'https://by.missmoc.top/api/', // target: 'http://192.168.0.108:8080', // target: 'http://192.168.0.106:8080', // target: 'http://47.109.37.87:3010',